CIT Hub Developer Documentation
このページの目次

CIT HUB EXTENSIONS

開発者ドキュメント / APIリファレンス

APIを使って、
CIT Hubを拡張する。

TypeScript SDKから利用できる機能、必要な権限、データの範囲、互換性をまとめています。実装例から読み始め、APIの詳細へ進めます。

Host API v47SDK v0.47.0Runtime QuickJS / TypeScript対象 iOS・iPadOS・macOS・Android
公開サーバーへの反映待ち
このリファレンスとSDKはHost API v47です。現在の開発者コンソールサーバーはHost API v34を返すため、v35以降を必要とするAPIはサーバー更新までアップロード・起動できません。v47 APIはSDK・アプリ・配布サーバーの更新後に利用できます。
このリファレンスについて
ここに記載するのは現行実装を確認できるAPIです。Capabilityが存在するかは capabilities.has() で実行時に確認してください。未提供APIは末尾に明示しています。

APIの全体像

拡張機能はアプリ内の隔離されたTypeScriptランタイムで動作します。画面はiOS・AndroidのネイティブUIで描画し、CIT Hubの個人データは端末内で読み取ります。

最初のAPI呼び出し

import { app, capabilities, cit } from '../sdk/index';

const host = app.hostVersion();
const canReadSchedule = capabilities.has('timetable.read');
const nextClass = canReadSchedule ? await cit.timetable.next() : null;

console.log({ host, nextClass });

APIは機能単位の権限とホストCapabilityを検査します。権限が宣言されていない場合や、古いアプリに必要なAPIがない場合は、呼び出しは明示的なエラーになります。

対応状況の見方

SDKに型があることと、すべてのOSで実機検証済みであることは同じではありません。次の区分を確認し、必要に応じて実行時Capabilityとエラーを扱ってください。

●実装済みAPI

本ページで説明する範囲。個別のOS制約・権限・データ取得条件は各節に記載しています。

●制約・部分対応あり

OSや元データの制約を受けます。例: 端末内キャッシュがない場合のデータAPI、OSに任される通知時刻。

●未提供

APIとして公開していない機能です。計画・要望・SDK上の型だけでは利用可能とは限りません。

セキュリティ境界
拡張機能はPortal/Manabaのパスワード、OTP秘密鍵、Cookie、他ユーザー情報、任意ネイティブコードにアクセスできません。本人データも宣言権限の範囲に限られ、外部送信は開発者が記述した処理に対して接続先を限定します。

はじめに

SDK ZIPを展開し、Node.js 22以降の環境で開発キット内のビルダーを使います。サンプルのソースを編集し、生成したJSONを開発者コンソールへアップロードしてください。

npm install
npm run build -- examples/study-status.ts

TypeScriptソースは開発者のPC上でビルドされます。信頼できないソースをビルドしないでください。アップロードされたコードをCIT Hubのサーバーで実行することはありません。

実行型拡張機能

import { defineProgram, interactive, state, ui } from '../sdk/index';

const count = state.create(0);
export default defineProgram({
  name: 'カウンター',
  version: '1.0.0',
  description: '操作回数を数えます',
  permissions: [],
  render: () => [
    ui.page('カウンター', [
      ui.heading(`現在 ${count.value}`),
      interactive.button('1増やす', () => count.set(count.value + 1))
    ])
  ]
});

defineProgram は隔離ランタイムで処理し、画面はネイティブ部品で描画します。DOM、任意のネイティブコード、グローバルなfetch、Portal/ManabaのCookieや秘密情報にはアクセスできません。

Runtime

アプリ内のQuickJS環境は、拡張機能ごとに分離されています。Promise、async/await、標準的なTypeScriptロジックとStateを利用できます。

制約上限・挙動
処理時間1回あたり最大250ms。超過時はその実行を停止
メモリ16MB
未完了のホスト要求32件
タイマー同時32件、10ms以上、最大24時間。OSによる遅延あり
ホスト要求1要求10秒、要求内容60KBまで

アプリ情報とライフサイクル

