Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bağlamalar ve şema sabitleme

Bu sayfa, bir eklentinin şema belgesinden (artifact) tipli istemci kodu üretmeyi ve istemcinizin hangi şema sürümüyle derlendiğini sabitlemeyi (pin) anlatır. Sabitleme sayesinde sunucu eklentiyi güncellediğinde istemciniz sessizce yanlış alanlarla konuşmak yerine uyuşmazlığı fark eder.

Şema belgesi ne içerir

GET /v1/plugins/{plugin_id}/schema ya da depodaki artifacts/plugins/<id>.plugin.schema.json aynı belgedir. Üst düzey alanlar:

AlanAnlam
pluginIdEklenti kimliği (ör. package-ride)
versionEklenti sürümü (ör. 1.44.0)
schemaSha256schemas bölümünün özeti; şema sabitleme anahtarı (aşağıda)
protocolVersionEklenti protokol ana sürümü (şimdilik 1)
codecProfileTel kodlaması: plugin-v1-decimal-int64 (sayılar)
schemasGirdi ve çıktı JSON şemaları (bileşen adı → şema)
queries, commandsİşlem tanımları
modulesRealtime modülleri

Bir işlem tanımı şu alanları taşır:

AlanAnlam
nameİşlem adı; istemci kodunda yöntem adıdır (ör. claimLoginBonus)
kind, method, pathcommand ya da query; HTTP yöntemi; tam yol
requestSchema, responseSchema, schemaVersionGirdi ve çıktı şemaları ve gönderilecek x-crx-schema-version
requestMessageType, responseMessageTypeYoldaki {message_type} ve çıktı mesaj türü
accessplayer, server ya da public
retryread (güvenle tekrar), same-key-command (yalnız aynı anahtarla tekrar), never
journalnone, full ya da reference: SDK’nın komutu yerelde nasıl kaydettiği (yeniden yüklemeden sonra devam için)
idempotencyRequired, receiptRetentionSeconds, resultPathKomutlar için: anahtar zorunluluğu, kayıt süresi, sonuç sorgu yolu
deprecatedVarsa kullanımdan kalkma bilgisi: since, sinceUnixS, replacement (sürümleme)

Realtime modülü tanımı moduleId, input, state, events, signals, authorityMode, deliveryClass, interestPolicy, stateTtlMs ve sequencePolicy taşır; girdi ve durum mesajlarında maxBytes, ratePerSecond ve burst bulunur (protokol).

schemaSha256 nedir

schemaSha256, belgedeki schemas nesnesinin kurallı JSON (anahtarlar sıralı, boşluksuz, UTF-8) çıktısının SHA-256 özetidir (küçük harfli onaltılık, 64 karakter). Şema alanları değişirse özet değişir; sürüm numarası aynı kalsa bile. Bu yüzden “sürüm eşleşiyor” demek yetmez: özet eşleşmelidir.

Özeti kendiniz de yeniden hesaplayıp doğrulayabilirsiniz:

import { createHash } from "node:crypto";

type Json = null | boolean | number | string | Json[] | { [key: string]: Json };

/** Anahtarları özyinelemeli sıralar; sunucudaki kurallı JSON biçimiyle aynı baytları üretir (boşluksuz). */
function canonical(value: Json): Json {
  if (Array.isArray(value)) return value.map(canonical);
  if (value !== null && typeof value === "object") {
    const sorted: { [key: string]: Json } = {};
    for (const key of Object.keys(value).sort()) sorted[key] = canonical(value[key] as Json);
    return sorted;
  }
  return value;
}

/** Şema belgesinin `schemas` bölümünden `schemaSha256` değerini yeniden hesaplar. */
export function schemaSha256(artifact: { schemas: Record<string, Json> }): string {
  return createHash("sha256").update(JSON.stringify(canonical(artifact.schemas)), "utf8").digest("hex");
}

/** Belgenin kendi bildirdiği özet, içeriğiyle uyuşuyor mu? */
export function artifactIsConsistent(artifact: { schemaSha256: string; schemas: Record<string, Json> }): boolean {
  return schemaSha256(artifact) === artifact.schemaSha256;
}

Not

Bu hesap yalnız schemas bölümünü kapsar; işlem listesini (commands, queries) ya da version alanını kapsamaz. Bir işlemin yolu ya da erişim türü değişirse özet değişmeyebilir; bu yüzden bağlamayı yeniden üretirken belgenin tamamının farkına da bakın.

