Satu kontrak untuk ekstensi situs.
Identitas, versi, dan kepercayaan
Setiap plugin memiliki identifier namespace / name, versi paket semantik independen dan tepat API versi "1". Namespace eyivo direserve. Tipe sistem atau standar; asal adalah sistem, diverifikasi atau pihak ketiga. Hanya platform-platform yang disetujui paket sistem-asal yang diterima dalam rilis ini. Paket tidak dapat memberikan diri mereka status yang diperlukan atau kemampuan baru.
Pemasangan dan konfigurasi
Master yang ditugaskan memiliki catatan instalasi. Pasang, aktifkan, non-aktifkan, uninstall dan upgrade jalankan di bawah sebuah situs dan transaksi basis data. Ketergantungan memasang pertama; hilang paket, siklus, konflik, dan penurunan nilai ditolak. Ketergantungan aktif dan platform-dibutuhkan paket tidak dapat dinonaktifkan atau dihapus. Tingkatkan kait menerima konfigurasi _ versi sebelumnya dan mungkin memmigrasi konfigurasi namespace mereka melalui APIKonfigurasi menggunakan skema skalar / objek yang dideklarasikan ditambah baku; kunci tidak dikenal ditolak. Penangan lifecycle harus kembali sebuah array dan tidak boleh bergantung pada efek samping eksternal.
Pengaturan dengan lingkup yang jelas.
Setiap situs dan plugin memiliki konfigurasi sendiri dalam database master yang ditugaskan. Panel aplikasi membaca dan menyimpan melalui Internal yang terotentikasi API di WireGuard; tidak ada kredensial basis data utama. Layanan bersama di plugins.eyivo.com menggunakan basis data terpisah untuk keadaan layanan.
Ladang Declared
50 maksimum
Kontainer objek dan properti nested berbagi total yang sama.
Konfigurasi lengkap
Maksimum 32 KB
32,768 kompak UTF-8 JSON byte, termasuk kunci, nilai, dan baku.
Kedalaman nesting
maksimum 3 tingkat
Bidang tingkat atas mulai di tingkat satu.
Host memvalidasi skema ketika mendaftarkan paket dan pemeriksaan konfigurasi lengkap pada setiap penulisan. Kunci tak dikenal ditolak. Panel kontrol dan validasi peramban tidak menggantikan penekanan sisi server.
String dukungan skema, integer, boolean, dan obyek dengan properti eksplisit. Array dan peta sewenang-wenang bukan tipe konfigurasi. Panjang string diukur dalam bytes. Bidang level Top-mulai di tingkat satu; wadah objek menghitung ke arah baik field total dan kedalaman bersarang.
Simpan revisi plugin situs. Revisi tetap mengembalikan konflik daripada menimpa pengaturan yang lebih baru. Muat ulang dan tinjau ulang nilai saat ini sebelum mencoba lagi. Mutasi ke plugin manapun di situs mengubah revisi ini, termasuk menonaktifkan, mengaktifkan, membatalkan, dan memasang ulang.
Lihat batas skema konfigurasi dan aturan pengkodean
{
"fields": 50,
"depth": 3,
"bytes": 32768,
"counting": "Every declared property counts, including object containers. Top-level fields are level one. JSON bytes include recursively merged defaults, keys and values, encoded compactly with UTF-8 characters and slashes unescaped.",
"types": [
"string",
"integer",
"boolean",
"object"
],
"policy": "Objects require explicit properties; unknown keys and arrays are rejected. Strings default to 4096 bytes and support min/max up to 32768 bytes. Integer min/max and scalar enum choices are supported. constructor, prototype and __proto__ are reserved keys."
}
Halamanmu, komponen Eyivo.
Suatu plugin memiliki definisi halamannya, tata letak, konten lokal, bentuk, dan aksi yang dinyatakan. Aplikasi pusat membuat definisi dengan komponen terpercaya di dalam panel pengguna yang ada. Mengklik plugin membuka halaman entri yang dinyatakan, seperti konfigurasi atau pengiriman inbox.
-
Menentukan halaman
Definisi halaman pendaftaran dan pengikat konfigurasi dalam paket. Tautan menu opsional yang dimiliki oleh plugin yang sama.
-
Penyewa dalam aplikasi
Aplikasi memeriksa akses situs dan menerima validasi JSON definisi dan data dari master yang ditugaskan. Tak ada plugin PHP atau Blade dipindahkan ke atau dieksekusi oleh aplikasi.
-
Eksekusi pada master
Aksi yang diijinkan melalui Internal API untuk penangan terbatas. Para master memaksa negara plugin, kemampuan, skema, dan batas konfigurasi.
Kelompok Plugin Tingkat Tunggal
Taut yang dapat dihapus muncul secara langsung di bawah Plugin bagi situs yang dipilih. Submenu yang dirested tidak didukung. Grup tetap tersembunyi ketika tidak ada taut yang terlihat. Menonaktifkan atau mencabut penghapus tautan dan memblokir halaman langsung dan akses aksi, termasuk permintaan dari tab yang sudah dibuka. Mengaktifkan toko ulang link yang berlaku.
Paket tanpa deklarasi panel, dan paket dinonaktifkan, membuka tampilan informasi dari daftar plugin. Paket yang dinonaktifkan tidak mengekspos halaman panel atau aksi yang terdaftar. Verifikasi Manusia menyediakan halaman paket baca-saja; standar keamanannya tetap terkontrol platform.
Keanggotaan situs dan aksi yang dinyatakan
Halaman dan aksi gubahan menyatakan tampilan atau ijin pengelolaan. Anggota situs saat ini dapat melihat halaman yang memenuhi syarat dan memohon aksi hanya tampilan; mengelola kebutuhan peran pemilik situs. Aplikasi ini mengambil aktor terpercaya dari keanggotaan signed-in. Bangun -in konfigurasi simpan / reset aksi memerlukan pengelolaan; pengelola custom menggunakan parameter dan skema respon. Setiap halaman hanya memungkinkan ID aksi yang terdaftar.
Pengungkapan tidak memberikan otoritas
Pemuatan halaman hanya dibaca. Satu halaman atau menu tidak dapat memberikan tanpa batas PHP, akses basis data, rute aplikasi yang sewenang-wenang, atau skrip di dalam panel yang terotentikasi. Mengekspos paket tanpa deklarasi panel tetap bekerja. Instalasi paket paket ketiga-partai tetap dinonaktifkan.
Komponen yang didukung
Tulis halaman memakai komponen terpercaya ini. Fields bind ke konfigurasi atau aksi masukan; pratilik tampilkan teks dan tabel polos secara baca-saja. Raw HTML, skrip sewenang-wenang, ekspresi, dan rendering kondisional tidak didukung.
stackgridcardtextalertfieldbuttonpreviewtablesubmission-listsubmission-detail
Lihat Panel Berjudul API kontrak dan batas
{
"api": "2",
"execution": "Plugins own JSON page definitions and restricted master-side handlers. App receives validated localized JSON only; plugin PHP, Blade, JavaScript, CSS, raw HTML and handler paths are not transferred or executed in the panel.",
"capabilities": [
"panel.render",
"panel.action",
"site.settings.read",
"site.settings.write"
],
"components": [
"stack",
"grid",
"card",
"text",
"alert",
"field",
"button",
"preview",
"table",
"submission-list",
"submission-detail"
],
"controls": [
"text",
"textarea",
"number",
"checkbox",
"select"
],
"action_types": [
"configuration.save",
"configuration.reset",
"handler"
],
"permissions": {
"view": [
"owner",
"viewer"
],
"manage": [
"owner"
]
},
"limits": {
"pages": 10,
"menu_links": 10,
"menu_depth": 1,
"actions": 20,
"action_input_bytes": 32768,
"components_per_page": 100,
"component_depth": 8,
"page_file_bytes": 65536,
"response_bytes": 262144,
"table_columns": 10,
"table_rows": 100
},
"configuration": "Configuration.save receives a complete configuration object as input; configuration.reset accepts empty input. Both require manage permission and site.settings.write. All panel actions require panel.action. Custom handlers declare view (read-only even for owners) or manage permission; their input/response use declared bounded schemas. Page loaders are read-only.",
"concurrency": "Every action requires the page revision. The master compares site.plugin_revision under the existing site row lock; stale saves return HTTP 409. Deactivation or uninstall blocks pages/actions and removes derived menus.",
"localization": "Definitions use locale maps with a required en fallback. The master localizes text before sending JSON to app. Field labels and input guidance are required.",
"supported_versions": [
"1",
"2"
],
"submissions": {
"version": "2",
"declaration": "submission-list declares form_type and detail_page; submission-detail declares the same form_type and list_page. Every registered form type requires mutually linked viewable pages and a flat sidebar menu entry to its list.",
"execution": "The host resolves current site/plugin ownership and supplies paginated summaries or a stored historical detail snapshot. App constructs all navigation and action URLs. Package PHP never reaches app.",
"contexts": "Page loaders receive authenticated actor and validated query/record context. Plugin operations cannot override the current site or plugin. Creating records requires an out-of-band host-issued FormProcessingContext unavailable to interpreted package code.",
"state": "Reading, archive and workflow state are independent. Record mutations require the current record_revision; configuration still uses plugin_revision. Viewing never marks a submission read. Viewers may read; existing owner/manage permissions govern mutations."
}
}
Bentuk dan riwayat pengajuan
Bentuk API 1 menyediakan tujuh prosesor yang disetujui. Tema memiliki tata letak dan gaya; plugin memiliki skema, validasi, dan alur kerja. Host menangani kegigihan, verifikasi, dan pemberitahuan.
| Plugin sistem | Tipe formulir |
|---|---|
eyivo/contact | Kontak contact |
eyivo/quote-request | Permintaan Kutipan quote_request |
eyivo/product-inquiry | Proses penyelidikan product_inquiry |
eyivo/appointment-request | Permintaan pertemuan appointment |
eyivo/course-application | Aplikasi kursus course_application |
eyivo/reservation-request | Permintaan pemesanan reservation |
eyivo/property-inquiry | Penyelidikan properti property_inquiry |
Satu bentuk, placements dapat digunakan kembali
Penyiapan membuat sebuah baku yang ditahan UUID per situs / plugin / type. Mengganti penempatan membuat identitas itu; membuat sebuah bentuk nama memberikan terpisah UUIDTema perubahan dan plugin memasang ulang riwayat. Tema menyatakan alias portabel; pemilihan penyunting menyimpan formulir tanpa meminta pelanggan untuk mengetik UUID.
{
"plugins": ["eyivo/contact", "eyivo/quote-request"],
"forms": {
"contact": {"plugin":"eyivo/contact","type":"contact","schema_version":1,"instance":"default"},
"quote": {"plugin":"eyivo/quote-request","type":"quote_request","schema_version":1,"instance":"default"}
}
}
Gunakan forms.contact dalam template kontak dan component.form dalam bagian lead. Ganti formulir _ preset dengan format _ binding. Render diberikan field dan bimbingan, aksi, CSRF, signed form _ context dan verifikasi _ html. Hanya dideklarasikan presentasi overrides dan bidang tambahan diijinkan diterima; dibutuhkan validasi tidak dapat melemah.
forms.contact · component.form · form_binding · form.fields · form.action · form.csrf_token · form.context · form.verification_html
Dua tampilan inbox, satu rekaman
Inbox situs bersama dan setiap bentuk plugin sendiri daftar / detail halaman menampilkan catatan yang sama. Paket formulir membutuhkan Panel API 2 submisi- daftar / submission- komponen detail dan link menu datar. Panel API 1 tetap didukung. Viewing tidak menandai catatan yang dibaca; baca / archive / workflow menyatakan terpisah dan edits menggunakan record _ revisi. Plugin yang tidak aktif kehilangan menu / halaman, sedangkan inbox yang berbagi mempertahankan snapshot historis.
{"components":[{"type":"submission-list","form_type":"contact","detail_page":"submission"}]}
{"components":[{"type":"submission-detail","form_type":"contact","list_page":"submissions"}]}
Data dan perizinan pelanggan
Catatan formulir tetap dalam basis data konten yang diberikan dan berbagi paket max _ db _ bytes yang ada dengan konten lain. Tidak ada submission terpisah -count atau retention quota ditambahkan. Konfigurasi tetap dalam basis data master dengan batas dari 50 field, 32 KB dan tiga tingkat. Anggota dapat melihat; pemilik / pengelolaan perubahan ijin. Plugin tidak menerima akses basis data langsung, dan PHP/ Blade tidak pernah bergerak ke aplikasi.
Diverifikasi penyimpanan dan pemberitahuan
Host memvalidasi konteks yang ditandatangani, menyatakan jawaban dan dibutuhkan Verifikasi Manusia, kemudian melakukan catatan, penggunaan, dan pemberitahuan bekerja bersama. Percobaan identik dan pembayaran pulih selama 24 jam tanpa menabung dua kali. SMTP pengiriman berjalan sesudahnya dan mungkin mencoba lagi; kegagalan surel tidak membatalkan catatan tersimpan. Penerima formulir yang tidak diatur kembali ke email perusahaan; jika alamat tidak valid, pengajuan disimpan tanpa email.
Semua tema dikirim menggunakan kontrak ini. Kontak legacy POSTs kembali 410; kontekt- halaman GET link masih bekerja. Permintaan pendahuluan dan reservasi tidak mengkonfirmasi booking. Ketiga-partai formulir prosesor, file upload dan aksi eksternal sewenang-wenang tidak termasuk.
POST /__eyivo/forms/{UUID}/submissionsGET /__eyivo/forms/{UUID}/challenge
Tema dan penempatan formulir
Tema menyatakan ketergantungan yang disetujui dan bentuk portabel alias dalam theme.json. Sebuah binding mengidentifikasi plugin, tipe, schema _ version dan instance; setup menyelesaikannya ke bentuk situs yang dipertahankan UUID. Templat kontak memakai forms.contact, dan komponen lead gunakan component.form dengan form _ binding. Render daerah yang diberikan, aksi, CSRF token, signed form _ context dan verifikasi _ html. Gunakan hanya deklarasi perubahan atau field tambahan yang diijinkan; dibutuhkan plugin validasi tidak dapat melemah. Semua tema dikirim menggunakan kontrak ini. Aksi eksternal dan kontak pensiun POST tidak didukung jalur pengiriman.
{"component_type":"eyivo:lead_form","data":{"form_binding":"contact"}}
Forms API 1
{
"api": "1",
"approval": "Only configured, approved Eyivo system form packages may declare forms; they require Human Verification and mandatory Panel API 2 submission pages.",
"schema": "forms.types maps stable identifiers to schema_version, localized label, fields, extensions, workflow and a restricted processor file. Fields declare scalar type, compatible control, required flag, localized label and guidance; strings require explicit max. No PHP, SQL, validation expressions or unknown fields are accepted.",
"field_types": [
"string",
"integer",
"boolean"
],
"controls": [
"text",
"textarea",
"email",
"tel",
"url",
"date",
"datetime-local",
"select",
"number",
"checkbox"
],
"presentation_extensions": [
"label",
"placeholder",
"help",
"order"
],
"storage": "The host owns site content storage. Plugin packages receive no credentials, database connection, SQL or unrestricted internal services. Site ownership is injected; schema snapshots remain readable without installed plugin code.",
"quotas": "Submission data consumes the existing package database allowance. Configuration limits of 50 fields / 32768 bytes / three levels do not cap form fields or accumulated submissions. Existing runtime, request and pagination bounds are technical transport protections.",
"identity": "Each site/plugin/type has a retained default form UUID created during authorized setup. Themes resolve portable aliases; rendering does not create instances. Additional named instances receive their own UUID. Theme changes and plugin reinstall preserve history.",
"transport": {
"encoding": "Escaped JSON byte counts match the restricted plugin interpreter; these technical ceilings do not limit accumulated form or submission counts.",
"schema_bytes": 49152,
"schema_accounting": "Definition plus one additional workflow copy, reserving the repeated workflow information on detail responses.",
"answers_bytes": 49152,
"source_bytes": 4096,
"processor_context_bytes": 114688,
"maximum_api_page": 25,
"instances_summary": [
"id",
"plugin_id",
"form_type",
"name",
"schema_version_id",
"record_revision",
"is_default"
]
}
}
Contoh manifest plugin
{
"id": "eyivo/human-verification",
"name": "Human Verification",
"version": "1.1.0",
"api": "1",
"type": "system",
"origin": "system",
"required": true,
"capabilities": [
"form.inject",
"form.validate",
"frontend.assets",
"public.endpoint",
"verification.challenge",
"verification.verify",
"panel.render"
],
"panel": {
"api": "1",
"entry": "settings",
"pages": {
"settings": {
"title": {
"en": "Human Verification",
"id": "Verifikasi Manusia",
"tr": "\u0130nsan Do\u011frulama",
"de": "Menschliche Verifizierung",
"es": "Verificaci\u00f3n humana",
"fr": "V\u00e9rification humaine",
"pt": "Verifica\u00e7\u00e3o humana",
"it": "Verifica umana",
"ar": "\u0627\u0644\u062a\u062d\u0642\u0642 \u0627\u0644\u0628\u0634\u0631\u064a"
},
"permission": "view",
"view": "panel/settings.json",
"actions": []
}
},
"menu": [],
"actions": []
},
"dependencies": {
"plugins": []
},
"conflicts": [],
"configuration": [],
"defaults": [],
"hooks": {
"form.before_submit": "render.php",
"form.validate": "validate.php"
},
"render_hook": "form.before_submit",
"required_validators": [
"contact"
],
"lifecycle": [],
"assets": [
{
"path": "assets/verification.css",
"type": "style"
},
{
"path": "assets/verification.js",
"type": "script"
}
],
"endpoints": {
"challenge": {
"method": "GET",
"handler": "challenge.php",
"parameters": {
"form_id": {
"type": "string",
"required": true,
"enum": [
"contact"
]
},
"locale": {
"type": "string",
"max": 10
}
},
"response": {
"token": {
"type": "string",
"max": 4096
},
"image": {
"type": "string",
"max": 65536
},
"expires_in": {
"type": "integer"
}
}
}
}
}
Plugin sistem · eyivo/contact · Forms API 1 / Panel API 2
{
"id": "eyivo/contact",
"name": "Contact",
"version": "1.0.0",
"api": "1",
"type": "system",
"origin": "system",
"required": false,
"capabilities": [
"forms.submissions.create",
"forms.submissions.read",
"forms.submissions.manage",
"forms.instances.read",
"forms.instances.manage",
"panel.render",
"panel.action"
],
"dependencies": {
"plugins": [
"eyivo/human-verification"
]
},
"conflicts": [],
"configuration": [],
"defaults": [],
"hooks": [],
"required_validators": [],
"lifecycle": [],
"assets": [],
"endpoints": [],
"forms": {
"api": "1",
"types": {
"contact": {
"schema_version": 1,
"label": {
"en": "Contact",
"id": "Kontak",
"tr": "İletişim",
"de": "Kontakt",
"es": "Contacto",
"fr": "Contact",
"pt": "Contato",
"it": "Contatti",
"ar": "التواصل",
"ru": "Контакт",
"nl": "Contact",
"pl": "Kontakt",
"ja": "お問い合わせ",
"ko": "문의",
"zh": "联系"
},
"fields": {
"name": {
"type": "string",
"control": "text",
"required": true,
"label": {
"en": "Name",
"id": "Nama",
"tr": "Ad",
"de": "Name",
"es": "Nombre",
"fr": "Nom",
"pt": "Nome",
"it": "Nome",
"ar": "الاسم",
"ru": "Имя",
"nl": "Naam",
"pl": "Imię i nazwisko",
"ja": "氏名",
"ko": "이름",
"zh": "姓名"
},
"max": 255,
"placeholder": {
"en": "Your full name",
"id": "Nama lengkap Anda",
"tr": "Adınız ve soyadınız",
"de": "Ihr vollständiger Name",
"es": "Tu nombre completo",
"fr": "Votre nom complet",
"pt": "Seu nome completo",
"it": "Il tuo nome completo",
"ar": "اسمك الكامل",
"ru": "Ваше полное имя",
"nl": "Uw volledige naam",
"pl": "Twoje imię i nazwisko",
"ja": "氏名を入力してください",
"ko": "성명을 입력하세요",
"zh": "请输入您的姓名"
},
"autocomplete": "name"
},
"email": {
"type": "string",
"control": "email",
"required": true,
"label": {
"en": "Email",
"id": "Email",
"tr": "E-posta",
"de": "E-Mail",
"es": "Correo electrónico",
"fr": "E-mail",
"pt": "E-mail",
"it": "Email",
"ar": "البريد الإلكتروني",
"ru": "Электронная почта",
"nl": "E-mail",
"pl": "E-mail",
"ja": "メールアドレス",
"ko": "이메일",
"zh": "电子邮箱"
},
"max": 254,
"placeholder": {
"en": "Your email address",
"id": "Alamat email Anda",
"tr": "E-posta adresiniz",
"de": "Ihre E-Mail-Adresse",
"es": "Tu dirección de correo",
"fr": "Votre adresse e-mail",
"pt": "Seu endereço de e-mail",
"it": "Il tuo indirizzo email",
"ar": "عنوان بريدك الإلكتروني",
"ru": "Ваш адрес электронной почты",
"nl": "Uw e-mailadres",
"pl": "Twój adres e-mail",
"ja": "メールアドレスを入力してください",
"ko": "이메일 주소를 입력하세요",
"zh": "请输入您的电子邮箱地址"
},
"autocomplete": "email"
},
"phone": {
"type": "string",
"control": "tel",
"required": false,
"label": {
"en": "Phone",
"id": "Telepon",
"tr": "Telefon",
"de": "Telefon",
"es": "Teléfono",
"fr": "Téléphone",
"pt": "Telefone",
"it": "Telefono",
"ar": "الهاتف",
"ru": "Телефон",
"nl": "Telefoon",
"pl": "Telefon",
"ja": "電話番号",
"ko": "전화번호",
"zh": "电话"
},
"max": 50,
"placeholder": {
"en": "Country code and phone number",
"id": "Kode negara dan nomor telepon",
"tr": "Ülke kodu ve telefon numarası",
"de": "Ländervorwahl und Telefonnummer",
"es": "Código de país y teléfono",
"fr": "Indicatif du pays et numéro",
"pt": "Código do país e telefone",
"it": "Prefisso internazionale e numero",
"ar": "رمز الدولة ورقم الهاتف",
"ru": "Код страны и номер телефона",
"nl": "Landcode en telefoonnummer",
"pl": "Numer telefonu z kodem kraju",
"ja": "国番号と電話番号を入力してください",
"ko": "국가 코드와 전화번호를 입력하세요",
"zh": "请输入国家代码和电话号码"
},
"autocomplete": "tel"
},
"message": {
"type": "string",
"control": "textarea",
"required": true,
"label": {
"en": "Message",
"id": "Pesan",
"tr": "Mesaj",
"de": "Nachricht",
"es": "Mensaje",
"fr": "Message",
"pt": "Mensagem",
"it": "Messaggio",
"ar": "الرسالة",
"ru": "Сообщение",
"nl": "Bericht",
"pl": "Wiadomość",
"ja": "メッセージ",
"ko": "메시지",
"zh": "留言"
},
"max": 20000,
"placeholder": {
"en": "Describe your question or request",
"id": "Jelaskan pertanyaan atau permintaan Anda",
"tr": "Sorunuzu veya talebinizi açıklayın",
"de": "Beschreiben Sie Ihre Frage oder Anfrage",
"es": "Describe tu pregunta o solicitud",
"fr": "Décrivez votre question ou demande",
"pt": "Descreva sua dúvida ou solicitação",
"it": "Descrivi la tua domanda o richiesta",
"ar": "صف سؤالك أو طلبك",
"ru": "Опишите ваш вопрос или запрос",
"nl": "Beschrijf uw vraag of verzoek",
"pl": "Opisz swoje pytanie lub prośbę",
"ja": "ご質問やご要望を入力してください",
"ko": "질문이나 요청 내용을 설명하세요",
"zh": "请描述您的问题或需求"
}
}
},
"extensions": {
"presentation": [
"label",
"placeholder",
"help",
"order"
],
"field_types": [
"string",
"integer",
"boolean"
]
},
"workflow": {
"initial": "received",
"states": {
"received": {
"en": "Received",
"id": "Diterima",
"tr": "Alındı",
"de": "Eingegangen",
"es": "Recibido",
"fr": "Reçu",
"pt": "Recebido",
"it": "Ricevuto",
"ar": "تم الاستلام"
},
"in_progress": {
"en": "In progress",
"id": "Sedang diproses",
"tr": "İşlemde",
"de": "In Bearbeitung",
"es": "En curso",
"fr": "En cours",
"pt": "Em andamento",
"it": "In corso",
"ar": "قيد المعالجة"
},
"completed": {
"en": "Completed",
"id": "Selesai",
"tr": "Tamamlandı",
"de": "Abgeschlossen",
"es": "Completado",
"fr": "Terminé",
"pt": "Concluído",
"it": "Completato",
"ar": "مكتمل"
}
},
"transitions": {
"start": {
"from": [
"received"
],
"to": "in_progress",
"label": {
"en": "Start processing",
"id": "Mulai proses",
"tr": "İşleme al",
"de": "Bearbeitung starten",
"es": "Iniciar gestión",
"fr": "Commencer le traitement",
"pt": "Iniciar atendimento",
"it": "Avvia elaborazione",
"ar": "بدء المعالجة"
}
},
"complete": {
"from": [
"received",
"in_progress"
],
"to": "completed",
"label": {
"en": "Complete",
"id": "Selesaikan",
"tr": "Tamamla",
"de": "Abschließen",
"es": "Completar",
"fr": "Terminer",
"pt": "Concluir",
"it": "Completa",
"ar": "إكمال"
}
},
"reopen": {
"from": [
"completed"
],
"to": "received",
"label": {
"en": "Reopen",
"id": "Buka kembali",
"tr": "Yeniden aç",
"de": "Erneut öffnen",
"es": "Reabrir",
"fr": "Rouvrir",
"pt": "Reabrir",
"it": "Riapri",
"ar": "إعادة الفتح"
}
}
}
},
"processor": "submit.php"
}
}
},
"panel": {
"api": "2",
"entry": "submissions",
"pages": {
"submissions": {
"title": {
"en": "Contact",
"id": "Kontak",
"tr": "İletişim",
"de": "Kontakt",
"es": "Contacto",
"fr": "Contact",
"pt": "Contato",
"it": "Contatti",
"ar": "التواصل"
},
"permission": "view",
"view": "panel/submissions.json",
"actions": []
},
"submission": {
"title": {
"en": "Submission",
"id": "Kiriman",
"tr": "Form kaydı",
"de": "Einsendung",
"es": "Solicitud",
"fr": "Demande",
"pt": "Solicitação",
"it": "Richiesta",
"ar": "الطلب"
},
"permission": "view",
"view": "panel/submission.json",
"actions": []
}
},
"menu": [
{
"page": "submissions",
"label": {
"en": "Contact",
"id": "Kontak",
"tr": "İletişim",
"de": "Kontakt",
"es": "Contacto",
"fr": "Contact",
"pt": "Contato",
"it": "Contatti",
"ar": "التواصل"
},
"icon": "list",
"order": 100
}
],
"actions": []
}
}
Bertanda kemampuan
Nyatakan kemampuan yang dibutuhkan paket. Host memeriksa mereka sebelum memungkinkan setiap operasi.
frontend.renderfrontend.assetsform.injectform.validatepublic.endpointsite.settings.readsite.settings.writeverification.challengeverification.verifypanel.renderpanel.actionforms.submissions.createforms.submissions.readforms.submissions.manageforms.instances.readforms.instances.manage
Hooks dan kejadian lifecycle
Frontend kait
page.headpage.body.startpage.body.endform.startform.before_fieldsform.after_fieldsform.before_submitform.after_submitform.end
kait latar
form.before_validateform.validateform.after_validateform.before_processform.after_process
Peristiwa Lifecycle
installenabledisableuninstallupgrade
Validasi dan urutan pemrosesan
Formulir mesin memvalidasi penyewa, penempatan yang ditandatangani konteks, plugin / skema saat ini dan menyatakan jawaban sebelum verifikasi. Ini mengikat pemulihan bukti untuk percobaan dan muatan kanonikal. Setelah memeriksa ulang keadaan dan kuota, prosesor terbatas memiliki menyimpan melalui host API dalam satu transaksi isi dengan penerimaan percobaan, penggunaan perubahan dan tugas pemberitahuan. Identik mencoba mengembalikan tanda terima tanpa menyimpan lagi. Kiriman email terjadi setelahnya dan mungkin mencoba lagi; kegagalan surat tidak pernah menghapus pengiriman yang tersimpan.
Terbatas PHP waktu-jalan
eyivo-php-subset-1
Konteks dan hasil
Penangan menerima $konteks sebagai JSONData yang kompatibel: site _ id, site _ public _ id, plugin _ id, apl, konfigurasi, lokal dan halaman yang berlaku / form _ id / form _ type / action / action / fields / validation / validation _ state. Identitas silet selalu disediakan oleh host. Laut render kembalikan field html; validasi kait mengembalikan field yang valid boolee. Setiap kolom yang diperlukan harus berupa validator yang benar-benar dikembalikan. Laut lain mengembalikan sebuah larik.
API ijin dan jembatan
$pluginApi mengekspos get, post, put, patch dan delete dengan sebuah ID literal dan sebuah parameter array. Setiap operasi dicentang terhadap manifest, kapabilitas, request schema, skema respon dan plugin opsional pembatasan. URL yang hilang ditolak. Site dan lingkup plugin tidak dapat dioverride. Pengaturan operasi berbagi layanan aplikasi yang sama seperti layanan terotentikasi Internal API pengelolaan konfigurasi. Pengaturan menulis terbatas untuk penangan lifecycle yang berwenang dan pemilik-berwenang pengelolaan aksi panel. Loaders halaman, lihat aksi, titik-titik publik dan membuat kait tidak dapat mengubah konfigurasi instalasi.
Lihat batasan sintaks dan eksekusi yang didukung
{
"execution": "Interpreted PHP subset. Package code is never included, evaluated, or autoloaded by PHP.",
"statements": [
"local assignment",
"return array",
"if / else with braces"
],
"expressions": [
"single-quoted strings",
"integers",
"booleans",
"null",
"arrays",
"array lookup",
"concatenation",
"strict equality",
"strict inequality",
"boolean operators",
"null coalescing"
],
"functions": [
"trim",
"strtolower",
"strlen",
"count",
"htmlspecialchars"
],
"forbidden": [
"all undeclared functions",
"superglobals",
"objects and classes",
"dynamic calls",
"references",
"loops",
"includes",
"eval",
"filesystem access",
"network access",
"database access",
"environment access",
"configuration manipulation",
"deserialization"
],
"source_bytes": 32768,
"tokens": 4096,
"syntax_depth": 32,
"evaluation_steps": 4096,
"api_calls_per_handler": 16,
"handler_wall_seconds": 10,
"binary_expression_chain": 128,
"forms_per_page": 32,
"data_bytes": 131072
}
Aset dan titik akhir publik
Paket mendaftarkan berkas skrip lokal, gaya, dan gambar. Skrip / gaya dimuat sekali ketika plugin merender; hanya berkas yang terdaftar yang dilayani. Plugin inline HTML gunakan sebuah elemen / atribut allowlist. Kebijakan Keamanan Kontent. Hak akses skrip terdaftar untuk hashes dengan Subresource Integritas. Endpoints gunakan / _ ejivo / plugin / {namespace} / {name} / {endpoint}, eksplisit metode dan dideklarasikan ruas masukan. Resolusi tent, batas rate dan CSRF proteksi untuk metode tidak aman tetap host- dikendalikan. Plugin titik akhir tidak pernah menambahkan rute aplikasi sewenang-wenang.
Verifikasi Manusia
ejivo / human- verification dibutuhkan di setiap situs. Layanan bersama pada plugins.eyivo.com / verification menggunakan terenkripsi enam- digit PNG tantangan dengan kadaluwarsa 180detik. Identitas klien yang terpercaya, diberikan layanan dan IP sumber yang dimunculkan. Terdaftar bentuk UUID dan ID mencoba mengikat setiap tantangan; verifikasi juga mengikat muatan kanonikal. Percobaan yang diterima identik dapat memulihkan hasil mereka selama 24 jam, sehingga mempertahankan kunci-kunci sebelumnya untuk jendela itu plus marjin jam / jaringan. Tidak ada tanda-tanda akhir. Daftar basis data plugin bersama replay / rate-limit negara penerimaan, tidak pernah membentuk jawaban atau inbox database.
Aksesibilitas dan perilaku peramban
Kendali memiliki label terlokalisasi, bimbingan masukan, pengumuman status, dan sebuah tombol penyegaran gambar. JavaScript harus diaktifkan. Mode awal image- hanya mode ini tidak dapat diselesaikan oleh pengunjung tidak dapat melihat gambar; sebuah tantangan alternatif yang dapat diakses bukan bagian dari v1. Halaman berisi formulir yang didukung bypass terbagi HTML caching. Pratilik tema menjaga kebijakan no- script mereka dan tidak dapat mengirimkan tantangan kerja.
Terekspose API operasi
Gunakan operasi ID ini melalui $pluginApi. Setiap entri di bawah ini berasal dari manifes eksposur yang sama yang digunakan untuk memaksakan perizinan waktu-jalan.
site.settings.read
Read the current plugin's namespaced site configuration.
site.settings.read
$pluginApi->get('site.settings.read', []);
Tilik parameter, respon, dan pembatasan
{
"parameters": [],
"response": {
"configuration": {
"type": "object"
}
},
"restricted_to_plugins": null,
"deprecated": false
}
site.settings.update
Replace the current plugin's configuration using its declared schema.
site.settings.write
$pluginApi->put('site.settings.update', ['configuration' => []]);
Tilik parameter, respon, dan pembatasan
{
"parameters": {
"configuration": {
"type": "object",
"required": true
}
},
"response": {
"configuration": {
"type": "object"
}
},
"restricted_to_plugins": null,
"deprecated": false
}
form.verification.widget
Render a localized verification control for a supported form.
form.inject
$pluginApi->get('form.verification.widget', []);
Tilik parameter, respon, dan pembatasan
{
"parameters": [],
"response": {
"html": {
"type": "string",
"max": 16384
}
},
"restricted_to_plugins": [
"eyivo/human-verification"
],
"deprecated": false
}
form.verification.challenge
Request a numeric image challenge bound to the current site and form.
verification.challenge
$pluginApi->get('form.verification.challenge', []);
Tilik parameter, respon, dan pembatasan
{
"parameters": [],
"response": {
"token": {
"type": "string",
"max": 4096
},
"image": {
"type": "string",
"max": 65536
},
"expires_in": {
"type": "integer"
}
},
"restricted_to_plugins": [
"eyivo/human-verification"
],
"deprecated": false
}
form.verification.verify
Consume a proof once. Rejection never allows form processing.
verification.verify
$pluginApi->post('form.verification.verify', ['token' => $context['fields']['verification_token'], 'answer' => $context['fields']['verification_answer']]);
Tilik parameter, respon, dan pembatasan
{
"parameters": {
"token": {
"type": "string",
"required": true,
"max": 4096
},
"answer": {
"type": "string",
"required": true,
"max": 12
}
},
"response": {
"valid": {
"type": "boolean"
}
},
"restricted_to_plugins": [
"eyivo/human-verification"
],
"deprecated": false
}
forms.submissions.create
Persist only the host-validated and verified attempt supplied out-of-band to the owning processor; accepts no answers or ownership override.
forms.submissions.create
$pluginApi->post('forms.submissions.create', []);
Tilik parameter, respon, dan pembatasan
{
"parameters": [],
"response": {
"result": {
"type": "object"
}
},
"restricted_to_plugins": null,
"deprecated": false
}
forms.submissions.list
Read paginated submission summaries for the current site and plugin in an authenticated panel context.
forms.submissions.read
$pluginApi->get('forms.submissions.list', []);
Tilik parameter, respon, dan pembatasan
{
"parameters": {
"form_type": {
"type": "string",
"max": 64
},
"form_id": {
"type": "string",
"max": 36
},
"cursor": {
"type": "string",
"max": 1024
},
"per_page": {
"type": "integer",
"min": 1,
"max": 25
},
"read": {
"type": "boolean"
},
"archived": {
"type": "boolean"
},
"workflow_state": {
"type": "string",
"max": 64
},
"from": {
"type": "string",
"max": 10
},
"to": {
"type": "string",
"max": 10
}
},
"response": {
"result": {
"type": "object"
}
},
"restricted_to_plugins": null,
"deprecated": false
}
forms.submissions.read
Read a historical submission snapshot owned by the current site and plugin.
forms.submissions.read
$pluginApi->get('forms.submissions.read', []);
Tilik parameter, respon, dan pembatasan
{
"parameters": {
"submission_id": {
"type": "string",
"max": 36,
"required": true
}
},
"response": {
"result": {
"type": "object"
}
},
"restricted_to_plugins": null,
"deprecated": false
}
forms.submissions.update
Apply authorized reading/archive changes or a declared workflow transition using the current record revision.
forms.submissions.manage
$pluginApi->patch('forms.submissions.update', []);
Tilik parameter, respon, dan pembatasan
{
"parameters": {
"submission_id": {
"type": "string",
"max": 36,
"required": true
},
"record_revision": {
"type": "integer",
"min": 1,
"required": true
},
"read": {
"type": "boolean"
},
"archived": {
"type": "boolean"
},
"transition": {
"type": "string",
"max": 64
}
},
"response": {
"result": {
"type": "object"
}
},
"restricted_to_plugins": null,
"deprecated": false
}
forms.submissions.delete
Explicitly delete an owned submission, cancel pending notifications and release its stored byte charge; preserve technical replay protection.
forms.submissions.manage
$pluginApi->delete('forms.submissions.delete', []);
Tilik parameter, respon, dan pembatasan
{
"parameters": {
"submission_id": {
"type": "string",
"max": 36,
"required": true
},
"record_revision": {
"type": "integer",
"min": 1,
"required": true
}
},
"response": {
"result": {
"type": "object"
}
},
"restricted_to_plugins": null,
"deprecated": false
}
forms.instances.list
Read cursor-paginated compact form summaries belonging to the current site and plugin; settings are not included.
forms.instances.read
$pluginApi->get('forms.instances.list', []);
Tilik parameter, respon, dan pembatasan
{
"parameters": {
"form_type": {
"type": "string",
"max": 64
},
"cursor": {
"type": "string",
"max": 1024
},
"per_page": {
"type": "integer",
"min": 1,
"max": 25
},
"q": {
"type": "string",
"max": 160
}
},
"response": {
"result": {
"type": "object"
}
},
"restricted_to_plugins": null,
"deprecated": false
}
forms.instances.create
Create a separate named form instance with an automatically generated UUID.
forms.instances.manage
$pluginApi->post('forms.instances.create', []);
Tilik parameter, respon, dan pembatasan
{
"parameters": {
"form_type": {
"type": "string",
"max": 64,
"required": true
},
"name": {
"type": "string",
"max": 160,
"required": true
}
},
"response": {
"result": {
"type": "object"
}
},
"restricted_to_plugins": null,
"deprecated": false
}
forms.instances.update
Update a current form instance name or schema-compatible settings under owner/manage authorization and record revision.
forms.instances.manage
$pluginApi->patch('forms.instances.update', []);
Tilik parameter, respon, dan pembatasan
{
"parameters": {
"form_id": {
"type": "string",
"max": 36,
"required": true
},
"record_revision": {
"type": "integer",
"min": 1,
"required": true
},
"name": {
"type": "string",
"max": 160
},
"settings": {
"type": "object"
}
},
"response": {
"result": {
"type": "object"
}
},
"restricted_to_plugins": null,
"deprecated": false
}
Kompatibilitas dan penyebaran
Pengaya API 1 Dukungan Bentuk API 1 dan Panel API 1 / 2. Paket formulir membutuhkan Panel API 2 daftar / detail halaman dan deklarasi menu. Kontrak yang tidak didukung dan sintaks tidak aman ditolak. Menyebarkan layanan penerimaan verifikasi pertama, kemudian master / contention migrations, plugin rekonsiliasi, migrasi warisan dan akuntansi penggunaan; sebarkan perender aplikasi yang kompatibel dan acuan Apex sesudahnya. Pertahankan riwayat dan kunci lama selama rollback. Semua mengirimkan tema menggunakan bentuk yang terdaftar; kontak warisan POSTs kembali 410. Pemaparan barang nyata ini dan izin waktu.