فهرست مستندات
مرجع مانیفست#
چهار فایل، پروژهها و اتصال محلی Al-Amr را تعریف میکنند:
al-amr.environment.jsonبازنگری یک Environment، ورودی bundle، قابلیتها و Pluginهای دقیق نصبشده را مشخص میکند.al-amr.app.jsonورودی bundle تغییرناپذیر App، دسترسی، نمایش، قابلیتهای نسخهدار، اعلانها، سازگاری و مستندات را شرح میدهد.al-amr.plugin.jsonانتشار Plugin، آداپتورها، مشخصات اختیاری بکاند، طرحوارهٔ تنظیمات، مجوزها، افشاها، سازگاری، مستندات، مخزن و مجوز نرمافزار را شرح میدهد.al-amr.lock.jsonشناسهٔ دقیق انتشار Registry، مشخصات پکیج و مقدار یکپارچگی SHA-512 انتخابشده توسط CLI را ثبت میکند.
مرزهای مانیفست#
وضعیت انتشار و بازبینی، اعتماد، endpoint زنده، secret، رابط دلخواه تنظیمات و فرمان نصب دستی در مانیفست Plugin قرار نمیگیرند؛ این موارد وضعیت Registry یا دادهٔ استقرارند.
EnvironmentEntrySchema یک union سختگیرانه است. محصولهای فعلی دسکتاپ v0.1
از ورودی bundle مانند {"kind":"bundle","version":"0.1.0"} استفاده میکنند؛
minClient تنها فیلد اختیاری entry است. Shell، origin مربوط به bundle را
میسازد و ارائه میکند، پس مانیفست آن را اعلام نمیکند.
عضو سختگیرانهٔ web قدیمی برای سازگاری parse با مقدارهای تاریخی
{"kind":"web","url":"https://example.com"} باقی مانده است؛ kind فقط در
همین شکل قدیمی میتواند حذف شود. URL آن در production به HTTPS نیاز دارد، HTTP
ساده را فقط روی میزبان loopback میپذیرد و credential و fragment را رد میکند.
parse عضو web قدیمی مسیر فعلی ساخت یا انتشار Environment نیست. هیچیک از دو عضو
entry فیلد callback مجوز، callback خروج یا runtime بومی ندارد. Shell دسکتاپ
client مربوط به OAuth و مالک آن جریانهاست.
رندرینگ Environment وضعیت مانیفست نیست#
مانیفست Environment قرارداد عمومی میزبان را توصیف میکند، نه موتور پیادهسازی
آن را. یک Environment میتواند از DOM، Canvas 2D، WebGL، WebGPU، WASM یا هر
موتور وب استفاده کند. عمداً هیچ فیلد عمومی engine، renderer یا
threeVersion وجود ندارد و Registry نیز هیچکدام را استنتاج نمیکند.
نمایهٔ رسمی و اختیاری نویسندگی R3F/WebGPU فقط با metadata محلی package انتخاب
میشود: یک package وقتی عضو نمایه است که نام خودش @al-amr/r3f یا
@react-three/fiber باشد، یا یکی از این markerها را در هر بخش dependency اعلام
کند. این انتخاب محدودهٔ سیاست محلی renderer و conformance افزودهٔ نمایهٔ R3F
را تعیین میکند. conformance عمومی Environment خنثی نسبت به موتور میماند و
هیچیک از دو مسیر conformance مانیفست wire را تغییر نمیدهد.
منبع رسانهٔ نمایشی الزامی#
revision تازهٔ App به presentation.iconUrl نسبی به bundle نیاز دارد. revision
تازهٔ Environment نیز باید portal.art.imageUrl و portal.art.alt غیرخالی
داشته باشد. scaffold در CLI فایلهای متناظر public/app-icon.png و
public/environment-cover.jpg را میسازد تا manifest اولیه به asset واقعی اشاره
کند:
{
"presentation": {
"title": "Metronome",
"iconUrl": "app-icon.png",
"mark": "clock"
}
}
{
"portal": {
"title": "Photography gallery",
"blurb": "A quiet gallery for curated photography.",
"art": {
"imageUrl": "environment-cover.jpg",
"alt": "Sunlit rooms in the photography gallery"
},
"visibility": "public"
}
}
برای App و Environment نوع bundle فعلی، رسانهٔ نمایشی مسیر نرمالشدهٔ نسبی به
bundle است و درون archive بازبینیشده جابهجا میشود. Environment
نوع web قدیمی در عوض از URL منبع absolute و همorigin با entry استفاده میکند.
Registry فقط raster محدود PNG یا JPEG را میپذیرد، metadata تأییدنشده را حذف
میکند و نتیجهٔ متصل به revision را از مسیر رسانهٔ content-addressed خودش ارائه
میدهد. کلاینت کاتالوگ و Widget، cardIcon یا cardCover را رندر میکند و هرگز
منبع ناشر را fetch نمیکند. manifest تاریخی بدون این فیلدها همچنان خواندنی است،
اما ورودی تازهٔ معتبر نیست.
اعلان بکاند متعلق به Environment#
یک بازنگری Environment میتواند یک شیء backend اعلام کند. این شیء مرز اختیار
دادهٔ دامنهای متعلق به ناشر است، نه رکورد استقرار Plugin:
{
"backend": {
"audience": "envb_conference_hall",
"endpointUrl": "https://conference.example.com/api",
"healthUrl": "https://conference.example.com/ready",
"grantScopes": ["conference:session", "conference:events:read"],
"contextSchema": {
"type": "object",
"properties": {
"purpose": { "type": "string", "maxLength": 40 }
},
"required": ["purpose"],
"additionalProperties": false
},
"dataDisclosures": ["Environment-pairwise actor identity"]
}
}
endpoint و health باید origin یکسان داشته باشند و production به HTTPS نیاز دارد. scope و context بسته، محدود و تغییرناپذیرند. رکوردها و نقشهای دامنهای Environment در همین بکاند میمانند، نه در metadata کاتالوگ Registry.
بومیسازی تغییرناپذیر کاتالوگ#
مانیفست Environment، App و Plugin میتواند map محدود localizations داشته
باشد. کلید یک برچسب زبان نرمال مانند fa، fa-IR یا zh-Hans-CN است. مقدار
فقط متن نمایشی عمومی و بازبینیشده را جایگزین میکند:
{
"localizations": {
"fa": {
"name": "سالن کنفرانس",
"shortDescription": "فضای کمحجم برای همایشهای زنده",
"category": "رویدادها"
}
}
}
Environment میتواند portal.title، portal.blurb و portal.artAlt و App
میتواند presentation.title را نیز بومی کند. این map شناسه، ناشر، handle،
نسخه، شیوهٔ تحویل entry، مجوز، سازگاری، اعتماد یا اختیار را تغییر نمیدهد و بخشی از
digest و بازبینی snapshot تغییرناپذیر است. رابط فارسی بهترتیب fa-IR، fa،
یک مقدار دیگر fa-* و در پایان متن پایه را انتخاب میکند. نبود ترجمه fallback
معتبر است و Portal نباید ترجمهٔ mutable جداگانه بسازد.
هر آداپتور frontend یک شناسهٔ پایدار، runtime میزبان، مسیر export پکیج،
فهرستی کراندار با حداکثر ۲۰۰ exports بازبینیشدهٔ runtime و ساختاری
TypeScript، قابلیتها و سازگاری همتا را اعلام میکند. اعتبارسنجی artifact پیش
از انتشار ثابت میکند هر binding نامبرده در declaration بازبینیشدهٔ
TypeScript وجود دارد. entrypoint باید فهرست export صریح و curated داشته باشد
تا wildcard re-export نتواند API عمومی بازبینیشده را بیصدا گسترش دهد.
آداپتورهای شرکتکننده در composition رابط میزبان bindingهای اختیاری
composition.provides و composition.contributes را اعلام میکنند. هر binding
سطحی معنایی مانند avatar.overhead، یک exportName موجود در exports و شرحی
محدود دارد. provider مالک هندسه و معنای سطح، contributor مالک محتوای قابل
استفادهٔ مجدد و Environment مالک ترتیب و mount است. برای نمونه Player Rig خروجی
PlayerAvatarOverlay را برای avatar.overhead و Media اکشن تماس را به همان سطح
اعلام میکند. Environment provider را داخل آواتار متناظر قرار میدهد و anchor
یا projection را از مختصات تکثیرشده بازسازی نمیکند. Plugin برای تزریق UI،
Plugin دیگری را import نمیکند. این bindingها باید در manifest.json
تغییرناپذیر، integration.md تولیدشده، types.d.ts بازبینیشده و صفحهٔ نسخهٔ
Developer Portal همخوان باشند.
طرحوارهٔ تنظیمات Plugin#
تنظیمات از طرحوارهای اعلانی و محدود استفاده میکنند. سطح اول و objectها حداکثر ۶۴ property، stringها حداکثر مؤثر ۴۰۹۶ نویسه و گزینههای enum همان محدودیت طول و pattern مقادیر ذخیرهشده را دارند. patternها از زیرمجموعهٔ امن، کراندار و anchorشده استفاده میکنند؛ گروه، alternation، backreference، wildcard و تکرار نامحدود پیش از انتشار رد میشود.
پیکربندی نصب Environment#
environmentConfig روی نصب Plugin، سیاست تغییرناپذیر میزبان است نه preference
کاربر. Plugin دارای پیکربندی غیرخالی یا پیچیده، environmentConfigSchema را با
همان زیرمجموعهٔ بسته و محدود JSON Schema اعلام میکند. Registry هر draft را
در برابر release دقیق نصبشده میسنجد و مقدار تأییدشده بعداً در Plugin Grant
امضا میشود. Plugin بدون این اعلان، مسیر سازگاری تنظیمات را نگه میدارد و نباید
از آن برای آرایه یا توپولوژی عملیاتی اتاق استفاده کند.
بافتار مجوز بکاند#
contextSchema از زیرمجموعهٔ سختگیرانه و محدود JSON Schema استفاده میکند که
دقیقاً با enforce شدن در Registry یکسان است. objectها با
additionalProperties: false بسته میشوند؛ هر نام required باید در
properties وجود داشته باشد؛ string و array بهترتیب maxLength و maxItems
دارند؛ و عمق، تعداد node و property و اندازهٔ enum محدود است. pattern باید آغاز
و پایان مشخص داشته باشد و گروه، alternation، backreference، wildcard یا تکرار
نامحدود نداشته باشد. keyword پشتیبانینشده هنگام اعتبارسنجی مانیفست رد میشود.
بازنگری Environment و App و releaseهای Plugin پس از انتشار تغییرناپذیرند؛ هر ویرایش snapshot پیشنویس تازهای میسازد. Registry پیش از انتشار App، archive اعتبارسنجیشده، سند ورودی، فهرست فایلها و digest را به revision متصل میکند. مانیفست App هیچ credential مربوط به Environment Runtime، secret بکاند یا شناسهٔ خام و پایدار کاربر ندارد.
نمایش، قابلیت و اعلان اپ#
هر اپ Compact دارد. Workspace اختیاری است و preferred mode باید در مجموعهٔ اعلامشده باشد:
{
"display": {
"modes": ["compact", "workspace"],
"preferredMode": "workspace",
"background": "persistent"
},
"presentation": { "title": "Metronome", "mark": "clock" }
}
Compact سطح محصول با عرض موبایل و Workspace سطح بزرگ دسکتاپ با inset صحنه است، نه fullscreen. هر دو همان سند را در AppHost دسکتاپ استفاده میکنند و تغییر حالت سند یا نشست تازه نمیسازد — presentation را درجا بهروز میکند، پس state حافظه حفظ میشود.
display.background پیشفرض "none" دارد: بستن پنل یا بازگشت، نمای محصول و
نشستش را نابود میکند. "persistent" از پلتفرم میخواهد سند را
وقتی اپ روی صفحه نیست زنده نگه دارد، برای اپهایی که اجرا میشوند نه اینکه نمایش
بدهند. بستن خود اپ همچنان به آن پایان میدهد. حداکثر سه اپ همزمان اجرا میشوند.
presentation.mark نشانی را نام میبرد که یک اپ در حال اجرا روی لانچر میپوشد، از
مجموعهای بسته که خود پلتفرم میکشد: note، sound، clock، calendar،
chart، map، message، spark، cube، tag، grid. پیشفرضش grid است.
presentation.iconUrl برای نشان اپ در حال اجرا استفاده نمیشود و هرگز داخل
سند یک محیط بار نمیشود. Registry آن را هنگام انتشار ingest میکند؛ کارت کاتالوگ
App فقط cardIcon حاصل و متعلق به Registry را رندر میکند.
قابلیتها درخواستهای بسته و نسخهبندیشدهاند:
{
"capabilities": {
"required": [
{
"id": "platform.environment.identity.read@1",
"versionRange": "^1.0.0"
},
{
"id": "host.spatial.context.read@1",
"versionRange": "^1.0.0"
}
],
"optional": []
}
}
رجیستری شناسهٔ ناشناخته، range ناسازگار، وابستگی ناقص و درخواست تکراری را رد میکند. وابستگی required نیز باید required باشد. درخواست immutable به معنی grant نیست؛ انتشار، Runtime، پشتیبانی محیط و رضایت در هر اجرا ارزیابی میشوند.
اپ واژگان رخداد و مدل background را هم اعلام میکند:
{
"notifications": {
"eventTypes": [
{
"type": "task.completed",
"label": "Task completed",
"policy": {
"family": "generic",
"subject": {
"mode": "per_occurrence",
"revision": "event_identity"
},
"effects": ["raise"],
"preferenceKey": "task.completed",
"pulse": "none",
"presentation": { "kind": "source" }
}
}
],
"backgroundDelivery": "delegated"
}
}
نویسندهٔ جدید Occurrence برای App باید policy تغییرناپذیر و بازبینیشدهٔ بالا
را اعلام کند: family بسته، هویت Subject و منبع revision، effectهای مجاز، کلید
پایدار ترجیح، policy مربوط به Pulse و مالک presentation. هیچکدام از این
انتخابهای policy داخل signal رخداد سفر نمیکند. declaration بدون policy فقط
برای caller تغییرناپذیرِ API additive و legacy publish خواندنی میماند.
رخداد غیرخالی به platform.notifications.publish.self@1 نیاز دارد. مدل
delegated علاوه بر آن
platform.notifications.connect.background.self@1 را میخواهد که dependency
آن همان grant انتشار است. endpoint، token، user ID، ظاهر mutable، HTML یا URL
دلخواه action در مانیفست نیست. قواعد Subject کلیددار و per-occurrence در
اعلانهای پلتفرم آمده است.
اعلام مکانی و اعلان محیط#
محیط دارای Host Services مکانی، vocabulary و سرویس را با هم اعلام میکند:
{
"spatial": {
"semanticLocations": [
{
"locationId": "stage",
"label": "Main stage",
"navigationPolicy": "confirm"
}
]
},
"hostServices": {
"protocolVersion": "1.0.0",
"provides": [
"host.spatial.context@1",
"host.spatial.locations@1",
"host.spatial.capture@1",
"host.spatial.navigation@1"
]
},
"notifications": {
"eventTypes": [{ "type": "event.starting", "label": "Event starting" }]
}
}
شناسهٔ موقعیت، معنای پایدار و متعلق به محیط است، نه route یا coordinate؛ و تنها
واژگان مکانی است که رجیستری نگه میدارد، چون فقط یک موقعیتِ اعلامشده را میشود
از بیرون نشانه گرفت. زون اینجا اعلام نمیشود: زون واقعیتی در زمان اجراست که
محیط همانجا گزارش میکند، ممکن است اصلاً وجود نداشته باشد، و هیچ چیز بیرون از
محیط نمیتواند به آن آدرس بدهد. شناسهها و eventها یکتا و محدودند. محیط بدون این
قابلیتها هر سه object را حذف میکند؛ spatial و hostServices در صورت استفاده
باید با هم باشند.
alamr validate --json
CLI با همان طرحوارههای قرارداد 0.1.0-alpha.1 مورد استفادهٔ Registry
اعتبارسنجی میکند.