TypeScript bağlaması üretme

  1. Şema belgesini alın ve bir dosyaya kaydedin. Sunucudan: oyuncu oturumuyla ya da sunucu anahtarıyla GET /v1/plugins/{plugin_id}/schema.
  2. Özeti belgeden okuyun (schemaSha256) ve release manifestinize/CI’ya yazın: bu sizin sabitleme değerinizdir.
  3. SDK’nın crx komutuyla bağlamayı üretin:
npx crx plugins generate \
  --input demo-game.plugin.schema.json \
  --schema-sha256 ffc38829f30ea0dd1b829f351f905854a9875806fbc8a2bbd591815c7ee52c2f \
  --output src/generated/demo-game.ts
  1. CI’da üretilmiş dosyanın güncel olduğunu denetleyin; --check dosyayı yazmaz, byte karşılaştırır:
npx crx plugins generate --input demo-game.plugin.schema.json \
  --schema-sha256 ffc38829f30ea0dd1b829f351f905854a9875806fbc8a2bbd591815c7ee52c2f \
  --output src/generated/demo-game.ts --check

Davranış:

  • Girdi belgesi yerel dosyadır; komut ağa çıkmaz ve belgeyi yürütmez.
  • --schema-sha256 zorunludur ve belgedeki schemaSha256 ile aynı olmalıdır; farklıysa üretim reddedilir. Özet otomatik yenilenmez: değişikliği bilinçli onaylarsınız.
  • Çıktı yalnız yeni dosya yazar; var olan dosyayı ezmez (üretimi yenilemek için dosyayı silin). Çıktı klasörü önceden var olmalı ve yolu sembolik bağ içermemelidir (komut yolu gerçek yoluyla karşılaştırır); sembolik bağ ve özel dosya reddedilir; hedef .ts olmalıdır. Girdi dosyası en çok 2 MiB olabilir.
  • Başarıda CRX PLUGINS GENERATE PASS (--check ile CRX PLUGINS CHECK PASS) yazar ve 0 ile çıkar.
  • Hata durumunda komut ayrıntı vermez (yol ve içerik sızmasın diye); tek satır CRX TYPES FAIL: input/version/hash/output reddedildi yazar ve 1 ile çıkar. Önce girdi dosyasını, özeti ve çıktı yolunu kontrol edin.
  • Aynı girdi her zaman aynı bayt çıktısını verir.

Üretilen dosya, şemalardan TypeScript tiplerini (bigint olarak int64), işlem tablolarını, modül tanımlarını ve gömülü artifact + özeti taşır. Kullanım:

import { DemoGameBinding } from "./generated/demo-game.js";

const demo = client.plugin(DemoGameBinding);
await demo.queries.getGiftStatus({ includeHistory: true });
const handle = await demo.commands.claimDailyGift.prepare({ giftKey: "daily" });

access: "server" olan işlemler oyuncu istemcisinde görünmez ve çağrılamaz; bunları sunucunuzdan sunucu anahtarıyla HTTP ile çağırın (eklentileri çağırma). access: "public" sorgular game.publicPlugin(...) ile kimliksiz çağrılır.

Not

Komut tanımı retry: "same-key-command" ise SDK ağ hatasında yalnız aynı anahtarla yeniden dener; journal: "full" ise sayfa yeniden yüklenince yarım kalan komut aynı anahtarla devam ettirilir. SDK kurulumu ve journal seçenekleri TypeScript SDK sayfasındadır.

Sabitleme (pin) ve uyuşmazlık

İstemci iki yerde sürüm uyumunu denetler:

  1. Derleme/başlatma zamanı, yerel: createGameClient ile bağlama kurarken oyununuzun release manifestindeki beklentiyi (pin) verirsiniz. Bağlama içindeki pluginId, schemaSha256, protocolVersion, codecProfile (ve verdiyseniz version) beklentiyle birebir eşleşmezse CrxError (kind: upgrade_required, code: plugin_binding_mismatch) fırlatır; hiçbir istek gitmez. Bu denetim sunucuya sormaz; yalnız elinizdeki bağlamanın beklediğiniz bağlama olduğunu doğrular.
  2. Sunucudaki gerçek belge: TypeScript SDK’sı çalışma zamanında /schema ucunu kendiliğinden çağırmaz. Sunucu eklentiyi güncellediyse istemcinizin eski bağlamasıyla uyuşmazlığı görmek için belgeyi başlangıçta kendiniz sorgulayıp özeti karşılaştırın:
import { DemoGameBinding } from "./generated/demo-game.js";

