CheckCourt
TypeScript SDK

Typed manifest

Write the app manifest in TypeScript, with autocompletion and compile-time checks

defineManifest returns the manifest unchanged. It exists for your editor and the compiler: scopes, events, extension points and their kinds are suggested and checked.

manifest.ts
import { defineManifest } from "@checkcourt/sdk";

export default defineManifest({
  installTargets: ["tenant"],
  tenantScopes: ["bookings:read", "courts:read"],
  events: ["booking.created", "booking.cancelled"],
  extensions: [
    { point: "booking.detail.panel", kind: "declarative", url: "https://door.example.com/ext/booking" },
    { point: "booking.action", kind: "declarative", url: "https://door.example.com/ext/open", label: "Tür öffnen" },
    { point: "app.settings", kind: "iframe", url: "https://door.example.com/settings" },
  ],
  settingsSchema: {
    type: "object",
    properties: {
      openMinutesBefore: { type: "number", title: "Minuten vor Spielbeginn", minimum: 0, maximum: 60, default: 10 },
    },
  },
  dataProcessing: {
    categories: ["Buchungsdaten"],
    purpose: "Öffnet die Platztür zur gebuchten Zeit",
    storageLocation: "EU",
    avvRequired: true,
  },
});

You upload JSON. Write the file with a small script, for example:

scripts/write-manifest.ts
import { writeFileSync } from "node:fs";
import manifest from "../manifest";

writeFileSync("manifest.json", JSON.stringify(manifest, null, 2) + "\n");

What the compiler checks

  • tenantScopes and userScopes only contain scopes apps may request. The scopes reserved for people are an error.
  • events only contains subscribable events. app.* events arrive without a subscription.
  • Every extension has a valid point, and kind fits the point: dashboard.widget, booking.action, kiosk.tile, court.annotation, member.list.column, booking.hint, booking_plan.action and sidebar.action only allow declarative.
  • booking.action, booking_plan.action, sidebar.action and nav.page need a label.
  • nav.page needs an icon (from @checkcourt/sdk 0.8.0). icon is otherwise only accepted on booking_plan.action and sidebar.action, and only with one of the allowed icon names.
  • height is only accepted on iframe entries (from @checkcourt/sdk 0.9.0); the range 120 to 2,000 is checked on upload.
  • settingsSchema has the shape CheckCourt renders as a form (string, number, boolean).
  • shares, reads, emits and subscribes have the shape described in Connections between apps.
  • permissions entries have a key and a label, and requires is only accepted on nav.page (from @checkcourt/sdk 0.11.0). Whether requires names a declared key, key format and limits are checked on upload.
  • dataProcessing is complete.

What can only be checked at runtime, CheckCourt checks on upload: whether every event has its scope, whether points with a subject have the required scope, URLs, lengths, duplicate points and the rules between installTargets and userLinking. You see the messages in the developer portal.

Types and constants

ExportContents
ManifestType of the whole manifest
ManifestExtensionOne entry in extensions
SettingsSchema, SettingsPropertysettingsSchema
AppPermission, MAX_APP_PERMISSIONS, APP_PERMISSION_KEY_PATTERNpermissions
GrantableScope, GRANTABLE_SCOPESAll scopes apps may request
SubscribableEventTypeAll subscribable events
ExtensionPoint, EXTENSION_POINTSPoints with allowed install targets and kinds
EXTENSION_POINT_SCOPEScope a point with a subject needs
StaticActionPoint, STATIC_ACTION_POINTS, STATIC_ACTION_LABEL_MAXbooking_plan.action and sidebar.action, label limit 24 (also for nav.page)
AppActionIcon, APP_ACTION_ICONSIcon names for static actions and nav.page
IFRAME_EXTENSION_HEIGHT_MIN, IFRAME_EXTENSION_HEIGHT_MAXRange of height (120 to 2,000)
DataProcessingdataProcessing
SharedMetadata, ReadMetadata, EmittedEvent, SubscribedEvent, AppEventSchemaConnection fields
SHARED_OBJECT_TYPES, SHARED_OBJECT_SCOPE, CONNECTION_NAME_PATTERN, MAX_SHARED_VALUE_BYTESConnection rules

On this page