@uzuhq/code-sdk 0.7.6 → 0.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/dev-globals.d.ts +12 -27
  2. package/dist/dev-globals.js +0 -15
  3. package/dist/dev-hooks-ClWM8HzI.d.ts +682 -0
  4. package/dist/index.d.ts +152 -66
  5. package/dist/index.js +1837 -416
  6. package/package.json +8 -5
  7. package/dist/action-types.test-d.d.ts +0 -11
  8. package/dist/action-types.test-d.js +0 -101
  9. package/dist/dev-hooks.d.ts +0 -241
  10. package/dist/dev-hooks.js +0 -132
  11. package/dist/dev-hooks.test.d.ts +0 -1
  12. package/dist/dev-hooks.test.js +0 -294
  13. package/dist/dev-prediction-traps.d.ts +0 -32
  14. package/dist/dev-prediction-traps.js +0 -0
  15. package/dist/dev-prediction-traps.test.d.ts +0 -1
  16. package/dist/dev-prediction-traps.test.js +0 -178
  17. package/dist/dev-state-patch.d.ts +0 -81
  18. package/dist/dev-state-patch.js +0 -295
  19. package/dist/dev-state-patch.test.d.ts +0 -1
  20. package/dist/dev-state-patch.test.js +0 -333
  21. package/dist/json-patch.d.ts +0 -7
  22. package/dist/json-patch.js +0 -78
  23. package/dist/random.d.ts +0 -11
  24. package/dist/random.js +0 -34
  25. package/dist/reconnectable-ws.d.ts +0 -60
  26. package/dist/reconnectable-ws.js +0 -229
  27. package/dist/room.d.ts +0 -23
  28. package/dist/room.js +0 -36
  29. package/dist/roster-params.test.d.ts +0 -1
  30. package/dist/roster-params.test.js +0 -86
  31. package/dist/run/local-server-action.d.ts +0 -16
  32. package/dist/run/local-server-action.js +0 -217
  33. package/dist/run/local-server-action.test.d.ts +0 -1
  34. package/dist/run/local-server-action.test.js +0 -242
  35. package/dist/run/optimistic-action-client.d.ts +0 -68
  36. package/dist/run/optimistic-action-client.js +0 -209
  37. package/dist/run/optimistic-action-client.test.d.ts +0 -1
  38. package/dist/run/optimistic-action-client.test.js +0 -430
  39. package/dist/run/server-action.d.ts +0 -16
  40. package/dist/run/server-action.js +0 -181
  41. package/dist/run/server-action.test.d.ts +0 -1
  42. package/dist/run/server-action.test.js +0 -105
  43. package/dist/server-clock.d.ts +0 -29
  44. package/dist/server-clock.js +0 -40
  45. package/dist/server-only.d.ts +0 -33
  46. package/dist/server-only.js +0 -21
  47. package/dist/sync/local.d.ts +0 -8
  48. package/dist/sync/local.js +0 -50
  49. package/dist/sync/online.d.ts +0 -5
  50. package/dist/sync/online.js +0 -165
  51. package/dist/types.d.ts +0 -345
  52. package/dist/types.js +0 -8
