def-game 6.0.0-alpha.0 → 6.1.0

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/README.md CHANGED
@@ -5,10 +5,10 @@
5
5
 
6
6
  ## Getting Started
7
7
 
8
- Node.js 22以降が必要です。v6は先行公開版です。
8
+ Node.js 22以降が必要です。v6.1.0の利用手順です。
9
9
 
10
10
  ```sh
11
- npx def-game@6.0.0-alpha.0 init-worker --directory my-game --name my-game
11
+ npx def-game@6.1.0 init-worker --directory my-game --name my-game
12
12
  cd my-game
13
13
  npm install
14
14
  npm run dev
@@ -1,24 +1,26 @@
1
- import type { CommandResult, CreateRoomResult, VerifiedActor } from "./types.js";
1
+ import type { CommandResult, CreateRoomResult, GetViewResult, VerifiedActor } from "./types.js";
2
2
  /** DOの信頼されたRPC面。アプリは外部リクエストを直接この面へ転送しない。 */
3
- interface RoomTransport<ActorCommand, SystemCommand, Error> {
3
+ interface RoomTransport<ActorCommand, SystemCommand, Error, View> {
4
4
  create(): Promise<CreateRoomResult>;
5
+ getView(actor: VerifiedActor): Promise<GetViewResult<View>>;
5
6
  dispatchActor(actor: VerifiedActor, command: ActorCommand): Promise<CommandResult<Error>>;
6
7
  dispatchSystem(command: SystemCommand): Promise<CommandResult<Error>>;
7
8
  fetch(request: Request): Promise<Response>;
8
9
  }
9
10
  /** 通常のアプリ操作向け参照。System入口を含めない。 */
10
- export interface RoomClient<ActorCommand, Error> {
11
+ export interface RoomClient<ActorCommand, Error, View = unknown> {
11
12
  create(): Promise<CreateRoomResult>;
13
+ getView(actor: VerifiedActor): Promise<GetViewResult<View>>;
12
14
  dispatchActor(actor: VerifiedActor, command: ActorCommand): Promise<CommandResult<Error>>;
13
15
  connect(actor: VerifiedActor): Promise<Response>;
14
16
  }
15
17
  /** 対象DOを選び、認証済みActor向けのAPIだけを返す。IDの解決はアプリが行う。 */
16
- export declare function getRoom<A, S, E>(namespace: {
17
- get(id: DurableObjectId): RoomTransport<A, S, E>;
18
- }, id: DurableObjectId): RoomClient<A, E>;
18
+ export declare function getRoom<A, S, E, V>(namespace: {
19
+ get(id: DurableObjectId): RoomTransport<A, S, E, V>;
20
+ }, id: DurableObjectId): RoomClient<A, E, V>;
19
21
  /** 認証・権限確認済みのwebhookやマッチングからSystem Commandを渡す参照。 */
20
- export declare function getSystemRoom<A, S, E>(namespace: {
21
- get(id: DurableObjectId): RoomTransport<A, S, E>;
22
+ export declare function getSystemRoom<A, S, E, V>(namespace: {
23
+ get(id: DurableObjectId): RoomTransport<A, S, E, V>;
22
24
  }, id: DurableObjectId): {
23
25
  dispatchSystem(command: S): Promise<CommandResult<E>>;
24
26
  };
@@ -1 +1 @@
1
- {"version":3,"file":"room-client.d.ts","sourceRoot":"","sources":["../../../src/cloudflare/room-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjF,4CAA4C;AAC5C,UAAU,aAAa,CAAC,YAAY,EAAE,aAAa,EAAE,KAAK;IACxD,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACpC,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1F,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC5C;AAED,kCAAkC;AAClC,MAAM,WAAW,UAAU,CAAC,YAAY,EAAE,KAAK;IAC7C,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACpC,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1F,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClD;AAED,iDAAiD;AACjD,wBAAgB,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAC7B,SAAS,EAAE;IAAE,GAAG,CAAC,EAAE,EAAE,eAAe,GAAG,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;CAAE,EAAE,EAAE,EAAE,eAAe,GACnF,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAYlB;AAED,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EACnC,SAAS,EAAE;IAAE,GAAG,CAAC,EAAE,EAAE,eAAe,GAAG,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;CAAE,EAAE,EAAE,EAAE,eAAe,GACnF;IAAE,cAAc,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;CAAE,CAG3D"}
1
+ {"version":3,"file":"room-client.d.ts","sourceRoot":"","sources":["../../../src/cloudflare/room-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhG,4CAA4C;AAC5C,UAAU,aAAa,CAAC,YAAY,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI;IAC9D,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACpC,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1F,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC5C;AAED,kCAAkC;AAClC,MAAM,WAAW,UAAU,CAAC,YAAY,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO;IAC7D,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACpC,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1F,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClD;AAED,iDAAiD;AACjD,wBAAgB,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAChC,SAAS,EAAE;IAAE,GAAG,CAAC,EAAE,EAAE,eAAe,GAAG,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;CAAE,EAAE,EAAE,EAAE,eAAe,GACtF,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAarB;AAED,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EACtC,SAAS,EAAE;IAAE,GAAG,CAAC,EAAE,EAAE,eAAe,GAAG,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;CAAE,EAAE,EAAE,EAAE,eAAe,GACtF;IAAE,cAAc,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;CAAE,CAG3D"}
@@ -3,6 +3,7 @@ export function getRoom(namespace, id) {
3
3
  const stub = namespace.get(id);
4
4
  return {
5
5
  create: () => stub.create(),
6
+ getView: actor => stub.getView(actor),
6
7
  dispatchActor: (actor, command) => stub.dispatchActor(actor, command),
7
8
  connect: actor => {
8
9
  if (!actor || typeof actor.actorId !== "string" || !actor.actorId)
@@ -1,5 +1,5 @@
1
1
  import { DurableObject } from "cloudflare:workers";
2
- import type { CommandResult, CreateRoomResult, GameAdapter, GameTypes, VerifiedActor } from "./types.js";
2
+ import type { CommandResult, CreateRoomResult, GetViewResult, GameAdapter, GameTypes, VerifiedActor } from "./types.js";
3
3
  /**
4
4
  * 1ルームを動かすCloudflare専用runtime。アプリはadapterだけを接続した派生クラスをexportする。
5
5
  * RPCとfetchは信頼されたWorker専用。認証・外部リクエスト保護はWorker入口が担当する。
@@ -9,6 +9,8 @@ export declare abstract class SessionRuntime<Env, T extends GameTypes> extends D
9
9
  protected abstract readonly adapter: GameAdapter<Env, T>;
10
10
  /** 所有者や参加者を要求せず、ゲームの初期状態だけを保存する。 */
11
11
  create(): Promise<CreateRoomResult>;
12
+ /** HTTP等からの読み取り。公開内容はprojectが決め、WS接続資格は要求しない。 */
13
+ getView(actor: VerifiedActor): Promise<GetViewResult<T["view"]>>;
12
14
  /** アプリが認証済みActorと、必要なら外部取得済み情報を渡す入口。 */
13
15
  dispatchActor(actor: VerifiedActor, command: T["actorCommand"]): Promise<CommandResult<T["error"]>>;
14
16
  /** webhook等の認証を済ませたサーバー専用入口。外部本文からoriginをコピーしない。 */
@@ -1 +1 @@
1
- {"version":3,"file":"session-runtime.d.ts","sourceRoot":"","sources":["../../../src/cloudflare/session-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,SAAS,EAAgD,aAAa,EAAE,MAAM,YAAY,CAAC;AAMvJ;;;GAGG;AACH,8BAAsB,cAAc,CAAC,GAAG,EAAE,CAAC,SAAS,SAAS,CAAE,SAAQ,aAAa,CAAC,GAAG,CAAC;;IACvF,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAEzD,oCAAoC;IAC9B,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAgBzC,wCAAwC;IAClC,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAKzG,oDAAoD;IAC9C,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAgFrF,0CAA0C;IACpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B,uDAAuD;IACjD,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAyBhD,8CAA8C;IACxC,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiEnF,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAGrD,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;CACxC"}
1
+ {"version":3,"file":"session-runtime.d.ts","sourceRoot":"","sources":["../../../src/cloudflare/session-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAgD,aAAa,EAAE,MAAM,YAAY,CAAC;AAMtK;;;GAGG;AACH,8BAAsB,cAAc,CAAC,GAAG,EAAE,CAAC,SAAS,SAAS,CAAE,SAAQ,aAAa,CAAC,GAAG,CAAC;;IACvF,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAEzD,oCAAoC;IAC9B,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAgBzC,iDAAiD;IAC3C,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IActE,wCAAwC;IAClC,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAKzG,oDAAoD;IAC9C,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,eAAe,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAgFrF,0CAA0C;IACpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B,uDAAuD;IACjD,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAyBhD,8CAA8C;IACxC,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiEnF,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAGrD,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;CACxC"}
@@ -26,6 +26,23 @@ export class SessionRuntime extends DurableObject {
26
26
  }
27
27
  });
28
28
  }
29
+ /** HTTP等からの読み取り。公開内容はprojectが決め、WS接続資格は要求しない。 */
30
+ async getView(actor) {
31
+ if (!actor || typeof actor.actorId !== "string" || actor.actorId.length === 0)
32
+ return failure("InvalidRequest");
33
+ return this.ctx.blockConcurrencyWhile(async () => {
34
+ try {
35
+ const state = await this.ctx.storage.get(STATE_KEY);
36
+ if (state === undefined)
37
+ return failure("RoomNotFound");
38
+ return { ok: true, view: this.adapter.game.project(state, actor.actorId) };
39
+ }
40
+ catch {
41
+ this.#report("view");
42
+ return failure("InternalError");
43
+ }
44
+ });
45
+ }
29
46
  /** アプリが認証済みActorと、必要なら外部取得済み情報を渡す入口。 */
30
47
  async dispatchActor(actor, command) {
31
48
  if (!actor || typeof actor.actorId !== "string" || actor.actorId.length === 0)
@@ -33,6 +33,14 @@ export type CreateRoomResult = {
33
33
  readonly ok: false;
34
34
  readonly error: RuntimeError;
35
35
  };
36
+ /** 保存状態そのものではなく、ゲームがActorに公開するViewを返す。 */
37
+ export type GetViewResult<View> = {
38
+ readonly ok: true;
39
+ readonly view: View;
40
+ } | {
41
+ readonly ok: false;
42
+ readonly error: RuntimeError;
43
+ };
36
44
  /** 状態と一緒に確定する、1つの現在decisionに対する予約・解除。 */
37
45
  export type TimeoutEffect = {
38
46
  readonly type: "schedule";
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cloudflare/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cloudflare/types.ts"],"names":[],"mappings":"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"}
@@ -52,10 +52,10 @@ WS接続後のメッセージはライブラリのWS処理へ届き、毎回Work
52
52
 
53
53
  ## 1. init-workerで開発を始める
54
54
 
55
- Node.js 22以降で、次を実行します。以下は先行公開版`6.0.0-alpha.0`の利用手順です。
55
+ Node.js 22以降で、次を実行します。以下は`6.1.0`の利用手順です。
56
56
 
57
57
  ```sh
