فهرست مستندات
اپها#
اپ (App) محصولی کاربرمحور است که مستقل ساخته و بهصورت باندل تغییرناپذیر
تحویل میشود. AppHost دسکتاپ آن را از Home یا هنگام فعال بودن Environment باز
میکند:
| واحد | نقش محصولی | مرز اجرا |
|---|---|---|
| محیط | مقصدی که کاربر وارد آن میشود | نمای باندل ایزوله، Runtime، صحنه و ترکیببندی خودش |
| اپ | محصول کاربرمحور قابلحمل | باندل دقیق منتشرشده در نمای محصول متعلق به دسکتاپ |
| پلاگین | قابلیتی که محیط نصب میکند | در v0.x کتابخانهٔ مورداعتماد داخل میزبان |
اپ «پلاگین دارای صفحه» نیست. پلاگین محیط را توسعه میدهد؛ اپ محصول، چرخهٔ داده، مبدأ مشتقشده، بکاند اختیاری و تاریخ انتشار تغییرناپذیر خودش را دارد. بازکردن اپ نه ورود به محیط تازه است و نه Presence تازه میسازد.
یک میزبان ویجت و دو حالت نمایش#
هر اپ باید در Compact کامل کار کند. Compact همان سطح باریک فعلی ویجت و از نظر طراحی یک محصول موبایلی است. اپ میتواند Workspace را هم اعلام کند؛ سطحی عریض برای کار دسکتاپی.
Workspace fullscreen مرورگر نیست. همان ویجت در viewport دسکتاپ بزرگ میشود، فاصلهٔ طراحیشده از لبهها را نگه میدارد، بخشی از صحنهٔ سهبعدی باقی میماند و chrome پلتفرم را حفظ میکند. در viewport کوچک Compact fallback همگانی است.
{
"display": {
"modes": ["compact", "workspace"],
"preferredMode": "workspace"
}
}
preferredMode حالت اولین اجرا روی دسکتاپ را تعیین میکند. اپ Compact-only
فقط ["compact"] دارد و کنترل بزرگکردن نمیبیند.
هر دو حالت یک revision و سند دارند. نشست متصلشده displayMode را گزارش
میکند. تغییر حالت presentation میزبان را درجا بهروز میکند؛ به تغییرهای
presentation subscribe کنید و reload یا نشست تازه فرض نکنید. state ماندگار
همچنان در بکاند است، چون close، update، recovery یا sign-out سند را پایان میدهد.
Header، کنترل حالت، close/back، انیمیشن، focus، input capture، inset و سیاست نمای محصول در مالکیت پلتفرم است. محتوای اپ در اندازهٔ نهایی reveal میشود و scale نمیشود. اپ ویجت دیگری mount نمیکند و به اندازه یا DOM داخلی ویجت تکیه ندارد.
دسترسی و اجرا#
Registry revisionهای دقیق در دسترس را برمیگرداند. دیدهشدن محصول با مجوز اجرا فرق دارد و هر launch به sign-in نیاز دارد. launch از Home بهصورت platform-hosted است؛ launch هنگام فعال بودن دنیا میتواند environment-hosted باشد.
پلتفرم پیش از mount نمای App درخواست capability تغییرناپذیر را ارزیابی میکند، افشای required/optional را توضیح میدهد و رضایت را ثبت میکند. نبود required جلوی اجرا را میگیرد؛ نبود optional باید تجربهای کاهشیافته ولی سالم بسازد.
دسکتاپ باندل اعتبارسنجیشده را روی alamr-app://<appId>/ در partition اختصاصی
میزبانی میکند. اپ PKCE verifier را میسازد و فقط challenge را از راه
window.alamr میفرستد. Registry کد یکبارمصرف متصل به revision، nonce، digest
قابلیتها و نسل میزبان میسازد. launch محیطمحور lease فعال والد را هم bind
میکند؛ launch پلتفرممحور والد و قابلیت Environment-scoped ندارد. اپ کد را با
نشست کوتاهعمر و memory-only عوض میکند.
اپ Runtime token، refresh token، raw account subject یا Plugin Grant محیط را
نمیگیرد. aact_* یک subject جفتی است که برای همان حساب و اپ میان محیطها
پایدار میماند. پروفایل و هویت محیط فقط با قابلیت واقعاً grantشده افشا میشوند.
Host Services#
پل تزریقشدهٔ window.alamr کانال strict و نسخهبندیشده و تنها پل
پشتیبانیشده میان اپ، پلتفرم و محیط است. اپ کد محیط را import، صحنه را inspect
یا Plugin API را invoke نمیکند.
کاتالوگ اولیه:
| قابلیت | اجازه |
|---|---|
platform.identity.profile.read@1 | خواندن پروفایل حساب مجازشده |
platform.environment.identity.read@1 | خواندن هویت امضاشدهٔ محیط فعال |
host.spatial.context.read@1 | محیط، visit، زون و موقعیت معنایی فعلی |
host.spatial.locations.read@1 | فهرست موقعیتهای پایدار محیط |
host.spatial.location.capture@1 | گرفتن مرجع محدود و opaque برای جای فعلی |
host.spatial.navigation.request@1 | درخواست حرکت با assess/commit |
platform.notifications.publish.self@1 | اعلان برای principal فعلی اپ |
platform.notifications.connect.background.self@1 | واگذاری اعلان پسزمینه به بکاند اپ |
platform.companions.list@1 | خواندنهای بعدی نام، چهره و شناسهٔ ناشناسِ مخصوص اپ تا زمان قطع؛ بدون موقعیت |
platform.companions.offer@1 | پیشنهاد دادن به یکی از همراهان، بدون شناختن او |
platform.notify.companion@1 | اعلان پلتفرمیِ بدون محتوای اپ برای یک همراه |
platform.call@1 | زنگ زدن به یک همراه از طرف شخص، و رساندن زنگ آن همراه به او |
platform.media.microphone@1 | درخواست ورودی میکروفن در قاب مجاز همان اپ |
platform.presence.roster.read@1 | شمار حاضران این دنیا، و نه اینکه چه کسانی |
قابلیتها بسته و نسخهبندیشدهاند. اعلام permission نه sandbox جاوااسکریپت است و نه grant. رجیستری انتشار، سازگاری، وابستگی، principal، رضایت و Runtime را بررسی میکند و اپ grant واقعی نشست را میخواند.
هویت مکانی متعلق به محیط است. محیط برای مقصدهای عمومی شناسههای پایدار زون و موقعیت را اعلام میکند، در حالی که اپ میتواند برای هر نقطهٔ معتبر locator محدود و متصل به نسخه ذخیره کند. اپ locator را مانند مختصات قابلحمل جهان تفسیر نمیکند. Navigation درخواست به محیط است و ممکن است تأیید پلتفرم بخواهد؛ اپ مستقیم player یا camera را جابهجا نمیکند.
برای قرارداد و نمونهٔ کد سرویسهای میزبان اپ را بخوانید.
Lifecycle#
اپ میتواند handler استاندارد app.lifecycle.beforeExit را از SDK ثبت کند.
پیش از close یا replace صریح و مخرب فراخوانی میشود. تغییر حالت فقط presentation
است و جابهجایی دسکتاپ میان دو Environment سند را نگه میدارد و اختیار Runtime
را جایگزین میکند. اپ allow برمیگرداند یا یک تأیید متعلق به پلتفرم میخواهد.
deadline یک ثانیه است و پاسخ دیررس، خراب یا خطادار نمیتواند کاربر را محبوس کند. Close یا replace، نمای محصول را نابود میکند.
اپهایی که دیده نمیشوند و همچنان اجرا میشوند#
بهصورت پیشفرض، کنار گذاشتن اپ به آن پایان میدهد: بستن پنل یا بازگشت، نمای محصول و نشستش را نابود میکند. اپی که باید از این جان به در ببرد، آن را اعلام میکند.
"display": { "modes": ["compact"], "preferredMode": "compact", "background": "persistent" }
background پیشفرض "none" دارد، پس اپی که چیزی نگوید دقیقاً مثل همیشه رفتار
میکند. "persistent" را وقتی اعلام کن که اپ تو اجرا میشود، نه اینکه فقط
نمایش میدهد — تایمری که باید بشمارد، صفی که باید پخش شود. بستن خود اپ همچنان به
آن پایان میدهد؛ فقط بستن پنل دیگر چنین نمیکند.
حداکثر سه اپ همزمان اجرا میشوند. این عدد از جا گرفتن نشانها کنار لانچر میآید، نه از یک محدودیت امنیتی، و روی نمایشگر کوچک و دستگاه کمحافظه به دو کاهش مییابد.
پلتفرم چه قول میدهد و چه قولی نمیدهد. قول میدهد سند زنده بماند و رشتهٔ صدا اجرا شود. قول نمیدهد کد تو سر وقت اجرا شود. نمای محصول پنهان یا سیستمعاملی که کلاینت دسکتاپ را suspend کند ممکن است تایمرها را کم یا متوقف کند. پس:
- یک لحظهٔ مطلق ذخیره کن و از روی ساعت رندر کن. تایمری که tick میشمارد دریفت
میکند؛ تایمری که
endsAt - Date.now()را حساب میکند نمیتواند. - به presentation مشترک شو.
state: "background"یعنی در حال اجرا و بیرون از صفحه — رسم را متوقف کن، پخش را ادامه بده.atساعت دیواری میزبان است، پس مقایسهاش با ساعت خودت هم فاصلهٔ طولانی را نشان میدهد هم انحراف ساعت دستگاه. - تا وقتی صدا تولید میکنی
setAudible(true)را صدا بزن. پلتفرم از همین راه میفهمد که باید روی لانچر نشانه بگذارد و تو را در انتهای صف قرار دهد وقتی مجبور است بپرسد کدام اپ بسته شود. این یک اطلاع است، نه یک مجوز: اعلام سکوت هنگام پخش چیزی را پنهان نمیکند، فقط به آدم کمتر میگوید.
تحویل پسزمینه چیز دیگری است. notifications.backgroundDelivery تعیین میکند
که آیا پلتفرم اجازه دارد وقتی آدم اصلاً نزدیک اپ تو نیست اعلانی برایش تحویل دهد.
display.background تعیین میکند که آیا سند خود اپ تو داخل همین بازدید زنده
میماند. هیچکدام دیگری را نتیجه نمیدهد.
نشستها تمدید میشوند و شناسهٔ نشست جابهجا میشود. نشست اپ پنج دقیقه عمر
دارد و پیش از انقضا دوباره صادر میشود؛ ساعت دست میزبان است و رمزنگاری کار اپ
توست، و همهاش داخل SDK انجام میشود. هر تمدید یک launch تازه است، پس session.id
عوض میشود. دادهٔ ذخیرهشده را روی session.appActorSub کلید بزن، که تا وقتی
آدم و اپ همان دو طرف باشند پایدار میماند.
تمدید همان چیزی است که اپ پسزمینه را محدود میکند: هر بررسیای که روی launch اول اجرا میشود دوباره اجرا میشود، پس قابلیتی که آدم پس بگیرد ظرف یک دورهٔ تمدید — کمتر از ۱۸۰ ثانیه — از کار میافتد، و حساب لغوشده یا خروج از حساب، اپ را ظرف همان ۳۰۰ ثانیهٔ خود توکن تمام میکند.
Escape داخل نمای App درخواست close را منتقل میکند و تصمیم نهایی،
focus و pointer lock در مالکیت میزبان است.
اعلانها#
Registry مالک projection ماندگار News است و محصول منبع همچنان history خودش را authoritative نگه میدارد. App جدید policy رخداد بازبینیشده را اعلام و یک Occurrence تغییرناپذیر signal میکند؛ Registry بدون اینکه caller صدا، treatment یا وضعیت recipient را انتخاب کند، آن را روی Subject کلیددار یا per-occurrence reduce میکند:
- App باز از نشست App signal میکند؛
- Environment فعال از نشست Runtime منتشر میکند؛
- بکاند محیط Grant کوتاهعمر و متصل به endpoint میگیرد؛
- بکاند اپ Project token محدود را با delegation opaque و مخصوص کاربر ترکیب میکند و outbox ماندگار منبع دارد.
App بدون بکاند تا وقتی frontend مجازش فعال است signal میفرستد. تحویل آفلاین، زمانبندیشده یا server-originated به مدل backend اپ نیاز دارد. Environment فعال و backend آن تا وقتی برای این authority plane یک API صریح Occurrence اضافه نشده، از routeهای additive و legacy publish استفاده میکنند.
manifest تغییرناپذیر App، family، حالت Subject، vocabulary مربوط به effect، هویت preference، policy مربوط به Pulse و presentation منبع یا template پلتفرم را ثابت میکند. محتوای source-authored plain text محدود میماند و فقط میتواند بازشدن App خودش را بخواهد. template پلتفرم فقط data shape بازبینیشدهٔ خودش را میپذیرد. URL دلخواه، HTML، script، callback خصوصی Widget و raw user ID ممنوع است. publish قدیمی برای caller تغییرناپذیر باقی میماند، اما ordering مربوط به Subject، watermark acknowledgement یا اختیار Pulse بهدست نمیآورد.
قواعد Occurrence، acknowledgement، delegation، reader و revocation در اعلانهای پلتفرم آمده است.
داده و مرز بکاند#
state ماندگار اپ در بکاند خود اپ و با subject جفتی تأییدشده کلید میخورد. فضای ذخیرهٔ partition محصول فقط cache است؛ هویت portable یا اختیار ماندگار بکاند نیست.
برای فراخوانی بکاند از client.authorizationHeader() استفاده کنید. بکاند با
@al-amr/backend نشست را introspect میکند و با غیرفعالشدن lease والد fail
closed میشود. identity داخل JSON مرورگر معتبر نیست.
@al-amr/backend کتابخانه است، نه سرویس اجباری الامر. اپ بدون بکاند آن را اجرا
نمیکند.
شکل پیشفرض پیکرهٔ شخصی، خصوصیِ هر محیط است: هر رکورد را نه فقط با بازیگر، بلکه
با محیطی که توکن introspectشده نام میبرد دامنهبندی کنید و توکن بدون محیط را رد
کنید. محصول actor_portable یک تصمیم اعتماد صریح است، نه حاصل حذف یک ستون.
ADR-0091 برای Notes
الزام میکند اپ فقط-حساب باشد، private_key_jwt بهکار ببرد، محیط فعلی
introspectشده را نگه دارد و backend.environments: "any" را با فهرست مجازِ
غیرخالی و بازبینیشده جایگزین کند. کلاینت فقط میتواند بدون پیوست، محیط فعلی یا
مکان captureشدهٔ فعلی را درخواست کند؛ هرگز محیط دیگری را انتخاب یا این provenance
را بازنویسی نمیکند. برای پیادهسازی مرجع apps/notes/packages/backend و برای
دامنهٔ پیشفرض و قواعد cache مشترک introspection،
ADR-0068 را بخوانید.
کشف و انتشار عمومی#
Developer Portal فقط نسخهٔ فعال و عمومی را نمایش میدهد: شناسه، ناشر، نسخهٔ دقیق، access، پشتیبانی Compact/Workspace و حالت ترجیحی، capabilityها، رخدادهای اعلان، مدل background، trust و مستندات بازبینیشده.
صفحهٔ کاتالوگ مجوز اجرا یا نصب نمیدهد. ایجاد، validation، test و publish عمومی
از CLI مستند alamr و API رجیستری در دسترس است؛ Console اختیاری است.
پیش از ارسال برای بازبینی، CLI یک باندل تغییرناپذیر را pack و upload میکند و فهرست محدود فایلهایش را با مسیر نسبی، اندازهٔ بایت و صحت SHA-512 به revision اپ متصل میکند. بازبین دقیقاً چکیدهٔ همین build را میبیند. انتشار، فعالسازی، update و rollback همان بایتهای نگهداریشده را انتخاب میکنند و هیچ host ناشری تماس گرفته نمیشود؛ باندل مفقود، تغییریافته یا ناسازگار fail closed است. ADR-0094 را ببینید.
هر revision تازهٔ App باید presentation.iconUrl نسبی به باندل نیز داشته باشد.
Registry فایل PNG یا JPEG محدود را از archive بازبینیشده میخواند، container و header و ابعاد آن را اعتبارسنجی و
metadata را با allowlist بازنویسی میکند، سپس نتیجه را به revision دقیق
متصل میسازد و descriptor متعلق به Registry با نام cardIcon را به کلاینتهای
کاتالوگ و Widget میدهد. icon غایب یا نامعتبر انتشار را متوقف میکند. scaffold
فایل public/app-icon.png را میسازد؛ ناشر پیش از انتشار آن را با icon مربعی
اختصاصی ۱۲۸ تا ۱۰۲۴ پیکسل جایگزین میکند. به
ADR-0078
مراجعه کنید.
هر revision اپ نمایندهٔ یک نسل build است. alamr build بایتهای production واقعی
را میسازد و alamr test --yes --json همانها را inventory، pack، upload، bind و
بررسی میکند. نسل تغییریافته revision تغییرناپذیر تازه میگیرد تا انتشار صرفاً
کدی اتصال build قدیمی را بازنویسی نکند. داراییها نسبت به ریشهٔ archive میمانند.
محدودیتهای فعلی#
- frontend اپ باندل تغییرناپذیر بازبینیشده است، نه بستهٔ Plugin و نه sandbox کامل ادعاشده.
- مصرف Plugin توسط اپ و UI داخل صحنه برای اپ هنوز وجود ندارد.
- camera، microphone، geolocation، display capture، clipboard، fullscreen و picture-in-picture مگر با capability متناظر که main process دسکتاپ enforce کرده باشد رد میشوند.
- raw pose، scene graph، social graph، OS push، email و marketing از قابلیتهای فعلی استنباط نمیشوند.
- نشست اپ کوتاهعمر و memory-only است و توکن سراسری اکوسیستم نیست.
- کروم پلتفرم هرگز نشانیای از سرورهای تو بار نمیکند.
presentation.iconUrlفایل داخل باندل بازبینیشده را نام میبرد؛ کارت کاتالوگ فقطcardIconتغییرناپذیر و متعلق به Registry را میگیرد. نشان اپ در حال اجرا همچنان ازpresentation.markمیآید، مجموعهای بسته که خود پلتفرم آن را میکشد. - AppHost دسکتاپ اپ پسزمینهای را که از قبل در حال اجراست هنگام جابهجایی محیط زنده نگه میدارد و اختیارش را روی محیط فعال تازه میکند؛ Grantهای محیط قبلی منتقل نمیشوند. هیچ چیزی اپی را مستقیم در پسزمینه راه نمیاندازد. اپ وقتی پسزمینه میشود که کسی کنارش گذاشته باشد.
- هرگز دو اپ همزمان روی صفحه نیستند. کنار هم چیدن، پنجرهٔ قابل تغییر اندازه و Workspace موبایل در دسترس نیستند.
Notes اپ دانش شخصی مرجع است. حالت کامل Compact و حالت ترجیحی Workspace یک کتابخانهٔ actor-portable را با پوشههای مستقل و یک سند بلوکی canonical باز میکنند؛ همان سند هم در ویرایش عادی و هم در اوتلاین شبیه Word دیده میشود. پیوست محیط یا مکان captureشده provenance اختیاری و تغییرناپذیر است؛ مکان نسبت به خود یادداشت نقش دوم دارد و navigation فقط وقتی ارائه میشود که محیط مالک همان محیط فعلی باشد. قابلیت حمل آن فقط به شش محیط first-party بازبینیشده میرسد. پیش از پذیرش محیط دلخواه یا ثالث، مراسم user-presence متعلق به مبدأ رجیستری لازم است.
همقدم نخستین اپ درونسازمانی است که دادهاش میان یک سازمان مشترک است، نه
scopeشده به یک نفر. مرجعِ هزینهٔ همین است: اپی که پیکرهٔ دادهاش را خوانندههای
بسیاری مشترکاً میخوانند نمیتواند از کلید مرکبی که
ADR-0068 آن را کنترلی ساختاری
میکند استفاده کند، پس بهجایش اقتدار را به یک محیط خانگی سنجاق میکند، فهرست
مجاز را روی خواندن هم میگذارد، دو مجموعهٔ محرمانه را جدا نگه میدارد تا خواندن
انبوه کند بماند، و در هر رأی نشستِ کنشگر را ثبت میکند.
ADR-0072 کل این معامله
را ثبت کرده است، از جمله ریسک باقیماندهای که تا آمدن احراز هویت کلاینت اپ سر
جایش میماند. دو قاعدهٔ فهرست اعضا را هم نشان میدهد: عضویت یک فهرست پذیرش است نه
سیاههٔ کسانی که اپ را باز کردهاند، و platform.identity.profile.read@1 اجازهٔ
دیدن نام را به خودِ اپ میدهد، نه به کاربران دیگرِ آن اپ — نمایش یک نفر به
نفر دیگر رضایت ثبتشدهٔ خودش را میخواهد.
پیش از انتشار، ساخت اپ، مرجع مانیفست، مرجع SDK و اعتماد و امنیت را بخوانید.