@uzuhq/code-sdk 0.8.9 → 0.8.10
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.
- package/dist/dev-globals.d.ts +1 -1
- package/dist/{dev-hooks-B9mpXwaP.d.ts → dev-hooks-7UDN8Xac.d.ts} +168 -162
- package/dist/index.d.ts +33 -33
- package/dist/index.js +525 -518
- package/package.json +6 -3
package/dist/dev-globals.d.ts
CHANGED
|
@@ -1,81 +1,3 @@
|
|
|
1
|
-
//#region src/dev-state-patch.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* `__uzu_dev.mergeRawState` / `__uzu_dev.patchRawState` の中身。
|
|
4
|
-
* scenario state を「object 階層の部分更新 (RFC 7396)」と「array 要素単体の書換
|
|
5
|
-
* 含む path-based ops (RFC 6902)」で書き換えるための utility。
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* RFC 7396 風 Merge Patch。
|
|
9
|
-
*
|
|
10
|
-
* RFC 7396 strict との差分:
|
|
11
|
-
* - `null` は target 側の **削除ではなく** null をセットする (`timerEndsAt: null`
|
|
12
|
-
* のような nullable field を狙い撃ちするユースケースを優先)
|
|
13
|
-
* - 値を削除したいときは {@link JsonPatchOp} の `remove` を使う
|
|
14
|
-
*
|
|
15
|
-
* Generic は使い手側の type を残すための shape ヒントで、ランタイム上は
|
|
16
|
-
* `Record<string, unknown>` と等価。
|
|
17
|
-
*/
|
|
18
|
-
type JsonMergePatch<S = unknown> = Partial<{ [K in keyof S]: S[K] extends unknown[] ? S[K] : S[K] extends object ? JsonMergePatch<S[K]> : S[K] | null; }> & Record<string, unknown>;
|
|
19
|
-
/**
|
|
20
|
-
* RFC 6902 JSON Patch operation。
|
|
21
|
-
*
|
|
22
|
-
* - `add` / `replace` / `test`: `value` 必須
|
|
23
|
-
* - `remove`: `value` / `from` 不要
|
|
24
|
-
* - `move` / `copy`: `from` 必須 (JSON Pointer)
|
|
25
|
-
* - `path` は JSON Pointer (例: `/board/1/4`、root は空文字)
|
|
26
|
-
*/
|
|
27
|
-
type JsonPatchOp = {
|
|
28
|
-
op: 'add';
|
|
29
|
-
path: string;
|
|
30
|
-
value: unknown;
|
|
31
|
-
} | {
|
|
32
|
-
op: 'remove';
|
|
33
|
-
path: string;
|
|
34
|
-
} | {
|
|
35
|
-
op: 'replace';
|
|
36
|
-
path: string;
|
|
37
|
-
value: unknown;
|
|
38
|
-
} | {
|
|
39
|
-
op: 'move';
|
|
40
|
-
path: string;
|
|
41
|
-
from: string;
|
|
42
|
-
} | {
|
|
43
|
-
op: 'copy';
|
|
44
|
-
path: string;
|
|
45
|
-
from: string;
|
|
46
|
-
} | {
|
|
47
|
-
op: 'test';
|
|
48
|
-
path: string;
|
|
49
|
-
value: unknown;
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* RFC 7396 (Merge Patch) を target に in-place 適用する。
|
|
53
|
-
*
|
|
54
|
-
* 規則:
|
|
55
|
-
* - `undefined` は no-op (key 自体を patch から落としたのと同じ)
|
|
56
|
-
* - `null` は **null をセット** (RFC 7396 strict と異なる、deletion はしない)
|
|
57
|
-
* - patch が object かつ target も object → 再帰 merge
|
|
58
|
-
* - patch が array → atomic replace (要素単位 merge なし、RFC 7396 spec 通り)
|
|
59
|
-
* - patch が primitive → overwrite
|
|
60
|
-
* - **target が array で patch が non-array object** → throw (silent な
|
|
61
|
-
* `[..., ...]` → `{ "0": ..., "1": ... }` 化を防ぐ)
|
|
62
|
-
*
|
|
63
|
-
* 型 mismatch (例: object → primitive) は overwrite で許可する。
|
|
64
|
-
*/
|
|
65
|
-
declare function applyJsonMergePatch(target: Record<string, unknown>, patch: JsonMergePatch): void;
|
|
66
|
-
/**
|
|
67
|
-
* RFC 6902 (JSON Patch) operations を target に in-place 適用する。
|
|
68
|
-
*
|
|
69
|
-
* 1 op でも失敗したら **その時点で throw** する (RFC 6902 spec: operations は
|
|
70
|
-
* sequentially evaluate、失敗時の rollback は規定なし)。caller が atomic に
|
|
71
|
-
* したいなら state を事前に snapshot しておく。
|
|
72
|
-
*
|
|
73
|
-
* root pointer (`''`) は本実装では `add` / `replace` のみ許可し、
|
|
74
|
-
* doc のフィールドを丸ごと差し替える形で動く (= 結局 `setRawState` で十分な
|
|
75
|
-
* ケースなので、わざわざ `patchRawState` で使うことはほぼない)。
|
|
76
|
-
*/
|
|
77
|
-
declare function applyJsonPatch(target: Record<string, unknown>, ops: JsonPatchOp[]): void;
|
|
78
|
-
//#endregion
|
|
79
1
|
//#region ../engine-core/src/game-time.d.ts
|
|
80
2
|
/**
|
|
81
3
|
* @docs
|
|
@@ -141,25 +63,25 @@ declare const GAME_START: GameTime;
|
|
|
141
63
|
* 載らないまま接続してくるので、シナリオは「roster に居ない = 観測者」で判別する。
|
|
142
64
|
* 席種別は roster エントリではなく自分の `SeatKind` として渡る。
|
|
143
65
|
*/
|
|
144
|
-
|
|
66
|
+
type Seat = {
|
|
145
67
|
id: string;
|
|
146
68
|
nickname: string;
|
|
147
69
|
iconUrl: string;
|
|
148
70
|
/** ホスト(mobile / emulator)から渡される、選択済みキャラクターの ID。未選択時は undefined。 */
|
|
149
71
|
characterId?: string;
|
|
150
|
-
}
|
|
72
|
+
};
|
|
151
73
|
type Emit = (eventName: string, data?: Record<string, unknown>) => void;
|
|
152
74
|
/** dev harness で観測される 1 件の emit。`data` は `emit(name)` 省略時に空 object になる。 */
|
|
153
|
-
|
|
75
|
+
type ServerEvent = {
|
|
154
76
|
name: string;
|
|
155
77
|
data: Record<string, unknown>;
|
|
156
|
-
}
|
|
157
|
-
|
|
78
|
+
};
|
|
79
|
+
type SeededRandom = {
|
|
158
80
|
float(): number;
|
|
159
81
|
int(max: number): number;
|
|
160
82
|
pick<T>(array: T[]): T;
|
|
161
83
|
shuffle<T>(array: T[]): T[];
|
|
162
|
-
}
|
|
84
|
+
};
|
|
163
85
|
/**
|
|
164
86
|
* 素の action handler の実行文脈。空なのは意図的。
|
|
165
87
|
*
|
|
@@ -168,7 +90,7 @@ interface SeededRandom {
|
|
|
168
90
|
* オンラインの先読みだけ値がズレる、という一番気付きにくい形で壊れる。
|
|
169
91
|
* そういう値が要る処理は `serverActions` 側に書く。
|
|
170
92
|
*/
|
|
171
|
-
|
|
93
|
+
type ActionContext = {
|
|
172
94
|
/**
|
|
173
95
|
* 現在のゲーム内時刻。先読みではクロックオフセットからの推定値。
|
|
174
96
|
*
|
|
@@ -181,21 +103,21 @@ interface ActionContext {
|
|
|
181
103
|
/** 今から `d` ms 後のゲーム内時刻。締切を state へ置くときに使う。 */
|
|
182
104
|
after(d: Duration): GameTime;
|
|
183
105
|
emit: Emit;
|
|
184
|
-
}
|
|
106
|
+
};
|
|
185
107
|
/** `deadlines` handler の実行文脈。サーバーでしか走らないので tick 以外を渡せる。 */
|
|
186
|
-
|
|
108
|
+
type DeadlineContext = {
|
|
187
109
|
/** 発火時点のゲーム内時刻。サーバー専用なので常に正確。 */
|
|
188
110
|
time: GameTime;
|
|
189
111
|
/** 今から `d` ms 後のゲーム内時刻。次の締切を state へ置き直すときに使う。 */
|
|
190
112
|
after(d: Duration): GameTime;
|
|
191
113
|
random: SeededRandom;
|
|
192
114
|
emit: Emit;
|
|
193
|
-
}
|
|
115
|
+
};
|
|
194
116
|
/** `deadlines` handler の引数。 */
|
|
195
|
-
|
|
117
|
+
type DeadlineArgs<S> = {
|
|
196
118
|
state: S;
|
|
197
119
|
ctx: DeadlineContext;
|
|
198
|
-
}
|
|
120
|
+
};
|
|
199
121
|
/**
|
|
200
122
|
* サーバー権威の締切。
|
|
201
123
|
*
|
|
@@ -206,7 +128,7 @@ interface DeadlineArgs<S> {
|
|
|
206
128
|
* 締切は state から導出するので、予約を張り替える処理を書かなくてよい。action が
|
|
207
129
|
* throw して state が巻き戻れば、締切も一緒に巻き戻る。
|
|
208
130
|
*/
|
|
209
|
-
|
|
131
|
+
type Deadline<S> = {
|
|
210
132
|
/**
|
|
211
133
|
* 締切のゲーム内時刻。締切が無いときは null / undefined。
|
|
212
134
|
*
|
|
@@ -230,9 +152,9 @@ interface Deadline<S> {
|
|
|
230
152
|
* 呼ぶので、handler 側で二重発火を弾く必要は無い。
|
|
231
153
|
*/
|
|
232
154
|
handler(args: DeadlineArgs<S>): void;
|
|
233
|
-
}
|
|
155
|
+
};
|
|
234
156
|
/** `serverActions` handler の実行文脈。サーバーでしか走らないので tick と乱数を渡せる。 */
|
|
235
|
-
|
|
157
|
+
type ServerActionContext = {
|
|
236
158
|
tick: number;
|
|
237
159
|
random: SeededRandom;
|
|
238
160
|
/** 現在のゲーム内時刻。同じ dispatch の `actions` に渡る `ctx.time` と同一値。 */
|
|
@@ -240,7 +162,7 @@ interface ServerActionContext {
|
|
|
240
162
|
/** 今から `d` ms 後のゲーム内時刻。 */
|
|
241
163
|
after(d: Duration): GameTime;
|
|
242
164
|
emit: Emit;
|
|
243
|
-
}
|
|
165
|
+
};
|
|
244
166
|
/** @deprecated `ServerActionContext` を使う。 */
|
|
245
167
|
type ServerOnlyActionContext = ServerActionContext;
|
|
246
168
|
/**
|
|
@@ -249,12 +171,12 @@ type ServerOnlyActionContext = ServerActionContext;
|
|
|
249
171
|
* オブジェクトなのは使うものだけ書けるようにするため。`ctx` を入れ子で残しているのは、
|
|
250
172
|
* 実行環境が与えるものをひとまとまりで helper へ渡せるようにするため。
|
|
251
173
|
*/
|
|
252
|
-
|
|
174
|
+
type ActionArgs<S, P = any> = {
|
|
253
175
|
state: S;
|
|
254
176
|
payload: P;
|
|
255
177
|
playerId: string;
|
|
256
178
|
ctx: ActionContext;
|
|
257
|
-
}
|
|
179
|
+
};
|
|
258
180
|
/**
|
|
259
181
|
* `P` は既定が `any` なので、 注釈のない handler はそのまま動く。 payload の形を
|
|
260
182
|
* 書いた handler だけが検査され、 送信側もその型で縛られる。 全部に注釈しないと
|
|
@@ -262,12 +184,12 @@ interface ActionArgs<S, P = any> {
|
|
|
262
184
|
*/
|
|
263
185
|
type ActionHandler<S, P = any> = (args: ActionArgs<S, P>) => void;
|
|
264
186
|
/** `serverActions` handler の引数。`ctx` にサーバー限定の tick / random が入る。 */
|
|
265
|
-
|
|
187
|
+
type ServerActionArgs<S, P = any> = {
|
|
266
188
|
state: S;
|
|
267
189
|
payload: P;
|
|
268
190
|
playerId: string;
|
|
269
191
|
ctx: ServerActionContext;
|
|
270
|
-
}
|
|
192
|
+
};
|
|
271
193
|
type ServerActionHandler<S, P = any> = (args: ServerActionArgs<S, P>) => Promise<void> | void;
|
|
272
194
|
/** @deprecated `ServerActionHandler` を使う。 */
|
|
273
195
|
type ServerOnlyActionHandlerFn<S> = ServerActionHandler<S>;
|
|
@@ -278,8 +200,14 @@ type ServerOnlyActionHandlerFn<S> = ServerActionHandler<S>;
|
|
|
278
200
|
type ServerOnlyAction<S> = ServerActionHandler<S> & {
|
|
279
201
|
readonly __serverOnly: true;
|
|
280
202
|
};
|
|
203
|
+
/**
|
|
204
|
+
* プレイヤーごとの、直近に届いた `__input` の中身。値の形はシナリオが決める。
|
|
205
|
+
*
|
|
206
|
+
* `update()` の ctx と、それを組み立てる各ランタイムが同じ型を見るために名前を付けてある。
|
|
207
|
+
*/
|
|
208
|
+
type PlayerInputs = Record<string, Record<string, any>>;
|
|
281
209
|
/** `update()` の ctx。サーバーでしか走らないので tick / random / playerInputs を持つ。 */
|
|
282
|
-
|
|
210
|
+
type UpdateContext = {
|
|
283
211
|
random: SeededRandom;
|
|
284
212
|
tick: number;
|
|
285
213
|
/** 現在のゲーム内時刻。update はサーバーでしか走らないので常に正確。 */
|
|
@@ -287,30 +215,30 @@ interface UpdateContext {
|
|
|
287
215
|
/** 今から `d` ms 後のゲーム内時刻。 */
|
|
288
216
|
after(d: Duration): GameTime;
|
|
289
217
|
emit: Emit;
|
|
290
|
-
playerInputs:
|
|
291
|
-
}
|
|
292
|
-
|
|
218
|
+
playerInputs: PlayerInputs;
|
|
219
|
+
};
|
|
220
|
+
type UpdateArgs<S> = {
|
|
293
221
|
state: S;
|
|
294
222
|
ctx: UpdateContext;
|
|
295
|
-
}
|
|
223
|
+
};
|
|
296
224
|
/**
|
|
297
225
|
* `setup()` の実行文脈。サーバーでしか走らないので実時刻をそのまま渡せる。
|
|
298
226
|
*
|
|
299
227
|
* `emit` は無い。まだ誰も購読していない時点なので、鳴らしても届かない。
|
|
300
228
|
*/
|
|
301
|
-
|
|
229
|
+
type SetupContext = {
|
|
302
230
|
random: SeededRandom;
|
|
303
231
|
/** ゲーム内時刻。setup は時計の起点なので必ず `0`。 */
|
|
304
232
|
time: GameTime;
|
|
305
233
|
/** 今から `d` ms 後のゲーム内時刻。setup では `d` そのものになる。 */
|
|
306
234
|
after(d: Duration): GameTime;
|
|
307
|
-
}
|
|
235
|
+
};
|
|
308
236
|
/** `setup()` の引数。 */
|
|
309
|
-
|
|
237
|
+
type SetupArgs = {
|
|
310
238
|
/** 配役を受け取る参加者。観測者は含まれない。 */
|
|
311
239
|
players: Seat[];
|
|
312
240
|
ctx: SetupContext;
|
|
313
|
-
}
|
|
241
|
+
};
|
|
314
242
|
/**
|
|
315
243
|
* `actions` の形だけを見る緩い制約。
|
|
316
244
|
*
|
|
@@ -321,7 +249,7 @@ interface SetupArgs {
|
|
|
321
249
|
type ActionMap<S> = Record<string, (args: ActionArgs<S, any>) => void>;
|
|
322
250
|
/** `serverActions` 用。 ActionMap と同じ理由で payload は any のままにする。 */
|
|
323
251
|
type ServerActionMap<S> = Record<string, (args: ServerActionArgs<S, any>) => Promise<void> | void>;
|
|
324
|
-
|
|
252
|
+
type GameLogic<S, A extends ActionMap<S> = ActionMap<S>, SA extends ServerActionMap<S> = ServerActionMap<S>> = {
|
|
325
253
|
setup(args: SetupArgs): S;
|
|
326
254
|
/**
|
|
327
255
|
* クライアント先読みとサーバーの両方で走る handler。決定的でなければならない。
|
|
@@ -348,7 +276,7 @@ interface GameLogic<S, A extends ActionMap<S> = ActionMap<S>, SA extends ServerA
|
|
|
348
276
|
*/
|
|
349
277
|
deadlines?: Record<string, Deadline<S>>;
|
|
350
278
|
tickRate?: number;
|
|
351
|
-
}
|
|
279
|
+
};
|
|
352
280
|
/** デフォルトのプレイヤーアイコン URL 一覧(dev / local モード用) */
|
|
353
281
|
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"];
|
|
354
282
|
//#endregion
|
|
@@ -361,7 +289,7 @@ type PlayScreenMessage = {
|
|
|
361
289
|
/** ブリッジメッセージのチャンネル */
|
|
362
290
|
type BridgeChannel = 'sdk' | 'game';
|
|
363
291
|
/** ワイヤーフォーマット: { channel, type, payload, playerId? } */
|
|
364
|
-
|
|
292
|
+
type BridgeMessage = {
|
|
365
293
|
channel: BridgeChannel;
|
|
366
294
|
type: string;
|
|
367
295
|
payload: Record<string, unknown>;
|
|
@@ -377,7 +305,7 @@ interface BridgeMessage {
|
|
|
377
305
|
* (受信側は playerId 無し = 旧 SDK ビルドとして扱う)。
|
|
378
306
|
*/
|
|
379
307
|
playerId?: string;
|
|
380
|
-
}
|
|
308
|
+
};
|
|
381
309
|
/**
|
|
382
310
|
* 自分の席種別。ホストが iframe URL の `?seatKind=` で伝える。
|
|
383
311
|
*
|
|
@@ -390,14 +318,14 @@ interface BridgeMessage {
|
|
|
390
318
|
*/
|
|
391
319
|
type SeatKind = 'player' | 'spectator' | 'admin';
|
|
392
320
|
/** プレイヤーごとのリアルタイム状態 */
|
|
393
|
-
|
|
321
|
+
type PlayerVoiceState = {
|
|
394
322
|
/** 音声状態。音声通話に未接続の場合は null */
|
|
395
323
|
audioStatus: 'speaking' | 'listening' | 'muted' | 'unstable' | null;
|
|
396
|
-
}
|
|
324
|
+
};
|
|
397
325
|
/** @deprecated 旧形式。新コードでは onPlayersChanged() と PlayerVoiceState を使用 */
|
|
398
|
-
|
|
326
|
+
type PlayersChangedMessage = {
|
|
399
327
|
players: Record<string, PlayerVoiceState>;
|
|
400
|
-
}
|
|
328
|
+
};
|
|
401
329
|
/**
|
|
402
330
|
* events handler。
|
|
403
331
|
*
|
|
@@ -411,13 +339,13 @@ type EventHandler = (data: Record<string, unknown>) => void;
|
|
|
411
339
|
* 先読みは外れることがあり、実行してしまったものは取り消せない。取り消せない副作用
|
|
412
340
|
* (analytics / 実績解除 / 長い演出) は必ず `predict: false` にすること。
|
|
413
341
|
*/
|
|
414
|
-
|
|
342
|
+
type EventSubscription = {
|
|
415
343
|
/** 先読み時点で実行してよいか。宣言必須。 */
|
|
416
344
|
predict: boolean;
|
|
417
345
|
handler: EventHandler;
|
|
418
|
-
}
|
|
346
|
+
};
|
|
419
347
|
/** action 名から payload 型を引く表。 注釈のない handler は `any` になる。 */
|
|
420
|
-
type PayloadMap<A> = { [K in keyof A]: A[K] extends ((args: infer G) =>
|
|
348
|
+
type PayloadMap<A> = { [K in keyof A]: A[K] extends ((args: infer G) => unknown) ? G extends {
|
|
421
349
|
payload: infer P;
|
|
422
350
|
} ? P : never : never; };
|
|
423
351
|
/**
|
|
@@ -428,7 +356,7 @@ type PayloadMap<A> = { [K in keyof A]: A[K] extends ((args: infer G) => any) ? G
|
|
|
428
356
|
* 省略できるようにする。
|
|
429
357
|
*/
|
|
430
358
|
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;
|
|
431
|
-
|
|
359
|
+
type GameConfig<S, A extends ActionMap<S> = ActionMap<S>, SA extends ServerActionMap<S> = ServerActionMap<S>> = {
|
|
432
360
|
logic: GameLogic<S, A, SA>;
|
|
433
361
|
/**
|
|
434
362
|
* `mySeatKind` は自分の席種別。roster に自分が居ない (= 観測者) ときに、GM ビューと
|
|
@@ -454,12 +382,12 @@ interface GameConfig<S, A extends ActionMap<S> = ActionMap<S>, SA extends Server
|
|
|
454
382
|
* iframe 内部の `window.innerWidth/Height` を保証する。
|
|
455
383
|
*/
|
|
456
384
|
devMinIframeShortEdge?: number;
|
|
457
|
-
}
|
|
385
|
+
} & ConnectionCallbacks;
|
|
458
386
|
type ConnectionState = 'connecting' | 'connected' | 'reconnecting' | 'disconnected';
|
|
459
|
-
|
|
387
|
+
type ConnectionCallbacks = {
|
|
460
388
|
/** WebSocket 接続状態が変化した時に呼ばれる */
|
|
461
389
|
onConnectionStateChange?: (state: ConnectionState) => void;
|
|
462
|
-
}
|
|
390
|
+
};
|
|
463
391
|
//#endregion
|
|
464
392
|
//#region src/host-globals.d.ts
|
|
465
393
|
declare global {
|
|
@@ -474,36 +402,114 @@ declare global {
|
|
|
474
402
|
}
|
|
475
403
|
//#endregion
|
|
476
404
|
//#region src/dev-prediction-traps.d.ts
|
|
477
|
-
|
|
405
|
+
type PredictionWarning = {
|
|
478
406
|
/** 呼び出した action 名。描画経路では `'(render)'`。 */
|
|
479
407
|
action: string;
|
|
480
408
|
/** 呼ばれた API 名 (`'Date.now()'` など) */
|
|
481
409
|
api: string;
|
|
482
|
-
}
|
|
410
|
+
};
|
|
483
411
|
/** 検出済みの警告一覧。`__uzu_dev.getPredictionWarnings()` から E2E で assert する用。 */
|
|
484
412
|
declare const getPredictionWarnings: () => readonly PredictionWarning[];
|
|
485
413
|
//#endregion
|
|
414
|
+
//#region src/dev-state-patch.d.ts
|
|
415
|
+
/**
|
|
416
|
+
* `__uzu_dev.mergeRawState` / `__uzu_dev.patchRawState` の中身。
|
|
417
|
+
* scenario state を「object 階層の部分更新 (RFC 7396)」と「array 要素単体の書換
|
|
418
|
+
* 含む path-based ops (RFC 6902)」で書き換えるための utility。
|
|
419
|
+
*/
|
|
420
|
+
/**
|
|
421
|
+
* RFC 7396 風 Merge Patch。
|
|
422
|
+
*
|
|
423
|
+
* RFC 7396 strict との差分:
|
|
424
|
+
* - `null` は target 側の **削除ではなく** null をセットする (`timerEndsAt: null`
|
|
425
|
+
* のような nullable field を狙い撃ちするユースケースを優先)
|
|
426
|
+
* - 値を削除したいときは {@link JsonPatchOp} の `remove` を使う
|
|
427
|
+
*
|
|
428
|
+
* Generic は使い手側の type を残すための shape ヒントで、ランタイム上は
|
|
429
|
+
* `Record<string, unknown>` と等価。
|
|
430
|
+
*/
|
|
431
|
+
type JsonMergePatch<S = unknown> = Partial<{ [K in keyof S]: S[K] extends unknown[] ? S[K] : S[K] extends object ? JsonMergePatch<S[K]> : S[K] | null; }> & Record<string, unknown>;
|
|
432
|
+
/**
|
|
433
|
+
* RFC 6902 JSON Patch operation。
|
|
434
|
+
*
|
|
435
|
+
* - `add` / `replace` / `test`: `value` 必須
|
|
436
|
+
* - `remove`: `value` / `from` 不要
|
|
437
|
+
* - `move` / `copy`: `from` 必須 (JSON Pointer)
|
|
438
|
+
* - `path` は JSON Pointer (例: `/board/1/4`、root は空文字)
|
|
439
|
+
*/
|
|
440
|
+
type JsonPatchOp = {
|
|
441
|
+
op: 'add';
|
|
442
|
+
path: string;
|
|
443
|
+
value: unknown;
|
|
444
|
+
} | {
|
|
445
|
+
op: 'remove';
|
|
446
|
+
path: string;
|
|
447
|
+
} | {
|
|
448
|
+
op: 'replace';
|
|
449
|
+
path: string;
|
|
450
|
+
value: unknown;
|
|
451
|
+
} | {
|
|
452
|
+
op: 'move';
|
|
453
|
+
path: string;
|
|
454
|
+
from: string;
|
|
455
|
+
} | {
|
|
456
|
+
op: 'copy';
|
|
457
|
+
path: string;
|
|
458
|
+
from: string;
|
|
459
|
+
} | {
|
|
460
|
+
op: 'test';
|
|
461
|
+
path: string;
|
|
462
|
+
value: unknown;
|
|
463
|
+
};
|
|
464
|
+
/**
|
|
465
|
+
* RFC 7396 (Merge Patch) を target に in-place 適用する。
|
|
466
|
+
*
|
|
467
|
+
* 規則:
|
|
468
|
+
* - `undefined` は no-op (key 自体を patch から落としたのと同じ)
|
|
469
|
+
* - `null` は **null をセット** (RFC 7396 strict と異なる、deletion はしない)
|
|
470
|
+
* - patch が object かつ target も object → 再帰 merge
|
|
471
|
+
* - patch が array → atomic replace (要素単位 merge なし、RFC 7396 spec 通り)
|
|
472
|
+
* - patch が primitive → overwrite
|
|
473
|
+
* - **target が array で patch が non-array object** → throw (silent な
|
|
474
|
+
* `[..., ...]` → `{ "0": ..., "1": ... }` 化を防ぐ)
|
|
475
|
+
*
|
|
476
|
+
* 型 mismatch (例: object → primitive) は overwrite で許可する。
|
|
477
|
+
*/
|
|
478
|
+
declare const applyJsonMergePatch: (target: Record<string, unknown>, patch: JsonMergePatch) => void;
|
|
479
|
+
/**
|
|
480
|
+
* RFC 6902 (JSON Patch) operations を target に in-place 適用する。
|
|
481
|
+
*
|
|
482
|
+
* 1 op でも失敗したら **その時点で throw** する (RFC 6902 spec: operations は
|
|
483
|
+
* sequentially evaluate、失敗時の rollback は規定なし)。caller が atomic に
|
|
484
|
+
* したいなら state を事前に snapshot しておく。
|
|
485
|
+
*
|
|
486
|
+
* root pointer (`''`) は本実装では `add` / `replace` のみ許可し、
|
|
487
|
+
* doc のフィールドを丸ごと差し替える形で動く (= 結局 `setRawState` で十分な
|
|
488
|
+
* ケースなので、わざわざ `patchRawState` で使うことはほぼない)。
|
|
489
|
+
*/
|
|
490
|
+
declare const applyJsonPatch: (target: Record<string, unknown>, ops: JsonPatchOp[]) => void;
|
|
491
|
+
//#endregion
|
|
486
492
|
//#region src/dev-hooks.d.ts
|
|
487
|
-
|
|
493
|
+
type UzuDevHooks<S = unknown> = {
|
|
488
494
|
/** 現在の per-player 視点 snapshot (onState コールバックの最新値)。未初期化なら null。 */
|
|
489
|
-
getSnapshot()
|
|
495
|
+
getSnapshot: () => unknown;
|
|
490
496
|
/** 生 server-side state (dev/local mode のみ。online ServerAction では null)。 */
|
|
491
|
-
getRawState()
|
|
492
|
-
playerId()
|
|
497
|
+
getRawState: () => S | null;
|
|
498
|
+
playerId: () => string | null;
|
|
493
499
|
/**
|
|
494
500
|
* 親 frame で virtual server を実体化した時の seed。
|
|
495
501
|
* 親 frame の `runDevHarness({ server })` 経由でしか attach されず、子 iframe の
|
|
496
502
|
* dev hooks 側では undefined。bug report 用に `?__dev_seed=<value>` として
|
|
497
503
|
* 貼り付けやすい uint32 を返す。
|
|
498
504
|
*/
|
|
499
|
-
getSeed
|
|
505
|
+
getSeed?: () => number;
|
|
500
506
|
/**
|
|
501
507
|
* 素の action handler が先読み実行中に実時刻 / 乱数を読んだ記録。
|
|
502
508
|
*
|
|
503
509
|
* 先読みはサーバーと同じ結果を再現できることが前提なので、ここに何か入っていたら
|
|
504
510
|
* そのシナリオはオンラインでだけ予測がズレる。E2E で `[]` を assert すると回帰を防げる。
|
|
505
511
|
*/
|
|
506
|
-
getPredictionWarnings()
|
|
512
|
+
getPredictionWarnings: () => readonly PredictionWarning[];
|
|
507
513
|
/**
|
|
508
514
|
* Server-side で action を直接 dispatch する。
|
|
509
515
|
*
|
|
@@ -517,11 +523,11 @@ interface UzuDevHooks<S = unknown> {
|
|
|
517
523
|
* 運用も可)。turn-based の E2E (将棋・人狼・カードゲーム) で「先手 → 後手」
|
|
518
524
|
* を 1 frame から打ち分けたい時に使う。
|
|
519
525
|
*/
|
|
520
|
-
send
|
|
526
|
+
send?: (args: {
|
|
521
527
|
as: string;
|
|
522
528
|
type: string;
|
|
523
529
|
payload?: Record<string, unknown>;
|
|
524
|
-
})
|
|
530
|
+
}) => Promise<void>;
|
|
525
531
|
/**
|
|
526
532
|
* 生 state を **全置換** する。state owner の frame (= dev/local) のみ。
|
|
527
533
|
*
|
|
@@ -530,7 +536,7 @@ interface UzuDevHooks<S = unknown> {
|
|
|
530
536
|
* 部分更新は {@link mergeRawState} を、array 要素単体の書換は
|
|
531
537
|
* {@link patchRawState} を使うこと。
|
|
532
538
|
*/
|
|
533
|
-
setRawState
|
|
539
|
+
setRawState?: (state: S) => Promise<void>;
|
|
534
540
|
/**
|
|
535
541
|
* RFC 7396 風 JSON Merge Patch で生 state を部分更新する (dev/local のみ)。
|
|
536
542
|
*
|
|
@@ -542,7 +548,7 @@ interface UzuDevHooks<S = unknown> {
|
|
|
542
548
|
* array が pure object に化ける silent な破壊を防ぐため、`array に
|
|
543
549
|
* non-array object patch を当てる`と **throw** する。
|
|
544
550
|
*/
|
|
545
|
-
mergeRawState
|
|
551
|
+
mergeRawState?: (patch: JsonMergePatch<S>) => Promise<void>;
|
|
546
552
|
/**
|
|
547
553
|
* RFC 6902 JSON Patch (path-based ops) で生 state を更新する (dev/local のみ)。
|
|
548
554
|
*
|
|
@@ -552,7 +558,7 @@ interface UzuDevHooks<S = unknown> {
|
|
|
552
558
|
*
|
|
553
559
|
* 局面の部分更新 (将棋の一手・盤面の cell 単体書換など) に使う。
|
|
554
560
|
*/
|
|
555
|
-
patchRawState
|
|
561
|
+
patchRawState?: (ops: JsonPatchOp[]) => Promise<void>;
|
|
556
562
|
/**
|
|
557
563
|
* snapshot 更新を event-driven に listen する。返り値は unsubscribe 関数。
|
|
558
564
|
*
|
|
@@ -563,11 +569,11 @@ interface UzuDevHooks<S = unknown> {
|
|
|
563
569
|
* cb には authoritative state の生参照 (run devHarness 親では `getRawState()` と
|
|
564
570
|
* 同一) が渡るので mutate しない。
|
|
565
571
|
*/
|
|
566
|
-
subscribeSnapshot(cb: (snapshot: unknown) => void)
|
|
572
|
+
subscribeSnapshot: (cb: (snapshot: unknown) => void) => () => void;
|
|
567
573
|
/** snapshot が predicate を満たすまで待つ。default 10 秒 timeout。 */
|
|
568
|
-
waitForSnapshot(predicate: (snapshot: unknown) => boolean, options?: {
|
|
574
|
+
waitForSnapshot: (predicate: (snapshot: unknown) => boolean, options?: {
|
|
569
575
|
timeoutMs?: number;
|
|
570
|
-
})
|
|
576
|
+
}) => Promise<unknown>;
|
|
571
577
|
/**
|
|
572
578
|
* action handler / `logic.update` の `emit` を listen する。callback には 1 回の
|
|
573
579
|
* dispatch / tick 内で発火した event を batch でまとめて渡す。**run devHarness 親
|
|
@@ -578,7 +584,7 @@ interface UzuDevHooks<S = unknown> {
|
|
|
578
584
|
* したい場合に使う。`config.events` callback とは独立経路で、scenario callback の
|
|
579
585
|
* throw も subscriber 通知を止めない。unsubscribe 関数を返す。
|
|
580
586
|
*/
|
|
581
|
-
subscribeEvents
|
|
587
|
+
subscribeEvents?: (cb: (events: readonly ServerEvent[]) => void) => () => void;
|
|
582
588
|
/**
|
|
583
589
|
* tick loop を pause する (run() devHarness 親 frame のみ)。
|
|
584
590
|
* 時間駆動の `logic.update` が走らなくなり、shogi の持ち時間減算等の自動進行を
|
|
@@ -586,15 +592,15 @@ interface UzuDevHooks<S = unknown> {
|
|
|
586
592
|
* tick loop を持たない frame (子 iframe / sync 単独 frame / online) と
|
|
587
593
|
* `tickRate <= 0` の scenario では undefined / no-op。
|
|
588
594
|
*/
|
|
589
|
-
pauseTick
|
|
595
|
+
pauseTick?: () => void;
|
|
590
596
|
/** pauseTick を解除する。 */
|
|
591
|
-
resumeTick
|
|
597
|
+
resumeTick?: () => void;
|
|
592
598
|
/** 手動で n tick 進める。default n = 1。 */
|
|
593
|
-
stepTick
|
|
599
|
+
stepTick?: (n?: number) => void;
|
|
594
600
|
/** 現在の tick 値を返す。tick loop を持たない frame では undefined。 */
|
|
595
|
-
getCurrentTick
|
|
601
|
+
getCurrentTick?: () => number;
|
|
596
602
|
/** pauseTick で止まっているかどうか。 */
|
|
597
|
-
isTickPaused
|
|
603
|
+
isTickPaused?: () => boolean;
|
|
598
604
|
/**
|
|
599
605
|
* `logic.setup` を再実行して virtual server を fresh start させる。
|
|
600
606
|
* run() devHarness の親 frame のみ attach される (state owner でしか reset 不可)。
|
|
@@ -605,10 +611,10 @@ interface UzuDevHooks<S = unknown> {
|
|
|
605
611
|
*
|
|
606
612
|
* pause 状態は維持される。`logic.setup` が副作用を持つ場合は再呼出で副作用が再発火する。
|
|
607
613
|
*/
|
|
608
|
-
reset
|
|
614
|
+
reset?: (opts?: {
|
|
609
615
|
seed?: number | 'random';
|
|
610
|
-
})
|
|
611
|
-
}
|
|
616
|
+
}) => void;
|
|
617
|
+
};
|
|
612
618
|
declare global {
|
|
613
619
|
interface Window {
|
|
614
620
|
__uzu_dev?: UzuDevHooks;
|
|
@@ -621,23 +627,23 @@ declare global {
|
|
|
621
627
|
*
|
|
622
628
|
* state 書き換え API は state owner frame のみ提供する。
|
|
623
629
|
*/
|
|
624
|
-
|
|
630
|
+
type RunHandle<S = unknown> = {
|
|
625
631
|
/** 内部 state の getter (dev hooks 用)。host iframe を持たない側では undefined */
|
|
626
|
-
getRawState
|
|
632
|
+
getRawState?: () => S | null;
|
|
627
633
|
/** 生 state 全置換。host iframe を持たない側では undefined */
|
|
628
|
-
setRawState
|
|
634
|
+
setRawState?: (state: S) => Promise<void>;
|
|
629
635
|
/** RFC 7396 風 Merge Patch。host iframe を持たない側では undefined */
|
|
630
|
-
mergeRawState
|
|
636
|
+
mergeRawState?: (patch: JsonMergePatch<S>) => Promise<void>;
|
|
631
637
|
/** RFC 6902 JSON Patch。host iframe を持たない側では undefined */
|
|
632
|
-
patchRawState
|
|
638
|
+
patchRawState?: (ops: JsonPatchOp[]) => Promise<void>;
|
|
633
639
|
/** 既存 inputs と同等の action 送信 (dev hooks 用) */
|
|
634
|
-
sendAction(type: string, payload?: Record<string, unknown>)
|
|
635
|
-
}
|
|
640
|
+
sendAction: (type: string, payload?: Record<string, unknown>) => void;
|
|
641
|
+
};
|
|
636
642
|
/**
|
|
637
643
|
* dev-hooks.ts から見た「SDK 内部のコンテキスト」。
|
|
638
644
|
* 各 run/* モジュールがこの形の handle を組み立てて attachDevHooks に渡す。
|
|
639
645
|
*/
|
|
640
|
-
|
|
646
|
+
type DevHooksCtx<S = unknown> = {
|
|
641
647
|
/** 最新 snapshot (per-player view)。未初期化なら null。 */
|
|
642
648
|
getSnapshot(): unknown;
|
|
643
649
|
/** 生 state getter (dev/local mode のみ)。 */
|
|
@@ -655,11 +661,11 @@ interface DevHooksCtx<S = unknown> {
|
|
|
655
661
|
* 提供する。それ以外のモードでは省略 (= `__uzu_dev.send` も生えない)。
|
|
656
662
|
* `args.as` で server-side dispatch の `from` を指定する (必須)。
|
|
657
663
|
*/
|
|
658
|
-
sendAction
|
|
664
|
+
sendAction?: (args: {
|
|
659
665
|
as: string;
|
|
660
666
|
type: string;
|
|
661
667
|
payload?: Record<string, unknown>;
|
|
662
|
-
})
|
|
668
|
+
}) => Promise<void>;
|
|
663
669
|
/** snapshot 更新を listen する。unsubscribe 関数を返す。 */
|
|
664
670
|
subscribeSnapshot(cb: (snapshot: unknown) => void): () => void;
|
|
665
671
|
/**
|
|
@@ -667,7 +673,7 @@ interface DevHooksCtx<S = unknown> {
|
|
|
667
673
|
* frame の `DevHostHandle` のみが提供する。それ以外のモードでは省略
|
|
668
674
|
* (= `__uzu_dev.subscribeEvents` も生えない)。
|
|
669
675
|
*/
|
|
670
|
-
subscribeEvents
|
|
676
|
+
subscribeEvents?: (cb: (events: readonly ServerEvent[]) => void) => () => void;
|
|
671
677
|
/** dev harness 親 frame の virtual server seed。親 attach 経路のみ。 */
|
|
672
678
|
getSeed?: () => number;
|
|
673
679
|
pauseTick?: () => void;
|
|
@@ -682,8 +688,8 @@ interface DevHooksCtx<S = unknown> {
|
|
|
682
688
|
reset?: (opts?: {
|
|
683
689
|
seed?: number | 'random';
|
|
684
690
|
}) => void;
|
|
685
|
-
}
|
|
686
|
-
declare
|
|
687
|
-
declare
|
|
691
|
+
};
|
|
692
|
+
declare const createDevHooks: <S>(ctx: DevHooksCtx<S>) => UzuDevHooks<S>;
|
|
693
|
+
declare const attachDevHooks: <S>(ctx: DevHooksCtx<S>) => void;
|
|
688
694
|
//#endregion
|
|
689
|
-
export {
|
|
695
|
+
export { plus as $, Deadline as A, ServerActionMap as B, SeatKind as C, ActionHandler as D, ActionContext as E, Seat as F, SetupArgs as G, ServerOnlyAction as H, SeededRandom as I, UpdateContext as J, SetupContext as K, ServerActionArgs as L, DeadlineContext as M, Emit as N, ActionMap as O, GameLogic as P, minus as Q, ServerActionContext as R, PlayersChangedMessage as S, ActionArgs as T, ServerOnlyActionContext as U, ServerEvent as V, ServerOnlyActionHandlerFn as W, GAME_START as X, Duration as Y, GameTime as Z, EventSubscription as _, createDevHooks as a, PlayScreenMessage as b, applyJsonMergePatch as c, getPredictionWarnings as d, sub as et, BridgeChannel as f, EventHandler as g, ConnectionState as h, attachDevHooks as i, DeadlineArgs as j, DEFAULT_ICON_URLS as k, applyJsonPatch as l, ConnectionCallbacks as m, RunHandle as n, JsonMergePatch as o, BridgeMessage as p, UpdateArgs as q, UzuDevHooks as r, JsonPatchOp as s, DevHooksCtx as t, PredictionWarning as u, GameConfig as v, SendAction as w, PlayerVoiceState as x, PayloadMap as y, ServerActionHandler as z };
|