58
- npx def-game@6.0.0-alpha.0 init-worker --directory my-game --name my-game
58
+ npx def-game@6.1.0 init-worker --directory my-game --name my-game
59
59
  cd my-game
60
60
  npm install
61
61
  npm run dev
@@ -133,6 +133,8 @@ Joinや設定変更は、その後のゲームCommandとして実装してくだ
133
133
  「部屋を作った人が所有者になる」というルールも、ライブラリではなくゲームが決めます。
134
134
 
135
135
  `project`では、自分の手札などActorに公開できる情報だけを返してください。
136
+ HTTPで部屋の概要や再読み込み用の情報を取得したい場合は、`room.getView(actor)`を使います。
137
+ 同じprojectが呼ばれるので、未参加者には要約、参加者には個別情報という出し分けもここで実装します。WSの接続資格は要求しません。
136
138
  `availableActions`は画面を作るための補助です。ボタンを非表示にしても不正なCommandは送れるため、操作可否は必ず`handleCommand`でも検証します。
137
139
 
138
140
  ## 3. ゲームと外部を接続する
@@ -172,7 +172,7 @@ export type TransitionResult<State, Effect, Error> =
172
172
  `availableActions`はViewに含める設計上の契約ですが、型の制約で自動的に必須化されてはいません。
