CIT HUB EXTENSIONS
開発者ドキュメント / APIリファレンス
APIを使って、
CIT Hubを拡張する。
TypeScript SDKから利用できる機能、必要な権限、データの範囲、互換性をまとめています。実装例から読み始め、APIの詳細へ進めます。
ここに記載するのは現行実装を確認できる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とエラーを扱ってください。
本ページで説明する範囲。個別のOS制約・権限・データ取得条件は各節に記載しています。
OSや元データの制約を受けます。例: 端末内キャッシュがない場合のデータAPI、OSに任される通知時刻。
APIとして公開していない機能です。計画・要望・SDK上の型だけでは利用可能とは限りません。
拡張機能はPortal/Manabaのパスワード、OTP秘密鍵、Cookie、他ユーザー情報、任意ネイティブコードにアクセスできません。本人データも宣言権限の範囲に限られ、外部送信は開発者が記述した処理に対して接続先を限定します。
はじめに
SDK ZIPを展開し、Node.js 22以降の環境で開発キット内のビルダーを使います。サンプルのソースを編集し、生成したJSONを開発者コンソールへアップロードしてください。
npm install
npm run build -- examples/study-status.tsTypeScriptソースは開発者の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, ui.date |
| 画面・操作 | 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 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の本人データ
| API | Permission | 内容 |
|---|---|---|
cit.courses.list/get/search/byWeekday/forPeriodcit.timetable.today/tomorrow/week/current/next/at/freePeriods | timetable.read | 端末に取得済みの授業・教室・時限・日付別授業 |
cit.assignments.list/get/pending/overdue/dueSoon/search/byCourse/between | assignments.read | 端末に取得済みの課題。提出済み状態は元データにない場合推定しません |
cit.todo.list/get/search/watch/create/update/complete/uncomplete/delete | todos.read, todos.write | 本人が登録したToDo。読み取りと変更は別権限 |
cit.courseNotes.list/get/create/update/delete | courseNotes.read, courseNotes.write | 本人の授業メモ |
cit.semester.current/list, cit.academicCalendar.list/on/between/isClassDay | timetable.read, calendar.read | 端末キャッシュに存在する学期・学年暦。根拠不足は不明値 |
cit.bus.routes/stops/timetable/next/between/serviceStatus | bus.read | アプリが取得・キャッシュした公開バス時刻表 |
cit.cafeteria.locations/menu/cameraStatus | cafeteria.read | 食堂拠点、メニューリンク、公開カメラ稼働状況 |
cit.settings.appearance/notifications/enabledServices, cit.services.list, cit.user.preferences | settings.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 権限と直接操作が必要です。宣言されていない権限を要求することはできません。
ユーティリティと暗号
| Namespace | API |
|---|---|
math | round, floor, ceil, min, max, abs, random, clamp, sum, average, median |
text | format, replace, split, join, contains, startsWith, endsWith, trim, lowercase, uppercase, regex |
json | parse, stringify |
date | now, parse, format, add, subtract, diff, startOfDay/endOfDay, startOfWeek/endOfWeek, isToday/isPast/isFuture, timezone |
utils | uuid, sleep, debounce, throttle |
geo | distance, bearing, contains |
crypto | randomBytes, 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ではありません。
| 操作 | 説明 | 認証 |
|---|---|---|
capabilities | host 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.read | cit.courses.* / cit.timetable.* | 端末に取得済みの本人の時間割 |
assignments.read | cit.assignments.* | 端末に取得済みの本人の課題 |
todos.read / todos.write | cit.todo.* | 本人が作成したToDoの読み取り・変更 |
courseNotes.read / courseNotes.write | cit.courseNotes.* | 本人の授業メモ |
calendar.read / bus.read / cafeteria.read | cit.academicCalendar.* / cit.bus.* / cit.cafeteria.* | アプリに取り込まれた学年暦・公開交通/食堂情報 |
settings.read | cit.settings.* / cit.services.list() | 本人の表示・通知・有効タブ設定。認証情報は含まない |
storage.* / files.storage / cloud.storage | 端末保存・専用ファイル・本人専用Cloud KV | 拡張機能ごとに隔離。任意の他ユーザー情報は取得不可 |
network.fetch + files.storage | network.uploadFile() / network.downloadFile() | 宣言したHTTPSホスト・拡張機能専用領域のみ。利用者操作が必須 |
network.fetch | network.fetch/get/post/put/patch/delete | manifestで列挙したHTTPSホストのみ |
camera.use / location.use / notifications.schedule | カメラ・現在地・ローカル通知 | 宣言に加えて、必要な場合はユーザー操作とOS許可が必要 |
files.user / files.selection.read / photos.user | ファイル選択・選択内容の読取・写真選択 | 利用者が選択した項目のみ |
動かない場合の確認順
app.hostVersion()とcapabilities.has()でホスト対応状況を確認します。- APIの権限をmanifestに宣言し、開発版を再ビルド・再アップロードします。
- 端末側で対象データが一度取得済みか、設定やOS権限が許可されているかを確認します。
- 例外は握りつぶさず、エラーの
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 | 追加内容 |
|---|---|
| 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仕様書を参照してください。
公開していないAPI
添付の構想すべてが実装済みではありません。サーバーFunctions/KV/DB/Cron、ユーザー間共有・グループ・Realtime・Push、WebSocket、OAuth/OIDC、拡張機能間Intents、OSウィジェット/App Intents、地図UI、画像変換、音声録音、モーションセンサー、汎用ドラッグ&ドロップ、任意Canvas/グラフ、PDFのページ操作、転送進捗は未実装または未接続です。
これらは使用できるAPIや権限として公開していません。APIの詳しい型・挙動・制限は詳細API仕様(Markdown)を確認してください。