برمجة JavaScript

يدعم Chute برمجة JavaScript لتعديل الطلبات/الاستجابات المتقدم، مطابقة القواعد المخصصة، تحليل DNS، والمهام المجدولة. تستخدم السكريبتات محرك Apple JavaScriptCore وتتبع واجهة برمجة السكريبتات المتوافقة مع Surge.

تعرف السكريبتات في القسم [Script] من ملف الإعدادات.

الإعدادات

[Script]
MyScript = type=http-request, script-path=/path/to/script.js, pattern=^https?://example\.com, requires-body=true, max-size=262144, timeout=10, argument=myArg
CronJob = type=cron, script-path=/path/to/cron.js, cron-expression=*/30 * * * *

معاملات السكريبت

المعامل مطلوب الافتراضي الوصف
type نعم http-request نوع تشغيل السكريبت (انظر أدناه)
script-path نعم مسار ملف محلي أو رابط HTTP(S) لسكريبت JS
pattern لا (مطابقة الكل) نمط رابط بتعبير نمطي لتصفية وقت تشغيل السكريبت
requires-body لا اكتشاف تلقائي فرض استلام السكريبت لمحتوى الطلب/الاستجابة الكامل
max-size لا 131072 (128KB) الحد الأقصى لحجم المحتوى بالبايت للسكريبتات التي تصل للمحتوى. إذا تجاوز المحتوى المجمّع هذا الحجم، يُتخطى السكريبت لذلك الطلب (لا يتم اقتطاع المحتوى)
timeout لا 5.0 ثانية مهلة تنفيذ لكل سكريبت. القيم فوق 30 ثانية تُخفض إلى 30
argument لا نص وسيط مخصص متاح كـ $argument في JS
debug لا false محجوز؛ لا تأثير له حالياً
cron-expression لا تعبير جدولة cron (لنوع cron فقط)
wake-system لا false محجوز؛ يُحلَّل لكن لا تأثير له حالياً
enable لا true تفعيل أو تعطيل هذا السكريبت
script-update-interval لا 0 استطلاع تحديث السكريبتات البعيدة (انظر نموذج التنفيذ)

أنواع السكريبتات

النص النوعي التعداد الوصف
http-request HTTP Request اعتراض وتعديل طلبات HTTP قبل التوجيه
http-response HTTP Response اعتراض وتعديل استجابات HTTP قبل العميل
http-request-before-send HTTP Request Before Send تعديل الطلب بعد جمع المحتوى الكامل، قبل الإرسال
rule Rule منطق مطابقة قواعد مخصص
dns DNS تحليل DNS مخصص
cron Cron سكريبتات مجدولة/موقوتة
event Event معالجات أحداث النظام (مثال: network-changed)

اكتشاف المحتوى التلقائي: إذا كان مصدر السكريبت يحتوي على $request.body أو $response.body، سيتم توفير المحتوى تلقائياً حتى max-size. استخدم requires-body=true لفرض هذا السلوك.


مرجع JavaScript API

تعمل السكريبتات في بيئة JavaScriptCore معزولة مع توفر الكائنات العامة التالية.

$request (للقراءة فقط)

متوفر في: http-request, http-response, http-request-before-send, rule

الخاصية النوع الوصف
.url String رابط الطلب الكامل
.method String طريقة HTTP (GET, POST, إلخ) أو QUERY لـ DNS
.headers Object ترويسات الطلب كأزواج key-value
.body String or null محتوى الطلب (مفكوك UTF-8)
.bodyBytes Uint8Array or null بايتات محتوى الطلب الخام
.hostname String اسم المضيف الهدف
.destPort Number منفذ الوجهة
.processPath String مسار العملية الطالبة (macOS فقط)
.userAgent String قيمة ترويسة User-Agent
.sourceIP String عنوان IP المصدر
.listenPort Number منفذ استماع البروكسي
.requestId String معرف طلب فريد
.dnsResult String عنوان IP المحلل
.srcPort Number منفذ المصدر
.protocol String البروتوكول المكتشف: http, https, tcp, dns