app.version()
app.extensionId()
app.environment()       // development | production
app.hostVersion()
app.capabilities()
app.onLaunch(callback)
app.onAppear(callback)
app.onDisappear(callback)
app.onResume(callback)
app.onSuspend(callback)
app.onOpenURL(callback)
app.onNotification(callback)
app.onMemoryWarning(callback)
capabilities.has('location.current')

イベント登録APIは購読解除関数を返します。通知やURLのイベントは対象拡張機能が開いている場合に配送します。アプリ終了後の任意バックグラウンド実行は保証されません。

標準UIと入力

SwiftUI・Jetpack Composeの標準コンポーネントで描画します。任意CSSや固定座標ではなく、宣言型の組み合わせで画面を作ります。

分類SDK API
テキストui.text, ui.heading, ui.label, ui.markdown, ui.code, ui.caption, ui.badge, ui.icon
レイアウトui.vstack, ui.hstack, ui.zstack, ui.grid, ui.scroll, ui.horizontalScroll, ui.spacer, ui.divider, ui.section, ui.disclosure, ui.footer
入力interactive.textField, interactive.textArea, interactive.secureField, interactive.toggle, ui.number, ui.slider, interactive.select, interactive.multiSelect, interactive.dateTime, interactive.dateRange
画面・操作ui.page, ui.courseList, ui.dataList, interactive.button, ui.link
見た目ui.styled(node, style)。テーマ色、文字サイズ、配置、余白、間隔をホストの許容範囲で指定

文字・入力部品の詳細な上限、スタイル属性、動的状態イベントはSDK同梱の型定義と詳細API仕様(Markdown)を参照してください。

状態同期する選択入力(host API v32)

const campus = state.create('新習志野');
interactive.select('campus', 'キャンパス', ['新習志野', '津田沼'], campus);
ui.text(`選択中: ${campus.value}`);

選択肢を選ぶと値がStateに入り、そのStateを参照する画面が更新されます。選択肢は1〜100件、1件200文字以内で重複不可です。SDKはこの入力を使う拡張機能に minimumHostAPI: 32 を設定します。

状態同期する複数選択(host API v34)

const supplies = state.create<string[]>(['講義資料']);
interactive.multiSelect('supplies', '持ち物', ['講義資料', '実験器具'], supplies);
ui.text(`選択中: ${supplies.value.join('、')}`);

複数選択UIはiOS・iPadOS・macOSとAndroidのネイティブ部品で表示されます。更新値は文字列配列としてStateへ同期されます。選択肢は1〜30件、各120文字以内で重複不可です。SDKが minimumHostAPI: 34 を設定します。

状態同期する日時入力(host API v35)

const reminderAt = state.create<number | null>(null);
interactive.dateTime('reminderAt', '通知する日時', reminderAt);
ui.text(reminderAt.value === null ? '未設定' : `${reminderAt.value} ms`);

OS標準の日付・時刻選択UIを使い、選択値はUnix epochミリ秒でStateに同期します。未設定は null です。SDKは minimumHostAPI: 35 を設定し、対応前のアプリでは起動できません。

状態同期する日時範囲(host API v36)

const period = state.create<{start:number|null;end:number|null}>({start:null,end:null});
interactive.dateRange('period', '対象期間', period);

開始・終了を別々に設定でき、各値はUnix epochミリ秒または null です。終了より後の開始日時は拒否し、ネイティブUIでは逆転しないよう補正します。SDKは minimumHostAPI: 36 を付けます。実例: extensions/examples/interactive-date-range.ts

複数行テキスト入力(host API v23)

const memo = state.create('');
interactive.textArea('memo', '授業メモ', memo);
ui.caption(`${memo.value.length} / 4000`);

入力値はStateへ反映され、入力上限は4,000文字です。端末内へ保存する場合は、用途に合うstorageなどのAPIと権限を別途使用してください。

状態とイベント

const value = state.create(0);
value.get();
value.set(1);
value.update(current => current + 1);
value.reset();
const stop = value.watch((next, previous) => {});
stop();

interactive.button('保存', async () => {
  await storage.set('draft', value.get());
});