173
173
  その表示は認可の代わりにならないため、Command実行時にも検証します。
174
174
 
175
- runtimeは接続時とCommand保存後の配信で呼びます。同じActorの複数接続などで何度呼ばれてもStateを変更してはいけません。
175
+ runtimeはHTTP等からの`getView`、接続時、Command保存後の配信で呼びます。同じActorの複数接続などで何度呼ばれてもStateを変更してはいけません。
176
176
  配信中に例外が出ても保存済みCommandは取り消しません。該当接続は閉じられ、診断対象になります。
177
177
 
178
178
  <a id="adapter-properties"></a>
@@ -313,8 +313,9 @@ State・Command・Effect・元の例外本文は引数に含めません。未
313
313
  interface VerifiedActor { readonly actorId: string }
314
314
 
315
315
  // getRoom(namespace, durableObjectId)が返す参照
316
- interface RoomClient<ActorCommand, Error> {
316
+ interface RoomClient<ActorCommand, Error, View = unknown> {
317
317
  create(): Promise<CreateRoomResult>;
318
+ getView(actor: VerifiedActor): Promise<GetViewResult<View>>;
318
319
  dispatchActor(actor: VerifiedActor, command: ActorCommand): Promise<CommandResult<Error>>;
319
320
  connect(actor: VerifiedActor): Promise<Response>;
320
321
  }
@@ -322,6 +323,34 @@ interface RoomClient<ActorCommand, Error> {
322
323
  // { dispatchSystem(command: SystemCommand): Promise<CommandResult<Error>> }
323
324
  ```
324
325
 
326
+ ### getView(actor):接続せずにViewを取得する
327
+
328
+ ```ts
329
+ const room = getRoom(env.ROOMS, id);
330
+ const result = await room.getView(verifiedActor);
331
+ // 公開HTTPのレスポンスやステータスはアプリで決める
332
+ ```
333
+
334
+ ```ts
335
+ type GetViewResult<View> =
336
+ | { readonly ok: true; readonly view: View }
337
+ | { readonly ok: false; readonly error: RuntimeError };
338
+ ```
339
+
340
+ runtimeが保存済みStateを読み、既存の`game.project(state, actor.actorId)`を呼んで返します。
341
+ ゲーム側に新しい関数の実装は必要ありません。View型はDOのadapterから推論されます。
342
+ 状態変更・Command実行・Effect・WS接続・他の接続への配信は行いません。
343
+
344
+ `canConnect`は呼びません。認証済みの未参加者にも、projectが部屋の概要等を返せます。
345
+ 参加者・観戦者・未参加者で何を見せるかはprojectで判断し、非公開Stateを返さないでください。
346
+ 未認証の公開閲覧を提供するAPIではなく、アプリは呼び出し前にActorを認証します。
347
+
348
+ 未作成はRoomNotFound、不正ActorはInvalidRequest、読み取り・projectの例外はInternalErrorです。
349
+ 内部例外はonErrorのview区間へ通知し、保存済み状態を変更しません。
350
+ 返るのは読み取り時点のViewであり、その後の操作が同じ状態で受理される保証はありません。
351
+
352
+ ### 作成・操作・接続
353
+
325
354
  `create()`は初期状態のみを保存し、二重作成を拒否します。JoinはゲームCommandです。
326
355
  `connect()`成功時は101のWS応答を返します。未作成404、接続資格なし403、内部例外500等になります。
327
356
  Actorが不正な場合は呼び出し側で例外になることもあります。
@@ -414,10 +443,10 @@ requestIdは応答の対応付け用で、永続的な重複排除には使い
414
443
 
415
444
  ### 始め方
416
445
 
417
- Node.js 22以降を使用します。先行公開版`6.0.0-alpha.0`を指定して生成します。
446
+ Node.js 22以降を使用します。`6.1.0`を指定して生成します。
418
447
 
419
448
  ```sh
420
- npx def-game@6.0.0-alpha.0 init-worker --directory my-game --name my-game
449
+ npx def-game@6.1.0 init-worker --directory my-game --name my-game
421
450
  cd my-game
422
451
  npm install
423
452
  npm run dev
@@ -425,7 +454,7 @@ npm run dev
425
454
 
426
455
  開発版をこのリポジトリから試す場合は、リポジトリで`npm pack`を実行します。
427
456
  `node bin/def-game.cjs init-worker --directory /path/to/my-game --name my-game`で生成し、生成先で
428
- `npm install /absolute/path/to/def-game-6.0.0-alpha.0.tgz`を実行してください。
457
+ `npm install /absolute/path/to/def-game-6.1.0.tgz`を実行してください。
429
458
  その後は`npm run typecheck`、`npm run build`、`npm run dev`を利用できます。buildはWranglerのdry-runで、公開しません。
430
459
 
431
460
  生成先は新しいディレクトリに限定します。既存ディレクトリは空でも拒否します。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "def-game",
3
- "version": "6.0.0-alpha.0",
3
+ "version": "6.1.0",
4
4
  "description": "Pure game definitions, a simulator, and a Cloudflare Durable Object runtime for turn-based games",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -12,7 +12,7 @@ npm install
12
12
  npm run dev
13
13
  ```
14
14
 
15
- 未公開alpha版では、`npm install`の代わりに`npm install /absolute/path/to/def-game-6.0.0-alpha.0.tgz`を実行してください。
15
+ ローカルの開発版では、`npm install`の代わりに`npm install /absolute/path/to/def-game-6.1.0.tgz`を実行してください。
16
16
  `http://127.0.0.1:8787`を開きます。別ブラウザープロファイルで共有URLを開くと、2人で試せます。
17
17
 
18
18
  実装前に[設計思想](node_modules/def-game/docs/design-philosophy.md)を読み、詳細は[runtime API・初期生成の使い方](node_modules/def-game/docs/runtime-api.md)を参照してください。
@@ -10,6 +10,6 @@
10
10
  "build": "wrangler deploy --dry-run --outdir dist",
11
11
  "deploy": "wrangler deploy"
12
12
  },
13
- "dependencies": { "def-game": "6.0.0-alpha.0", "hono": "^4.13.7", "jose": "^6.2.12" },
13
+ "dependencies": { "def-game": "6.1.0", "hono": "^4.13.7", "jose": "^6.2.12" },
14
14
  "devDependencies": { "@cloudflare/workers-types": "^5.20260911.1", "typescript": "^5.8.2", "wrangler": "^4.131.1" }
15
15
  }