$response (للقراءة فقط)

متوفر في: http-response

الخاصية النوع الوصف
.status Number رمز حالة HTTP
.headers Object ترويسات الاستجابة كأزواج key-value
.body String or null محتوى الاستجابة (مفكوك UTF-8)
.bodyBytes Uint8Array or null بايتات محتوى الاستجابة الخام
.rawBody Uint8Array or null اسم بديل لـ .bodyBytes

$done(value) — معالج الإكمال

يجب استدعاؤه مرة واحدة بالضبط في نهاية السكريبت للإشارة إلى الاكتمال. يتوقف تنفيذ السكريبت حتى يتم استدعاء $done() أو انتهاء المهلة.

$done({})                        // تمرير — لا تعديلات
$done()                          // إجهاض الاتصال
$done({matched: true})           // نتيجة مطابقة القاعدة (لسكريبتات القواعد فقط)
$done({address: "1.2.3.4"})      // نتيجة DNS (لسكريبتات DNS فقط)

قيم إرجاع سكريبت طلب HTTP:

$done({
    url: "https://new.example.com/path",     // إعادة كتابة الرابط
    headers: {"X-Custom": "value"},           // تعديل الترويسات
    body: "new request body",                 // تعديل المحتوى
    response: {                               // إرجاع استجابة اصطناعية (تخطي الخادم العلوي)
        status: 200,
        headers: {"Content-Type": "text/html"},
        body: "<html>Blocked</html>"
    }
})

عند توفير response، يتم اختصار الطلب: يرجع Chute الاستجابة الاصطناعية مباشرة إلى العميل دون الاتصال بالخادم العلوي. هذا مفيد للحظر، محاكاة APIs، أو إرجاع محتوى مخزن مؤقتاً.

قيم إرجاع سكريبت استجابة HTTP:

$done({
    status: 200,                              // تعديل رمز الحالة
    headers: {"X-Custom": "value"},           // تعديل ترويسات الاستجابة
    body: "new response body",                // تعديل محتوى الاستجابة
    url: "https://other.example.com"          // تشغيل إعادة توجيه 302
})

عند توفير url، يرجع Chute إعادة توجيه 302 إلى الرابط المعطى بدلاً من الاستجابة الأصلية. يجب إرجاع url مع واحد على الأقل من status / headers / body؛ النتيجة التي تحتوي على url فقط تُعامل كتمرير.

قيم إرجاع سكريبت DNS:

$done({address: "1.2.3.4"})                  // IP واحد
$done({addresses: ["1.2.3.4", "5.6.7.8"]})   // عدة IPs
$done({address: "10.0.0.1", ttl: 300})       // مع TTL مخصص (بالثواني، الافتراضي 60)

المفتاحان server / servers مقبولان لكن يتم تجاهلهما حالياً؛ يسقط التحليل إلى DNS العادي.

$httpClient — عميل HTTP غير متزامن

إجراء طلبات HTTP من داخل السكريبتات. يتم إلغاء جميع الطلبات عند $done() أو المهلة.

$httpClient.get(url, function(error, response, data) {
    if (error) {
        console.log("Request failed: " + error)
    } else {
        console.log("Status: " + response.status)
        console.log("Response: " + data)
    }
})

$httpClient.post(url, {headers: {...}, body: "...", timeout: 5}, callback)
$httpClient.put(url, options, callback)
$httpClient.del(url, options, callback)
$httpClient.head(url, options, callback)
$httpClient.options(url, options, callback)
$httpClient.patch(url, options, callback)

توقيع callback: callback(error, response, data)

  • error: نص الخطأ أو null
  • response: {status: Number, headers: Object} أو null
  • data: محتوى استجابة UTF-8 نصي أو null

$httpClient متوفر في سكريبتات http-request و http-response و http-request-before-send و cron و event. وهو غير متوفر في سكريبتات rule و dns.

$persistentStore — تخزين Key-Value

تخزين key-value دائم يبقى عبر إعادة تشغيل السكريبتات والعمليات. مدعوم بـ NSUserDefaults.

