فهرست مستندات

مرجع مانیفست#

چهار فایل، پروژه‌ها و اتصال محلی 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 اعتبارسنجی می‌کند.