State更新は画面を再描画します。イベントコールバック内で非同期のホストAPIを呼び出せます。ホスト要求は権限とCapabilityを別々に検査します。

CIT Hubの本人データ

APIPermission内容
cit.courses.list/get/search/byWeekday/forPeriod
cit.timetable.today/tomorrow/week/current/next/at/freePeriods
timetable.read端末に取得済みの授業・教室・時限・日付別授業
cit.assignments.list/get/pending/overdue/dueSoon/search/byCourse/betweenassignments.read端末に取得済みの課題。提出済み状態は元データにない場合推定しません
cit.todo.list/get/search/watch/create/update/complete/uncomplete/deletetodos.read, todos.write本人が登録したToDo。読み取りと変更は別権限
cit.courseNotes.list/get/create/update/deletecourseNotes.read, courseNotes.write本人の授業メモ
cit.semester.current/list, cit.academicCalendar.list/on/between/isClassDaytimetable.read, calendar.read端末キャッシュに存在する学期・学年暦。根拠不足は不明値
cit.bus.routes/stops/timetable/next/between/serviceStatusbus.readアプリが取得・キャッシュした公開バス時刻表
cit.cafeteria.locations/menu/cameraStatuscafeteria.read食堂拠点、メニューリンク、公開カメラ稼働状況
cit.settings.appearance/notifications/enabledServices, cit.services.list, cit.user.preferencessettings.read本人が有効にしているサービスのタブ名と表示・通知設定。任意のサービスを自動では開きません

これらの情報は端末内で読み、拡張APIサーバーへ転送しません。キャッシュ未取得の場合は空または利用できない旨を返します。元データにない単位数、提出状態、全学休講情報は推定しません。

import { cit } from '../sdk/index';

const today = await cit.timetable.today();
const due = await cit.assignments.dueSoon(7);
const notes = await cit.courseNotes.list();
const enabledServices = await cit.services.list();

保存・データベース

端末内Key-Value

storage.get/set/has/remove/clear/keys は本人・拡張機能・開発/公開環境ごとに分離されます。拡張機能固有データを最大256KB保存できます。他端末との同期はしません。

保護された端末内保存

secureStorage.get/set/delete はiOS/macOSのKeychainまたはAndroidの暗号化保存を使います。CIT Hub本体の認証情報にはアクセスできません。

ローカルデータベース

database.createTable/insert/update/delete/get/query/transaction/watch。比較条件、並べ替え、件数制限のクエリをSDKで構成できます。スキーマは拡張機能専用でSQLite互換ではなく、非同期処理をtransaction callbackから実行できません。

ユーザー専用Cloud KV

cloudUser.get/set/delete はCIT Hubアカウントと拡張機能に隔離されます。revisionによる競合検出、暗号化、容量上限があります。サーバーFunctionsやユーザー間共有ではありません。

ファイル

拡張機能専用領域(host API v30)

await files.write('draft.txt', new TextEncoder().encode('メモ'));
const bytes = await files.read('draft.txt');
await files.copy('draft.txt', 'backup.txt');
await files.move('backup.txt', 'archive.txt');
const names = await files.list();

権限はfiles.storage。最大256KiB/ファイル、最大100ファイル・合計5MiBです。ファイル名のみを受け付け、パス区切り、親ディレクトリ指定、シンボリックリンク、既存宛先への上書きを拒否します。拡張機能の領域外へアクセスできません。

ユーザーが選ぶファイル

ui.file でシステムの選択画面を開きます。files.selection.info/readSelected は選択済みファイルの内容をチャンクで読みます。追加の files.selection.read が必要です。任意フォルダの一覧はできません。

写真・メディア・共有

ui.coursePicker、ui.capturePhoto、ui.importPhotos、ui.photoGrid で、授業選択・撮影・写真取り込み・一覧を組み合わせられます。データは端末内の拡張機能専用領域に保存します。ユーザー操作なしの撮影や写真ライブラリ全体の列挙はできません。

ui.image/video/audio は許可されたHTTPSメディアを表示します。ui.file でユーザーが選んだファイルをアプリ内プレビューまたは対応アプリへ渡せます。ui.shareText、ui.copyText は利用者の操作から実行します。