$persistentStore.write(data, key)   // تخزين قيمة
$persistentStore.read(key)          // استرجاع قيمة
$persistentStore.remove(key)        // إزالة قيمة

$notification — الإشعارات المحلية

نشر إشعارات نظام محلية.

$notification.post("Title", "Subtitle", "Notification body text")

$network — معلومات الشبكة

معلومات حالة الشبكة للقراءة فقط.

$network.dns   // مصفوفة من عناوين IP لخوادم DNS
$network.wifi  // {ssid: "WiFiName", bssid: null}

bssid دائماً null؛ ولا تُعبأ ssid إلا على iOS.

تنبيه: في الإصدارات الحالية، الخاصيتان $network و $environment غير مرئيتين للسكريبتات بسبب قيد في الجسر (bridging) وتُقرآن كـ undefined. بيانات $script الوصفية متاحة في سكريبتات cron و event فقط.

$environment — معلومات وقت التشغيل

$environment.system     // "iOS" أو "macOS"
$environment.appVersion // نص إصدار KLNEKit SDK

$utils — أدوات مساعدة

$utils.geoip("1.2.3.4")   // رمز الدولة (مثال: "US")
$utils.ipasn("1.2.3.4")   // رقم ASN (مثال: "13335")
$utils.ungzip(data)       // فك ضغط بيانات gzip

$klne — واجهة التحكم بالبروكسي

التحكم في وقت تشغيل البروكسي من السكريبتات. $klne متوفر في جميع أنواع السكريبتات.

$klne.getPolicyGroups()               // الحصول على جميع مجموعات السياسات
$klne.selectPolicy("Group", "Proxy")  // تبديل سياسة لمجموعة
$klne.getActiveConnections()          // سرد الاتصالات النشطة
$klne.closeConnection("id")           // محجوزة — حالياً بلا تأثير
$klne.flushDNS()                      // مسح ذاكرة DNS المؤقتة
$klne.startURLTest("Group")           // تشغيل اختبار رابط لمجموعة
$klne.reloadConfiguration()           // إعادة تحميل جميع الإعدادات
$klne.setOutboundMode("rule")         // تعيين النمط: "global"/"proxy", "direct", "rule"
$klne.setHTTPCaptureEnabled(true)     // تفعيل/تعطيل MitM

تُرجع getPolicyGroups() مجموعات السياسات القابلة للاختيار:

{
  count: 1,                    // Number — عدد المجموعات
  policyGroups: [{
    name: "MainGroup",         // String — اسم المجموعة
    type: 0,                   // Number — 0 select, 1 url-test, 2 fallback, 3 ssid, 5 load-balance
    policyNames: ["A", "B"],   // Array of String — السياسات المرشحة
    selectedIndex: 0,          // Number — فهرس السياسة النشطة (يغيب عندما تكون غير محسومة)
    selectedPolicy: "A"        // String — اسم السياسة النشطة (يغيب عندما تكون غير محسومة)
  }]
}

تُرجع getActiveConnections() مصفوفة (Array) تصف الاتصالات الحالية:

[{
  id: "0x600002f01230",  // String — معرّف اتصال مبهم
  host: "example.com",   // String — المضيف الوجهة (يغيب عندما يكون مجهولاً)
  port: 443              // Number — منفذ الوجهة
}]

أما بقية الدوال فتأخذ وسائط بسيطة ولا تُرجع شيئاً:

  • selectPolicy(group, policy) — تجعل policy (اسماً من policyNames الخاصة بالمجموعة) السياسة النشطة لـ group. اسم المجموعة أو السياسة غير المعروف يُتجاهل مع تحذير في السجل.
  • closeConnection(id) — محجوزة. لا تستطيع النواة الحالية إغلاق اتصالات مفردة؛ استدعاؤها لا يفعل سوى تسجيل تحذير ولا يغلق شيئاً.
  • flushDNS() — تمسح ذاكرة DNS المؤقتة.
  • startURLTest(group) — تبدأ اختبار زمن استجابة غير متزامن لمجموعة من نوع url-test أو fallback؛ أنواع المجموعات الأخرى والأسماء غير المعروفة تُتجاهل مع تحذير.
  • reloadConfiguration() — تعيد تحميل الإعدادات الحالية.
  • setOutboundMode(mode)"global" و "proxy" كلاهما يوجّه كل الحركة عبر البروكسي، و"direct" يرسل كل الحركة مباشرةً، وأي قيمة أخرى تختار نمط القواعد.
  • setHTTPCaptureEnabled(enabled) — تفعّل أو تعطّل فك تشفير HTTPS (MitM) أثناء التشغيل؛ تأخذ قيمة منطقية.