/**
 * Sunucudaki şema belgesini alır ve elinizdeki bağlamayla karşılaştırır. Uyuşmazsa istemciyi güncelleyin:
 * yeni belgeyi alın, yeni `schemaSha256`'yı manifestinize yazın, bağlamayı yeniden üretin.
 * Çerez oturumu açıkken tarayıcıda çalışır (aynı kökenden, `credentials: "include"`).
 */
export async function serverSchemaMatches(baseUrl: string, environmentId: string): Promise<boolean> {
  const response = await fetch(`${baseUrl}/v1/plugins/${DemoGameBinding.pluginId}/schema`, {
    credentials: "include",
    headers: { "x-crx-env": environmentId },
  });
  if (!response.ok) throw new Error(`şema belgesi alınamadı: HTTP ${response.status}`);
  const live = (await response.json()) as {
    pluginId: string;
    schemaSha256: string;
    protocolVersion: number;
    codecProfile: string;
  };
  return (
    live.pluginId === DemoGameBinding.pluginId &&
    live.schemaSha256 === DemoGameBinding.schemaSha256 &&
    live.protocolVersion === DemoGameBinding.protocolVersion &&
    live.codecProfile === DemoGameBinding.codecProfile
  );
}

Unity SDK’sında bu denetim hazırdır: PluginClient.VerifyServerSchemaAsync() sunucunun belgesini alır ve pluginId, schemaSha256, protocolVersion, codecProfile (ve pin’de verilmişse version) alanlarını bağlamanın pin’iyle karşılaştırır. Uyuşmazlıkta OpenPlayException (ErrorKind.UpgradeRequired, kod plugin_binding_mismatch) fırlatır; pin alanı yok ya da bozuksa ErrorKind.Contract.

using System.Threading.Tasks;
using OpenPlay;
using OpenPlay.PackageRide;

/// <summary>
/// Oyuna girerken sunucudaki eklenti şemasının, pakete gömülü bağlamayla aynı olduğunu doğrular.
/// Uyuşmazlıkta (<c>UpgradeRequired</c>, kod <c>plugin_binding_mismatch</c>) oyuncuyu güncellemeye yönlendirin.
/// </summary>
public static class PluginPinCheck
{
    public static async Task<bool> ServerSchemaMatches(OpenPlayClient client)
    {
        var rides = PackageRideClient.Create(client); // pin: pluginId, schemaSha256, protocolVersion, codecProfile, version
        try
        {
            await rides.Plugin.VerifyServerSchemaAsync(); // GET /v1/plugins/package-ride/schema; yalnız pin alanlarını okur
            return true;
        }
        catch (OpenPlayException ex) when (ex.Kind == ErrorKind.UpgradeRequired)
        {
            UnityEngine.Debug.LogWarning("Eklenti şeması değişti; istemciyi güncelleyin: " + ex.Code);
            return false;
        }
    }
}

Uyuşmazlık olursa istemci ne görür

Sunucu eklentiyi güncelleyip istemciniz eski bağlamayla çağırırsa:

Değişiklikİstemci görür
İşlemin schemaVersion değeri arttı400 invalid_argument (bilinmeyen şema sürümü). x-crx-schema-version eskiyi gönderiyordu
İşlem ya da mesaj türü kalktı404 not_found
Girdi şemasına zorunlu alan eklendi400 invalid_argument (şemaya uymayan yük)
Çıktı şeması değiştiSDK yanıtı bağlamaya göre çözemez; contract türünde hata
Eklenti ortamınız için etkin değil / sürüm yetkisi uyuşmuyor403 forbidden

Çözüm hep aynıdır: güncel şema belgesini alın, bilinçli olarak yeni schemaSha256’yı manifestinize yazın, bağlamayı yeniden üretin ve istemciyi yayınlayın. Eski istemcilerin bir süre daha çalışması gerekiyorsa sunucuda eski şema sürümünün korunup korunmadığını eklenti sağlayıcınıza sorun; bunun garantisi platformda yoktur.

Unity bağlaması

Unity SDK’sında bağlama yalnız package-ride eklentisi için hazır gelir (OpenPlay.PackageRide: PackageRideBinding, PackageRideClient). Başka bir eklenti için Unity bağlaması bugün üretilemez: SDK’nın üretici betiği depo içi bir araçtır ve yayımlanan pakette gelmez. Üretici yalnız access değeri player ya da public olan işlemleri paketler (sunucuya özel işlem pakete girmez) ve yalnız plugin-v1-decimal-int64 kodlamasını kabul eder; int64 alanlar C# long olur.

Kullanım için Unity SDK sayfasındaki PluginCall örneğine bakın.

Sıradaki adım