全コーデック、画像編集、録音、PDFページ操作のすべてをサポートするわけではありません。対応OS・形式はAPI仕様を確認してください。

ネットワーク

network.status() と network.onChange(callback) は端末の接続状態を参照します。接続先名、IP、SSIDは返しません。

const response = await network.fetch('https://api.example.com/items', {
  method: 'GET',
  headers: { Accept: 'application/json' }
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);

network.fetch/get/post/put/patch/delete は network.fetch 権限とmanifestの許可ホスト宣言を必要とします。HTTPS標準ポートのみ、Cookie/Host等の危険なヘッダーは禁止、本文32 KiB・応答1 MiB・ヘッダー20個までです。リダイレクトは追従せず、プライベート・予約済みIPに解決される接続先も拒否します。任意ホストを宣言なく呼び出すことはできません。

ファイル転送(host API v33)

const downloaded = await network.downloadFile(
  'https://api.example.com/handout.pdf',
  'handout.pdf'
);
if (downloaded.ok) {
  const bytes = await files.read(downloaded.file.name);
  // bytes は拡張機能専用ストレージから読み出した Uint8Array
}

network.downloadFile(url, destinationName, headers?) は取得したファイルを拡張機能専用ストレージへ保存し、名前・サイズ・HTTP状態を返します。network.uploadFile(url, sourceName, options?) は同じ専用領域に保存済みのファイルをPOSTまたはPUTで送ります。どちらも利用者が押したボタンの処理中に呼ぶ必要があり、network.fetch と files.storage の両権限、manifestの完全一致HTTPSホスト宣言が必要です。任意の端末ファイルパスにはアクセスできません。

ファイル転送はリクエスト・レスポンス各256 KiBまでです。ダウンロードはリダイレクトしません。保存時は拡張機能専用ストレージのファイル名・件数・総容量制限を適用します。通常のテキスト通信も応答上限は256 KiBです。通信先には端末のIP等が伝わり、アップロードしたファイルの内容も通信先へ渡ります。

端末・位置情報・触覚

device.info/platform/osVersion/deviceClass/screen/locale/timezone/appearance/capabilities は画面やOSの情報を返します。端末固有識別子は提供しません。

location.current() は location.use とユーザー操作を必要とし、単発の現在地・精度・取得時刻を返します。バックグラウンド追跡や位置のサーバー保存はありません。

haptics.light/medium/heavy/success/warning/error は対応端末のみ実行されます。accessibility.status で利用可能なアクセシビリティ状態を取得し、accessibility.label/hint/role で対応UI要素を補助できます。

ローカル通知と権限

const status = await notification.permission();
await notification.schedule({
  id: 'study-reminder',
  title: '復習',
  body: '今日のノートを確認する',
  at: new Date(Date.now() + 60 * 60 * 1000),
  repeat: 'none',
  data: { screen: 'review' }
});
notification.onOpen(event => console.log(event.data));

notifications.schedule 権限が必要です。許可状態は permissions.status/request で確認し、OS許可を要求する処理はユーザー操作から開始します。schedule/cancel/cancelAll/listScheduled/onOpen を利用できます。端末内通知であり、サーバーPushや端末間同期ではありません。OS都合で通知時刻が遅れる場合があります。

permissions.openSettings() は settings.open 権限と直接操作が必要です。宣言されていない権限を要求することはできません。

ユーティリティと暗号

NamespaceAPI
mathround, floor, ceil, min, max, abs, random, clamp, sum, average, median
textformat, replace, split, join, contains, startsWith, endsWith, trim, lowercase, uppercase, regex
jsonparse, stringify
datenow, parse, format, add, subtract, diff, startOfDay/endOfDay, startOfWeek/endOfWeek, isToday/isPast/isFuture, timezone
utilsuuid, sleep, debounce, throttle
geodistance, bearing, contains
cryptorandomBytes, UUID用途の安全乱数、SHA-256、HMAC、AES-256-GCM

暗号機能は拡張機能が渡したデータだけを端末内で処理します。CIT HubのKeychain、OTP、ログインCookie、アプリセッションの秘密情報にはアクセスできません。暗号化キーは拡張機能専用の secureStorage で管理してください。

エラー

ExtensionError、PermissionError、UserInteractionError、UnsupportedError、NetworkError、StorageError、ValidationError、ConflictError、NotFoundError、RateLimitError を提供します。未知のホストエラーもcodeを保持した ExtensionError で通知します。

開発者サーバーAPI

開発者コンソールとCIT Hubアプリが使用するAPIです。一般拡張機能のJavaScriptをサーバーで実行するFunctions APIではありません。

操作説明認証
capabilitieshost API version・対応permissionの固定メタデータ不要
register/login/logout/logout-all/password-change開発者アカウントとセッション管理アカウント認証
upload/submit/mine/catalog/developer本人の開発版、審査提出、承認済みカタログアプリ確認または開発者セッション
install/open/uninstallアプリ内の追加、起動、削除。host API互換性を検査本人のアカウント
data-save拡張機能専用のユーザー入力値本人・拡張機能scope
list/review審査・公開停止別管理キー

ユーザーデータはアカウント単位で隔離され、レビュー権限と一般ユーザー権限は別です。APIトークンやアプリ認証情報を拡張機能へ渡しません。

権限と互換性

使用するデータやOS機能だけをmanifestの permissions に宣言します。審査・追加確認で利用者に説明されます。Capabilityが存在してもOS権限が許可されたとは限りません。permissions.status() で区別してください。

export default defineProgram({
  name: '授業準備',
  version: '1.0.0',
  description: '次の授業と準備メモを表示します',
  permissions: ['timetable.read', 'courseNotes.read'],
  render: () => [/* native UI */]
});

SDK builderは利用APIから minimumHostAPI を設定します。現行アプリより新しいhost APIを要求する拡張機能は、古いアプリで追加・起動できません。

権限一覧

manifestには、実際に使う機能の権限だけを記載します。CIT Hubデータの権限は本人の端末内データへのアクセスを許可し、OS権限や外部通信の許可とは別に検査されます。

権限対象API範囲
timetable.readcit.courses.* / cit.timetable.*端末に取得済みの本人の時間割
assignments.readcit.assignments.*端末に取得済みの本人の課題
todos.read / todos.writecit.todo.*本人が作成したToDoの読み取り・変更
courseNotes.read / courseNotes.writecit.courseNotes.*本人の授業メモ
calendar.read / bus.read / cafeteria.readcit.academicCalendar.* / cit.bus.* / cit.cafeteria.*アプリに取り込まれた学年暦・公開交通/食堂情報
settings.readcit.settings.* / cit.services.list()本人の表示・通知・有効タブ設定。認証情報は含まない
storage.* / files.storage / cloud.storage端末保存・専用ファイル・本人専用Cloud KV拡張機能ごとに隔離。任意の他ユーザー情報は取得不可
network.fetch + files.storagenetwork.uploadFile() / network.downloadFile()宣言したHTTPSホスト・拡張機能専用領域のみ。利用者操作が必須
network.fetchnetwork.fetch/get/post/put/patch/deletemanifestで列挙したHTTPSホストのみ
camera.use / location.use / notifications.scheduleカメラ・現在地・ローカル通知宣言に加えて、必要な場合はユーザー操作とOS許可が必要
files.user / files.selection.read / photos.userファイル選択・選択内容の読取・写真選択利用者が選択した項目のみ

動かない場合の確認順

  1. app.hostVersion() と capabilities.has() でホスト対応状況を確認します。
  2. APIの権限をmanifestに宣言し、開発版を再ビルド・再アップロードします。
  3. 端末側で対象データが一度取得済みか、設定やOS権限が許可されているかを確認します。
  4. 例外は握りつぶさず、エラーの name と code を記録して原因別に案内します。
try {
  const status = await network.status();
  const next = await cit.timetable.next();
  // UIへ結果を反映
} catch (error) {
  console.error(error.name, error.code, error.message);
  // PermissionError / UnsupportedError / data_unavailable などを個別に扱う
}

エラーコードはSDKの型定義と詳細仕様書を正としてください。未実装APIはCapabilityとして公開されず、代替動作を推測して実行しません。

ホストAPIの主な追加履歴

Host API追加内容
v47OSのリンク動作を使うアクセシブルなネイティブリンクボタン ui.linkButton()
v46Stateと同期するネイティブ検索欄 interactive.searchField()
v45アクセシブルなネイティブアイコンボタン interactive.iconButton()
v44入力フォーカス・送信イベント onFocus / onBlur / onSubmit
v43安全領域・最小最大寸法・縦横比を扱うレスポンシブレイアウト ui.safeArea() / ui.frame()
v42検証済みデータから描画するネイティブ横棒グラフ ui.barChart()
v40ネイティブカード・余白グループ・レスポンシブコンテナ ui.card() / ui.group() / ui.container()
v41状態更新を包むOS標準アニメーション animation.animate() / animation.spring() / animation.transition()
v39読み込み・空・エラー状態の標準表示 ui.loading() / ui.emptyState() / ui.errorState()
v38ネイティブ線形進捗表示 ui.progress()
v37ネイティブStepper・Checkbox・RadioとTypeScript State同期
v36ネイティブ日時範囲入力とState同期 interactive.dateRange()
v35ネイティブ日時入力とState同期 interactive.dateTime()
v34ネイティブ複数選択UIとState同期 interactive.multiSelect()
v33ボタン操作を必須にした専用領域とのHTTPSファイル転送 network.uploadFile() / network.downloadFile()
v32選択変更をTypeScript Stateへ同期する interactive.select()
v31本人が有効にしている学内サービス名の一覧 cit.services.list()
v30拡張機能専用ファイルの複製・移動
v29縦・横スクロールコンテナ
v28ネットワーク接続状態の変更購読
v24–v27位置情報、接続状態、レイアウト、文字スタイル
v21–v23本人専用Cloud KV、テキストUI、複数行入力
v16–v20時間割・課題・ToDo・学年暦・バス・食堂データAPI
v9–v15実行型SDK、端末保存、ファイル、クリップボード、設定、通知など

各バージョンの厳密な制約と未実装範囲は詳細API仕様書を参照してください。

読み込み・空・エラー状態

ui.loading(label)、ui.emptyState(title, message)、ui.errorState(title, message)は、読み込み中・該当データなし・エラーを区別して伝える標準UIです。iOS・iPadOS・macOS・Androidでネイティブ描画します。SDKビルダーは最低Host API v39を自動設定し、古いホストでは互換性エラーとして起動を防ぎます。

ui.loading("時間割を読み込み中")
ui.emptyState("課題はありません", "新しい課題が届くとここに表示されます")
ui.errorState("読み込めませんでした", "通信状態を確認して再度お試しください")

カード・グループ・コンテナ

ui.card(children, label?) はOS標準のカード面、ui.group(children) は背景を足さず間隔を整理するグループ、ui.container(children) は画面幅に追従する領域です。固定座標に依存せず、iOS・iPadOS・macOS・AndroidのネイティブUIで表示します。最低Host API v40が必要で、SDKが最低バージョンを自動記録します。

ui.container([
  ui.card([ui.heading("今週の授業"), ui.data("timetable.week")], "時間割"),
  ui.group([ui.caption("操作"), ui.button("更新", "refresh")])
])

ネイティブアニメーション

animation.animate(options, update) は更新関数内のState変更をネイティブ画面へ渡し、iOS・iPadOS・macOSではSwiftUI、AndroidではComposeのレイアウトアニメーションとして描画します。期間は0.05〜1.5秒、曲線はlinear/easeIn/easeOut/easeInOut/springに限定します。自由な描画ループは実行しません。

await animation.animate({ duration: 0.25, curve: "easeInOut" }, () => {
  expanded.set(!expanded.value);
});
await animation.spring(() => expanded.set(true), { damping: 0.82 });

利用にはHost API v41が必要です。SDKビルダーが最低ホストバージョンを設定し、未対応端末では起動を拒否します。

状態と同期する入力コントロール

interactive.stepper、interactive.checkbox、interactive.radioはOS標準の入力UIを使用し、ユーザーの変更を型付きイベントとしてTypeScript Stateへ反映します。範囲・刻み・選択肢はビルド時とサーバーで検証されます。Host API v37。

interactive.stepper("count", "個数", count, 0, 10, 1)
interactive.checkbox("ready", "確認しました", ready)
interactive.radio("campus", "キャンパス", ["新習志野", "津田沼"], campus)

進捗表示

ui.progress(label, value)はOSネイティブの線形進捗表示です。値は0から1までの有限値で指定し、SDKビルドが最低Host API v38を設定します。

ui.progress("ファイルを処理中", 0.62)

横棒グラフ

ui.barChart(title, categories, series)はカテゴリ1〜12件、系列1〜4件、0〜1,000,000の有限値からOS標準の横棒表示を作ります。各系列の値数はカテゴリ数と一致させます。自由なCanvas描画は行いません。Host API v42が必要です。

ui.barChart("今週の学習時間", ["月", "火", "水"], [{ label: "時間", values: [1.5, 2, 0.75] }])

Safe Area とレスポンシブ寸法

ui.safeArea(children)はノッチ・システムバー・画面端を避けるOSネイティブ領域です。ui.frame(node, bounds)では最小/最大の幅と高さ、縦横比を指定できます。単位はiOS/macOSがpt、Androidがdp。幅・高さは0〜2000、縦横比は0.1〜10で、最小値は最大値以下である必要があります。最低Host API v43です。

ui.safeArea([ui.frame(ui.column([ui.heading("今週の授業"), ui.data("timetable.periods")]), { minWidth: 240, maxWidth: 860 })])

入力フォーカスと送信イベント

interactive.textFieldとinteractive.secureFieldはonFocus、onBlur、onSubmitを受け取ります。複数行textAreaではonSubmitを提供しません。入力値とフォーカス状態は端末内QuickJSで扱い、サーバーに送信しません。Host API v44が必要です。

interactive.textField("query", "キーワード", query, {
  onFocus: () => status.set("入力中"),
  onBlur: () => status.set("入力終了"),
  onSubmit: () => status.set(query.value),
})

ネイティブアイコンボタン(Host API v45)

interactive.iconButton(icon, label, onPress)はOS標準アイコンを44pt/dp以上のタップ領域で表示し、VoiceOverとTalkBack用ラベルを設定します。許可アイコンはbook、calendar、bus、check、clock、info、map、person、photo、plus、search、edit、list、bellです。

interactive.iconButton("plus", "回数を増やす", () => count.set(count.value + 1))

ネイティブ検索欄(Host API v46)

interactive.searchField(key, label, value, events?)はStateと同期する検索用ネイティブ部品です。検索アイコン、入力消去、検索キーを備え、最大4,000文字です。Host API v46以降が必要です。

const query = state.create('');
interactive.searchField('query', '課題名を入力', query, {
  onSubmit: () => searchAssignments(query.value)
});

実例: extensions/examples/interactive-search-field.ts

公開していないAPI

添付の構想すべてが実装済みではありません。サーバーFunctions/KV/DB/Cron、ユーザー間共有・グループ・Realtime・Push、WebSocket、OAuth/OIDC、拡張機能間Intents、OSウィジェット/App Intents、地図UI、画像変換、音声録音、モーションセンサー、汎用ドラッグ&ドロップ、自由なCanvas描画・棒グラフ以外のチャート、PDFのページ操作、転送進捗は未実装または未接続です。

これらは使用できるAPIや権限として公開していません。APIの詳しい型・挙動・制限は詳細API仕様(Markdown)を確認してください。

Portalパスワード、OTP秘密鍵、認証Cookie、CIT Hubセッショントークン、他ユーザーの個人データ、別拡張機能のprivate storage、端末固有識別子、無音撮影、無制限ファイルアクセス、任意ネイティブコード、無制限バックグラウンド実行はAPIとして提供しません。