$script — بيانات السكريبت الوصفية

$script.name       // اسم السكريبت من الإعدادات
$script.type       // نص نوع السكريبت
$script.startTime  // طابع زمني رتيب (ثوانٍ منذ مرجع إقلاع النظام، وليس Epoch)

globals لكل تنفيذ

يتم حقن المتغيرات التالية لكل تنفيذ سكريبت وهي خاصة بأنواع سكريبتات معينة.

$argument — وسيط السكريبت

القيمة النصية من معامل argument= في إعدادات السكريبت. متوفر في: http-request, http-response, http-request-before-send, rule, dns, cron, event.

console.log("Argument: " + $argument)

$domain — نطاق DNS (لسكريبتات DNS فقط)

اسم النطاق الذي يتم الاستعلام عنه. متوفر فقط في سكريبتات dns.

var domain = $domain  // مثال: "example.com"

$cronexp — تعبير Cron (لسكريبتات Cron فقط)

تعبير جدولة cron من إعدادات السكريبت. متوفر فقط في سكريبتات cron.

console.log("Schedule: " + $cronexp)  // مثال: "*/30 * * * *"

$event — معلومات الحدث (لسكريبتات Event فقط)

معلومات عن الحدث المشغل. حالياً فقط network-changed مدعوم.

console.log("Event: " + $event.name)  // "network-changed"

console — التسجيل

console.log("Debug message")    // سجل تفصيلي
console.warn("Warning message")  // سجل تحذيري
console.error("Error message")   // سجل تحذيري موسوم كخطأ JavaScript

setTimeout(fn, seconds) — مؤقت

جدولة دالة للتشغيل بعد تأخير.

setTimeout(function() {
    console.log("Delayed execution")
}, 2.5)  // 2.5 ثانية

$scriptImport(subScriptPath) — محمل السكريبتات الفرعية

تحميل وتقييم ملف JavaScript آخر. تُدعم مسارات الملفات المحلية فقط؛ روابط http(s):// و file:// مرفوضة. ($script محجوز لكائن بيانات السكريبت الوصفية.)

$scriptImport("/path/to/helper.js")

// تمرير البيانات بين السكريبتات باستخدام $persistentStore

تفاصيل أنواع السكريبتات

سكريبت طلب HTTP

ينفذ عند استلام ترويسات الطلب. يمكنه تعديل الرابط، الترويسات، والمحتوى قبل توجيه الطلب.

[Script]
ModifyHeaders = type=http-request, script-path=modify.js, pattern=^https://api\.example\.com

سكريبت استجابة HTTP

ينفذ عند استلام ترويسات الاستجابة. يمكنه تعديل الحالة، الترويسات، والمحتوى قبل الإرجاع إلى العميل.

[Script]
ModifyResponse = type=http-response, script-path=response.js, pattern=^https://api\.example\.com

سكريبت HTTP Request Before Send

ينفذ بعد جمع محتوى الطلب الكامل، قبل الإرسال إلى الخادم العلوي مباشرة. مفيد لتعديل محتويات طلبات POST/PUT.

[Script]
BeforeSend = type=http-request-before-send, script-path=before-send.js, pattern=^https://api\.example\.com, requires-body=true

سكريبت القاعدة

مطابقة قواعد مخصصة. يجب على السكريبت استدعاء $done({matched: true}) أو $done({matched: false}).

[Rule]
SCRIPT,MyRuleScript,DIRECT

[Script]
MyRuleScript = type=rule, script-path=rule.js