package/dist/types.d.ts DELETED
@@ -1,345 +0,0 @@
1
- /**
2
- * @docs
3
- * - SDK仕様: docs/docs/uzu_code/play-screen-sdk.md
4
- * - APIリファレンス: docs/docs/uzu_code/sdk-guide/api-reference.md
5
- * - 開発パターン: docs/docs/uzu_code/sdk-guide/patterns.md
6
- * - 外部 automation API: docs/docs/uzu_code/sdk-guide/dev-hooks.md
7
- */
8
- /** @deprecated 旧フラット形式。新コードでは BridgeMessage を使用 */
9
- export type PlayScreenMessage = {
10
- type: string;
11
- [key: string]: unknown;
12
- };
13
- /** ブリッジメッセージのチャンネル */
14
- export type BridgeChannel = 'sdk' | 'game';
15
- /** ワイヤーフォーマット: { channel, type, payload, playerId? } */
16
- export interface BridgeMessage {
17
- channel: BridgeChannel;
18
- type: string;
19
- payload: Record<string, unknown>;
20
- /**
21
- * 送信元プレイヤーの ID(ゲーム → ホスト方向のみ)。
22
- * Web エミュレータでは複数プレイヤーの iframe が同一オリジンになり
23
- * postMessage の送信元 iframe を区別できないため、ホストはこの値で
24
- * 自分宛メッセージかを判定する。
25
- *
26
- * Flutter ホスト(QueryParamsBuilder)と dev ハーネスは URL に必ず
27
- * playerId を付与するため、ゲーム → ホスト方向では常に存在する。
28
- * optional なのはホスト → ゲーム方向のメッセージが持たないため
29
- * (受信側は playerId 無し = 旧 SDK ビルドとして扱う)。
30
- */
31
- playerId?: string;
32
- }
33
- /**
34
- * 自分の席種別。ホストが iframe URL の `?seatKind=` で伝える。
35
- *
36
- * roster に載るのは `player` だけ。観測者 (`spectator` / `admin`) は roster 外の接続として
37
- * 開くので、「player か観測者か」は `state.players` の空振りで分かる。一方 **`spectator` と
38
- * `admin` の区別は state から導けない**ため、この値で分ける。seatId の命名規約
39
- * (`admin_0` 等) をシナリオに見せると、規約が変わった瞬間に静かに壊れる。
40
- *
41
- * 自己申告なので権限の根拠にはならない。表示の分岐にだけ使うこと。
42
- */
43
- export type SeatKind = 'player' | 'spectator' | 'admin';
44
- /**
45
- * roster に載る席。
46
- *
47
- * roster は配役を受け取る参加者だけで構成される。観測者 (GM 席・観戦席) は roster に
48
- * 載らないまま接続してくるので、シナリオは「roster に居ない = 観測者」で判別する。
49
- * 席種別は roster エントリではなく自分の `SeatKind` として渡る。
50
- */
51
- export interface Seat {
52
- id: string;
53
- nickname: string;
54
- iconUrl: string;
55
- /** ホスト(mobile / emulator)から渡される、選択済みキャラクターの ID。未選択時は undefined。 */
56
- characterId?: string;
57
- }
58
- /** プレイヤーごとのリアルタイム状態 */
59
- export interface PlayerVoiceState {
60
- /** 音声状態。音声通話に未接続の場合は null */
61
- audioStatus: 'speaking' | 'listening' | 'muted' | 'unstable' | null;
62
- }
63
- /** @deprecated 旧形式。新コードでは onPlayersChanged() と PlayerVoiceState を使用 */
64
- export interface PlayersChangedMessage {
65
- players: Record<string, PlayerVoiceState>;
66
- }
67
- export type Emit = (eventName: string, data?: Record<string, unknown>) => void;
68
- /**
69
- * events handler。
70
- *
71
- * `emit(name, data)` の `data` をそのまま受け取る。先読み中か確定後かは渡さない
72
- * (どちらで呼ばれても同じ処理をする前提。 `predict` で宣言済みなので分岐の必要がない)。
73
- */
74
- export type EventHandler = (data: Record<string, unknown>) => void;
75
- /**
76
- * events の購読宣言。
77
- *
78
- * 先読みは外れることがあり、実行してしまったものは取り消せない。取り消せない副作用
79
- * (analytics / 実績解除 / 長い演出) は必ず `predict: false` にすること。
80
- */
81
- export interface EventSubscription {
82
- /** 先読み時点で実行してよいか。宣言必須。 */
83
- predict: boolean;
84
- handler: EventHandler;
85
- }
86
- /** dev harness で観測される 1 件の emit。`data` は `emit(name)` 省略時に空 object になる。 */
87
- export interface ServerEvent {
88
- name: string;
89
- data: Record<string, unknown>;
90
- }
91
- export interface SeededRandom {
92
- float(): number;
93
- int(max: number): number;
94
- pick<T>(array: T[]): T;
95
- shuffle<T>(array: T[]): T[];
96
- }
97
- /**
98
- * 素の action handler の実行文脈。空なのは意図的。
99
- *
100
- * 素の handler はサーバーとクライアント先読みの両方で走る。クライアントが自力で
101
- * 再現できない値 (tick / 乱数) をここで配ると、サーバー・ソロ・dev では本物が入るのに
102
- * オンラインの先読みだけ値がズレる、という一番気付きにくい形で壊れる。
103
- * そういう値が要る処理は `serverActions` 側に書く。
104
- */
105
- export interface ActionContext {
106
- /**
107
- * サーバーで処理される時刻 (ms)。先読みではクロックオフセットからの推定値。
108
- *
109
- * 推定なのでサーバーとは数十 ms ずれる。時刻での分岐に使うと境界で判定が割れるので、
110
- * 分岐は `update()` (サーバー専用) で行う。
111
- *
112
- * 同じ action を再適用しても値は変わらない (初回予測時の値を使い回す)。
113
- */
114
- now: number;
115
- emit: Emit;
116
- }
117
- /** `deadlines` handler の実行文脈。サーバーでしか走らないので tick 以外を渡せる。 */
118
- export interface DeadlineContext {
119
- /** 発火時刻 (ms)。サーバー専用なので常に正確。 */
120
- now: number;
121
- random: SeededRandom;
122
- emit: Emit;
123
- }
124
- /** `deadlines` handler の引数。 */
125
- export interface DeadlineArgs<S> {
126
- state: S;
127
- ctx: DeadlineContext;
128
- }
129
- /**
130
- * サーバー権威の締切。
131
- *
132
- * 「state のこの時刻を過ぎたらこれをする」を宣言する。サーバーが `at` の最も早いものに
133
- * 合わせて自分で起き、過ぎた締切の `handler` を呼ぶ。`tickRate` で毎秒ポーリングする
134
- * 必要が無くなり、その間 Durable Object は hibernate できる。
135
- *
136
- * 締切は state から導出するので、予約を張り替える処理を書かなくてよい。action が
137
- * throw して state が巻き戻れば、締切も一緒に巻き戻る。
138
- */
139
- export interface Deadline<S> {
140
- /**
141
- * 締切の絶対時刻 (ms)。締切が無いときは null / undefined。
142
- *
143
- * `state.timer?.endsAt` のような optional chain の結果をそのまま返せるよう
144
- * undefined も受ける。数値以外は「締切なし」として同じに扱う。
145
- *
146
- * state が変わるたびに呼ばれるので、state だけから決まる軽い関数にすること。
147
- * ここで実時刻や乱数を読むと、呼ばれるたびに答えが変わって予約が暴れる。
148
- */
149
- at(args: {
150
- state: S;
151
- }): number | null | undefined;
152
- /**
153
- * `at` の時刻を過ぎたときにサーバーで呼ばれる。
154
- *
155
- * 発火は at-least-once だが、SDK が発火直前に `at` を評価し直して過ぎているものだけを
156
- * 呼ぶので、handler 側で二重発火を弾く必要は無い。
157
- */
158
- handler(args: DeadlineArgs<S>): void;
159
- }
160
- /** `serverActions` handler の実行文脈。サーバーでしか走らないので tick と乱数を渡せる。 */
161
- export interface ServerActionContext {
162
- tick: number;
163
- random: SeededRandom;
164
- /** サーバーの実時刻 (ms)。同じ dispatch の `actions` に渡る `ctx.now` と同一値。 */
165
- now: number;
166
- emit: Emit;
167
- }
168
- /** @deprecated `ServerActionContext` を使う。 */
169
- export type ServerOnlyActionContext = ServerActionContext;
170
- /**
171
- * action handler の引数。
172
- *
173
- * オブジェクトなのは使うものだけ書けるようにするため。`ctx` を入れ子で残しているのは、
174
- * 実行環境が与えるものをひとまとまりで helper へ渡せるようにするため。
175
- */
176
- export interface ActionArgs<S, P = any> {
177
- state: S;
178
- payload: P;
179
- playerId: string;
180
- ctx: ActionContext;
181
- }
182
- /**
183
- * `P` は既定が `any` なので、 注釈のない handler はそのまま動く。 payload の形を
184
- * 書いた handler だけが検査され、 送信側もその型で縛られる。 全部に注釈しないと
185
- * 恩恵が無い、 という移行にならないようにするための既定値。
186
- */
187
- export type ActionHandler<S, P = any> = (args: ActionArgs<S, P>) => void;
188
- /** `serverActions` handler の引数。`ctx` にサーバー限定の tick / random が入る。 */
189
- export interface ServerActionArgs<S, P = any> {
190
- state: S;
191
- payload: P;
192
- playerId: string;
193
- ctx: ServerActionContext;
194
- }
195
- export type ServerActionHandler<S, P = any> = (args: ServerActionArgs<S, P>) => Promise<void> | void;
196
- /** @deprecated `ServerActionHandler` を使う。 */
197
- export type ServerOnlyActionHandlerFn<S> = ServerActionHandler<S>;
198
- /**
199
- * @deprecated `serverActions` フィールドに直接書く。
200
- * `serverOnly()` で wrap された handler。`__serverOnly` brand で識別する。
201
- */
202
- export type ServerOnlyAction<S> = ServerActionHandler<S> & {
203
- readonly __serverOnly: true;
204
- };
205
- /** `update()` の ctx。サーバーでしか走らないので tick / random / playerInputs を持つ。 */
206
- export interface UpdateContext {
207
- random: SeededRandom;
208
- tick: number;
209
- /** サーバーの実時刻 (ms)。update はサーバーでしか走らないので常に正確。 */
210
- now: number;
211
- emit: Emit;
212
- playerInputs: Record<string, Record<string, any>>;
213
- }
214
- export interface UpdateArgs<S> {
215
- state: S;
216
- ctx: UpdateContext;
217
- }
218
- /**
219
- * `setup()` の実行文脈。サーバーでしか走らないので実時刻をそのまま渡せる。
220
- *
221
- * `emit` は無い。まだ誰も購読していない時点なので、鳴らしても届かない。
222
- */
223
- export interface SetupContext {
224
- random: SeededRandom;
225
- /** サーバーの実時刻 (ms)。setup はサーバーでしか走らないので常に正確。 */
226
- now: number;
227
- }
228
- /** `setup()` の引数。 */
229
- export interface SetupArgs {
230
- /** 配役を受け取る参加者。観測者は含まれない。 */
231
- players: Seat[];
232
- ctx: SetupContext;
233
- }
234
- /**
235
- * `actions` の形だけを見る緩い制約。
236
- *
237
- * `Record<string, ActionHandler<S>>` (payload: any) を制約に使うと、 推論時に
238
- * handler 型がそちらへ広げられ payload の型が取り出せなくなる。 payload を
239
- * `any` のままにしてキーと引数の形だけ縛る。
240
- */
241
- export type ActionMap<S> = Record<string, (args: ActionArgs<S, any>) => void>;
242
- /** `serverActions` 用。 ActionMap と同じ理由で payload は any のままにする。 */
243
- export type ServerActionMap<S> = Record<string, (args: ServerActionArgs<S, any>) => Promise<void> | void>;
244
- /** action 名から payload 型を引く表。 注釈のない handler は `any` になる。 */
245
- export type PayloadMap<A> = {
246
- [K in keyof A]: A[K] extends (args: infer G) => any ? G extends {
247
- payload: infer P;
248
- } ? P : never : never;
249
- };
250
- /**
251
- * `inputs` が受け取る送信関数。 action 名と payload の両方が型で縛られる。
252
- *
253
- * payload を一律 optional にすると、 形が必須の action でも省略が通ってしまう。
254
- * payload 型が undefined を含むとき (= 注釈なしの any や明示的に optional) だけ
255
- * 省略できるようにする。
256
- */
257
- export type SendAction<A> = <K extends keyof A & string>(...args: undefined extends PayloadMap<A>[K] ? [type: K, payload?: PayloadMap<A>[K]] : [type: K, payload: PayloadMap<A>[K]]) => void;
258
- export interface GameLogic<S, A extends ActionMap<S> = ActionMap<S>, SA extends ServerActionMap<S> = ServerActionMap<S>> {
259
- setup(args: SetupArgs): S;
260
- /**
261
- * クライアント先読みとサーバーの両方で走る handler。決定的でなければならない。
262
- *
263
- * `serverActions` に同名のキーを置くと、同じ action の「サーバーだけで走る続き」に
264
- * なる。1 つの action を「即座に反映していい部分」と「サーバーが決める部分」へ
265
- * 分けられる (例: 駒の移動は先読み、持ち時間の減算はサーバー)。
266
- */
267
- actions: A;
268
- /**
269
- * サーバーでのみ走る handler。実時刻 / 乱数 / fetch など、クライアント先読みで
270
- * 再現できない処理をここに書く。async 可。
271
- *
272
- * `actions` と同名でも別名でもよい。別名だけに置けば「先読みしない action」
273
- * (旧 `serverOnly()` 相当) になる。
274
- */
275
- serverActions?: SA;
276
- update(args: UpdateArgs<S>): void;
277
- /**
278
- * state 由来の締切。サーバーが `at` の時刻に自分で起きて `handler` を呼ぶ。
279
- *
280
- * 時刻をきっかけに何かを起こすなら `tickRate` で毎秒ポーリングせずこちらを使う。
281
- * ポーリング中は Durable Object が hibernate できない。
282
- */
283
- deadlines?: Record<string, Deadline<S>>;
284
- tickRate?: number;
285
- }
286
- export interface GameConfig<S, A extends ActionMap<S> = ActionMap<S>, SA extends ServerActionMap<S> = ServerActionMap<S>> extends ConnectionCallbacks {
287
- logic: GameLogic<S, A, SA>;
288
- /**
289
- * `mySeatKind` は自分の席種別。roster に自分が居ない (= 観測者) ときに、GM ビューと
290
- * 観戦ビューを出し分けるために使う。他プレイヤーの席種別は渡らない。
291
- */
292
- onState: (state: S, myPlayerId: string, mySeatKind: SeatKind) => void;
293
- inputs: (sendAction: SendAction<A & SA>) => void;
294
- /**
295
- * `emit(name, data)` の購読。 キーごとに `predict` の宣言が必須。
296
- *
297
- * 同じ出来事が二重に実行されないよう、SDK は「先読みで実行した記録」を持ち、
298
- * サーバーから同一の event (name と data が完全一致) が届いたら実行を抑止する。
299
- * したがって `data` には**クライアントとサーバーで必ず同じ値になるもの**だけを
300
- * 入れること。`ctx.now` や乱数 ID を混ぜると一致せず二重実行になる。
301
- */
302
- events?: Record<string, EventSubscription>;
303
- playerCount: number;
304
- /** Dev harness のデフォルト向き。manifest.json の `orientation` を渡す。 */
305
- orientation?: 'portrait' | 'landscape';
306
- /**
307
- * Dev harness で各 iframe inner viewport 短辺の下限 (CSS px)。
308
- * default 360。狭い viewport では親 frame に `body { zoom: N }` を当てて
309
- * iframe 内部の `window.innerWidth/Height` を保証する。
310
- */
311
- devMinIframeShortEdge?: number;
312
- }
313
- export type PatchFn = (ops: Operation[]) => void;
314
- export type SetFn = (path: string, value: unknown) => void;
315
- export interface SyncConfig<S = any> extends ConnectionCallbacks {
316
- initialState: (players: Seat[]) => S;
317
- onState: (state: S, myPlayerId: string, serverTime: number) => void;
318
- inputs: (patch: PatchFn, set: SetFn) => void;
319
- events?: Record<string, (data: Record<string, unknown>) => void>;
320
- playerCount: number;
321
- /** Dev harness のデフォルト向き。manifest.json の `orientation` を渡す。 */
322
- orientation?: 'portrait' | 'landscape';
323
- /**
324
- * Dev harness で各 iframe inner viewport 短辺の下限 (CSS px)。
325
- * default 360。狭い viewport では親 frame に `body { zoom: N }` を当てて
326
- * iframe 内部の `window.innerWidth/Height` を保証する。
327
- */
328
- devMinIframeShortEdge?: number;
329
- }
330
- export interface Operation {
331
- op: 'replace' | 'add' | 'remove';
332
- path: string;
333
- value?: unknown;
334
- }
335
- /** Sentinel value — patch の value にセットすると、サーバーが Date.now() に置換する */
336
- export declare const SERVER_TIME: "__SERVER_TIME__";
337
- /** デフォルトのプレイヤーアイコン URL 一覧(dev / local モード用) */
338
- export declare const DEFAULT_ICON_URLS: readonly ["https://imagedelivery.net/htp-D7B2hJT5XtdWYN9e7Q/4d0da24d-bcf2-4f7b-d1a0-f1bb8c747300/original", "https://imagedelivery.net/htp-D7B2hJT5XtdWYN9e7Q/8c75fccb-41d6-429d-e943-06c728a72a00/original", "https://imagedelivery.net/htp-D7B2hJT5XtdWYN9e7Q/43f45d11-da38-4d6e-637d-3df78e583500/original"];
339
- export type ConnectionState = 'connecting' | 'connected' | 'reconnecting' | 'disconnected';
340
- export interface ConnectionCallbacks {
341
- /** WebSocket 接続状態が変化した時に呼ばれる */
342
- onConnectionStateChange?: (state: ConnectionState) => void;
343
- /** サーバーで patch 適用が失敗した時に呼ばれる (sync モード専用) */
344
- onPatchFailed?: (reason: string) => void;
345
- }
package/dist/types.js DELETED
@@ -1,8 +0,0 @@
1
- /** Sentinel value — patch の value にセットすると、サーバーが Date.now() に置換する */
2
- export const SERVER_TIME = '__SERVER_TIME__';
3
- /** デフォルトのプレイヤーアイコン URL 一覧(dev / local モード用) */
4
- export const DEFAULT_ICON_URLS = [
5
- 'https://imagedelivery.net/htp-D7B2hJT5XtdWYN9e7Q/4d0da24d-bcf2-4f7b-d1a0-f1bb8c747300/original',
6
- 'https://imagedelivery.net/htp-D7B2hJT5XtdWYN9e7Q/8c75fccb-41d6-429d-e943-06c728a72a00/original',
7
- 'https://imagedelivery.net/htp-D7B2hJT5XtdWYN9e7Q/43f45d11-da38-4d6e-637d-3df78e583500/original',
8
- ];