سكريبت DNS

تحليل DNS مخصص. يستقبل $domain ويرجع عنواناً (عناوين) محللة.

// dns.js
var domain = $domain
if (domain === "internal.example.com") {
    $done({address: "10.0.0.1", ttl: 300})
} else {
    $done({})  // تمرير إلى تحليل DNS العادي
}

سكريبت Cron

تنفيذ مجدول باستخدام تعبيرات cron. الحد الأدنى للفاصل هو 60 ثانية.

[Script]
HalfHourlyTask = type=cron, script-path=task.js, cron-expression=*/30 * * * *

يُحترم فقط حقل الدقائق من التعبير: */N يعمل كل N دقيقة. أي تعبير آخر ينطلق كل 60 ثانية، ويجب على السكريبت التحقق من الوقت الحالي بنفسه ليقرر ما إذا كان سيتصرف.

سكريبت الحدث

يتم تشغيله بواسطة أحداث النظام. حالياً يدعم حدث network-changed (ينطلق عند تغير شبكة WiFi أو الجوال).

[Script]
NetChange = type=event, script-path=network-changed.js

كائن $event متاح:

$event.name  // "network-changed"

أمثلة عملية

إعادة توجيه الأجهزة المحمولة

سكريبت http-request يعيد توجيه مستخدمي الجوال بناءً على User-Agent:

[Script]
MobileRedirect = type=http-request, script-path=mobile-redirect.js, pattern=^https://example\.com
// mobile-redirect.js
var ua = $request.headers["User-Agent"] || ""
if (/Mobile|Android|iPhone/.test(ua)) {
    $done({
        response: {
            status: 302,
            headers: {"Location": "https://m.example.com" + $request.url.replace(/.*example\.com/, "")},
            body: ""
        }
    })
} else {
    $done({})
}

حظر المحتوى في استجابات API

سكريبت http-response يزيل الإعلانات والمحتوى المدعوم من استجابة JSON API:

[Script]
RemoveAds = type=http-response, script-path=remove-ads.js, pattern=^https://api\.example\.com/feed, requires-body=true
// remove-ads.js
var body = JSON.parse($response.body)
if (body.ads) {
    delete body.ads
}
if (body.recommendations) {
    body.recommendations = body.recommendations.filter(function(r) {
        return !r.sponsored
    })
}
$done({body: JSON.stringify(body)})

تعديل محتوى الطلب قبل الإرسال

سكريبت http-request-before-send ينقي حمولة POST:

[Script]
SanitizePayload = type=http-request-before-send, script-path=sanitize.js, pattern=^https://api\.example\.com/submit, requires-body=true
// sanitize.js
var body = JSON.parse($request.body)
body.clientSecret = "[REDACTED]"
body.timestamp = Math.floor(Date.now() / 1000)
$done({body: JSON.stringify(body)})

قاعدة مخصصة: التوجيه حسب الوقت

سكريبت rule يختار بروكسي مختلف حسب وقت اليوم:

[Rule]
SCRIPT,TimeBasedRule,ProxyA

[Script]
TimeBasedRule = type=rule, script-path=time-rule.js
// time-rule.js
var hour = new Date().getHours()
if (hour >= 9 && hour < 18) {
    $done({matched: false})  // السقوط إلى القاعدة التالية خلال ساعات العمل
} else {
    $done({matched: true})   // استخدام ProxyA خارج ساعات العمل
}

DNS مخصص للنطاقات الداخلية

سكريبت dns يحل أسماء المضيفين الداخلية إلى عناوين IP محلية:

[Script]
InternalDNS = type=dns, script-path=internal-dns.js
// internal-dns.js
var internalHosts = {
    "gitlab.local": "10.0.0.10",
    "registry.local": "10.0.0.11",
    "monitor.local": "10.0.0.12"
}
if (internalHosts[$domain]) {
    $done({address: internalHosts[$domain], ttl: 3600})
} else {
    $done({})  // تمرير إلى DNS العادي
}

التبديل التلقائي للسياسة عند تغيّر الشبكة

سكريبت event يفحص الاتصال بعد تغيّر الشبكة ويبدل مجموعة السياسات وفقًا لذلك:

[Script]
NetSwitch = type=event, script-path=network-switch.js
// network-switch.js
$httpClient.head("https://www.google.com/generate_204", {timeout: 5},
    function(error, response, data) {
        if (error) {
            // فشل الفحص على الشبكة الجديدة — التبديل إلى المجموعة الاحتياطية
            $klne.selectPolicy("MainGroup", "BackupProxy")
            console.log("Probe failed after " + $event.name)
        } else {
            $klne.selectPolicy("MainGroup", "MainProxy")
        }
        $done({})
    })

تنبيه: قراءة SSID لشبكة Wi-Fi عبر $network هي الحل الطبيعي هنا، لكن $network غير مرئي للسكريبتات حاليًا (انظر التنبيه في $network)؛ في الإصدارات الحالية يمكن الاعتماد على الفحص عبر $httpClient.

فحص دوري للصحة

سكريبت cron يتحقق من صحة البروكسي كل 30 دقيقة:

[Script]
HealthCheck = type=cron, script-path=health-check.js, cron-expression=*/30 * * * *
// health-check.js
$httpClient.head("https://www.google.com/generate_204", {timeout: 10},
    function(error, response, data) {
        if (error || response.status !== 204) {
            console.error("Health check failed: " + (error || "status " + response.status))
            $notification.post("Chute Alert", "Health Check", "Cannot reach Google")
        } else {
            console.log("Health check OK")
        }
        $done({})
    }
)

استدعِ $done({}) داخل الـ callback — إكمال السكريبت يلغي جميع طلبات $httpClient المعلقة، لذا فإن $done() متزامناً في نهاية السكريبت سيلغي فحص الصحة قبل وصول استجابته.

إثراء استجابات API ببيانات خارجية

سكريبت http-response يثري بيانات المستخدمين باستدعاء API ثانوي:

[Script]
EnrichUsers = type=http-response, script-path=enrich.js, pattern=^https://api\.example\.com/users, requires-body=true
// enrich.js
var users = JSON.parse($response.body)
var pending = users.length
if (pending === 0) { $done({}) }

users.forEach(function(user, index) {
    $httpClient.get("https://internal-api.example.com/avatar/" + user.id,
        function(error, resp, data) {
            if (!error && resp.status === 200) {
                users[index].avatar = JSON.parse(data).url
            }
            pending--
            if (pending === 0) {
                $done({body: JSON.stringify(users)})
            }
        }
    )
})

نموذج التنفيذ

  • تعمل جميع السكريبتات على طابور تسلسلي مخصص لسلامة الخيوط.
  • كل تنفيذ سكريبت له مهلة خاصة به؛ إذا لم يتم استدعاء $done() خلال المهلة، يعامل السكريبت كتمرير.
  • يُحتفظ بمجموعة من 3 سياقات JSContext مهيأة مسبقاً؛ يُتخلص من السياق بعد كل تنفيذ ويُستبدل بآخر جديد، لذا لا تتسرب globals أبداً بين التشغيلات.
  • على iOS/tvOS، تخضع السكريبتات لحد ذاكرة 10MB؛ على macOS، 512MB.
  • السكريبتات البعيدة (مسارات HTTP/HTTPS) تُجلب عند كل تنفيذ. عندما تكون script-update-interval غير صفرية، يستطلع Chute الرابط إضافياً بطلب HEAD شرطي كل 10 دقائق؛ 0 (الافتراضي) يعطل الاستطلاع.

دمج سكريبتات الوحدات

يمكن أيضاً تعريف السكريبتات في ملفات Module (.sgmodule) تحت القسم [Script].

S. Smart Rabbit LLC © All Rights Reserved            updated 2026-08-18 12:00:48

هذه الصفحة ترجمة للنسخة الإنجليزية. في حال وجود اختلاف، يُعتمد على النسخة الإنجليزية.

ملاحظة: التطبيق لا يدعم اللغة العربية حاليًا.

results matching ""

    No results matching ""