@dxos/plugin-game 0.11.0 → 0.12.0-next-bbabc02363f18d7643ea4160e3a7a7809870fd0d
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/lib/{chunk-types.mjs → Game.mjs} +3 -27
- package/dist/lib/Game.mjs.map +1 -0
- package/dist/lib/GameCapabilities.mjs +17 -0
- package/dist/lib/GameCapabilities.mjs.map +1 -0
- package/dist/lib/GameEvents.mjs +14 -0
- package/dist/lib/GameEvents.mjs.map +1 -0
- package/dist/lib/GamePlugin.mjs +5 -5
- package/dist/lib/GamePlugin.mjs.map +1 -1
- package/dist/lib/GamePlugin.node.mjs +4 -4
- package/dist/lib/GamePlugin.node.mjs.map +1 -1
- package/dist/lib/GamePlugin.workerd.mjs +4 -4
- package/dist/lib/GamePlugin.workerd.mjs.map +1 -1
- package/dist/lib/{chunk-load-game.mjs → GameUtil.mjs} +7 -2
- package/dist/lib/GameUtil.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +8 -3
- package/dist/lib/capabilities.mjs.map +1 -1
- package/dist/lib/chunk-GameArticle.mjs +2 -2
- package/dist/lib/chunk-GameArticle.mjs.map +1 -1
- package/dist/lib/chunk-GameCard.mjs +2 -2
- package/dist/lib/chunk-GameCard.mjs.map +1 -1
- package/dist/lib/chunk-create-object.mjs +8 -6
- package/dist/lib/chunk-create-object.mjs.map +1 -1
- package/dist/lib/chunk-meta.mjs +1 -1
- package/dist/lib/chunk-meta.mjs.map +1 -1
- package/dist/lib/chunk-react-surface.mjs +4 -3
- package/dist/lib/chunk-react-surface.mjs.map +1 -1
- package/dist/lib/chunk-rolldown-runtime.mjs +13 -0
- package/dist/lib/components.mjs +3 -3
- package/dist/lib/components.mjs.map +1 -1
- package/dist/lib/index.mjs +5 -3
- package/dist/lib/plugin.mjs +1 -1
- package/dist/lib/plugin.mjs.map +1 -1
- package/dist/lib/translations.mjs +2 -2
- package/dist/lib/translations.mjs.map +1 -1
- package/dist/lib/util.mjs +1 -1
- package/dist/types/src/GamePlugin.d.ts +1 -1
- package/dist/types/src/GamePlugin.d.ts.map +1 -1
- package/dist/types/src/GamePlugin.node.d.ts +1 -1
- package/dist/types/src/GamePlugin.node.d.ts.map +1 -1
- package/dist/types/src/GamePlugin.workerd.d.ts +1 -1
- package/dist/types/src/GamePlugin.workerd.d.ts.map +1 -1
- package/dist/types/src/capabilities/create-object.d.ts +2 -2
- package/dist/types/src/capabilities/create-object.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +2 -3
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +2 -2
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/components/CreateGamePanel.d.ts +4 -4
- package/dist/types/src/components/CreateGamePanel.d.ts.map +1 -1
- package/dist/types/src/components/CreateGamePanel.stories.d.ts +1 -1
- package/dist/types/src/containers/GameArticle/GameArticle.d.ts +1 -1
- package/dist/types/src/containers/GameArticle/GameArticle.d.ts.map +1 -1
- package/dist/types/src/containers/GameCard/GameCard.d.ts +1 -1
- package/dist/types/src/containers/GameCard/GameCard.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +4 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/plugin.d.ts +1 -1
- package/dist/types/src/plugin.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Game.d.ts +2 -2
- package/dist/types/src/types/GameCapabilities.d.ts +54 -5
- package/dist/types/src/types/GameCapabilities.d.ts.map +1 -1
- package/dist/types/src/types/GameEvents.d.ts +7 -0
- package/dist/types/src/types/GameEvents.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +54 -30
- package/src/GamePlugin.node.tsx +6 -5
- package/src/GamePlugin.tsx +15 -10
- package/src/GamePlugin.workerd.tsx +5 -4
- package/src/capabilities/create-object.ts +6 -5
- package/src/capabilities/index.ts +6 -3
- package/src/capabilities/react-surface.ts +4 -3
- package/src/components/CreateGamePanel.stories.tsx +2 -2
- package/src/components/CreateGamePanel.tsx +6 -5
- package/src/containers/GameArticle/GameArticle.tsx +3 -1
- package/src/containers/GameCard/GameCard.tsx +2 -1
- package/src/index.ts +4 -1
- package/src/meta.ts +1 -1
- package/src/plugin.ts +1 -1
- package/src/translations.ts +2 -1
- package/src/types/Game.ts +2 -2
- package/src/types/GameCapabilities.ts +56 -6
- package/src/types/GameEvents.ts +15 -0
- package/dist/lib/chunk-load-game.mjs.map +0 -1
- package/dist/lib/chunk-types.mjs.map +0 -1
- package/dist/lib/types.mjs +0 -3
- package/dist/types/src/types/index.d.ts +0 -5
- package/dist/types/src/types/index.d.ts.map +0 -1
- package/dist/types/src/types/types.d.ts +0 -50
- package/dist/types/src/types/types.d.ts.map +0 -1
- package/src/types/index.ts +0 -9
- package/src/types/types.ts +0 -57
|
@@ -1,22 +1,8 @@
|
|
|
1
|
-
import "./chunk-
|
|
2
|
-
import { Capability } from "@dxos/app-framework";
|
|
1
|
+
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
3
2
|
import * as Schema from "effect/Schema";
|
|
4
3
|
import { Annotation, DXN, Obj, Ref, Type } from "@dxos/echo";
|
|
5
4
|
import { FormInputAnnotation, LabelAnnotation } from "@dxos/echo/Annotation";
|
|
6
5
|
import { CardAnnotation } from "@dxos/schema";
|
|
7
|
-
import { meta } from "#meta";
|
|
8
|
-
//#region \0rolldown/runtime.js
|
|
9
|
-
var __defProp = Object.defineProperty;
|
|
10
|
-
var __exportAll = (all, no_symbols) => {
|
|
11
|
-
let target = {};
|
|
12
|
-
for (var name in all) __defProp(target, name, {
|
|
13
|
-
get: all[name],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
17
|
-
return target;
|
|
18
|
-
};
|
|
19
|
-
//#endregion
|
|
20
6
|
//#region src/types/Game.ts
|
|
21
7
|
var Game_exports = /* @__PURE__ */ __exportAll({
|
|
22
8
|
Game: () => Game,
|
|
@@ -68,16 +54,6 @@ var make = ({ name, players, variant }) => {
|
|
|
68
54
|
});
|
|
69
55
|
};
|
|
70
56
|
//#endregion
|
|
71
|
-
|
|
72
|
-
var GameCapabilities_exports = /* @__PURE__ */ __exportAll({ VariantProvider: () => VariantProvider });
|
|
73
|
-
/**
|
|
74
|
-
* A game variant contribution. Each variant plugin (chess, tic-tac-toe, ...)
|
|
75
|
-
* contributes one of these via `Capability.contributes(GameCapabilities.VariantProvider, variant)`.
|
|
76
|
-
* Consumers iterate via `Capability.getAll(GameCapabilities.VariantProvider)` (Effect) or
|
|
77
|
-
* `useCapabilities(GameCapabilities.VariantProvider)` (React).
|
|
78
|
-
*/
|
|
79
|
-
var VariantProvider = Capability.make(`${meta.profile.key}.capability.variant`);
|
|
80
|
-
//#endregion
|
|
81
|
-
export { make as a, Game_exports as i, VariantProvider as n, Game as r, GameCapabilities_exports as t };
|
|
57
|
+
export { Game, GameRef, Player, make, Game_exports as t };
|
|
82
58
|
|
|
83
|
-
//# sourceMappingURL=
|
|
59
|
+
//# sourceMappingURL=Game.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Game.mjs","names":[],"sources":["../../src/types/Game.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { Annotation, DXN, Obj, Ref, Type } from '@dxos/echo';\nimport { FormInputAnnotation, LabelAnnotation } from '@dxos/echo/Annotation';\nimport { CardAnnotation } from '@dxos/schema';\n\n// @import-as-namespace\n\n/**\n * A player in a game.\n * `role` is variant-defined (e.g. 'white' | 'black' for chess, 'x' | 'o' for tictactoe).\n * `identity` is the optional DID of a human player; absent for AI or empty seats.\n * `name` is an optional display label (useful for AI/guest players).\n */\nexport const Player = Schema.Struct({\n role: Schema.String.annotations({\n description: 'Variant-defined player role (e.g. \"white\", \"x\").',\n }),\n identity: Schema.optional(\n Schema.String.annotations({\n description: 'DID of the player; absent for AI or empty seats.',\n }),\n ),\n name: Schema.optional(\n Schema.String.annotations({\n description: 'Optional display name for the player.',\n }),\n ),\n});\n\nexport type Player = Schema.Schema.Type<typeof Player>;\n\n/**\n * Base Game object. Variant-specific state lives in a separate referenced object.\n * Unifies all game variants (chess, tic-tac-toe, ...) under one typename so they share\n * graph node, create flow, and shared surface scaffolding.\n */\nexport class Game extends Type.makeObject<Game>(DXN.make('org.dxos.type.game', '0.1.0'))(\n Schema.Struct({\n name: Schema.optional(Schema.String),\n players: Schema.mutable(Schema.Array(Player))\n .annotations({ description: 'Players in the game.' })\n .pipe(FormInputAnnotation.set(false), Schema.optional),\n variant: Ref.Ref(Obj.Unknown)\n .annotations({ description: 'Reference to variant-specific state object.' })\n .pipe(FormInputAnnotation.set(false)),\n }).pipe(\n LabelAnnotation.set(['name']),\n Annotation.IconAnnotation.set({ icon: 'ph--sword--regular', hue: 'indigo' }),\n CardAnnotation.set(true),\n // Delegate the graph-node icon to the referenced variant state's schema. Falls back to\n // the static `ph--sword--regular` above while the variant ref is still loading.\n Annotation.IconFromRefAnnotation.set('variant'),\n ),\n) {}\n\n/**\n * Variant-narrowed reference to a Game.\n *\n * Encodes — at the type level — that the variant ref points to a specific state type.\n * Runtime narrowing is performed by `GameUtil.loadGame(ref, variantType)` which validates and\n * returns the resolved Game together with its typed variant state.\n *\n * @example\n * ```ts\n * input: Schema.Struct({\n * game: GameRef(Chess.State),\n * }),\n * // handler:\n * const { game, variant } = yield* GameUtil.loadGame(input.game, Chess.State);\n * // `variant` is typed as Chess.State.\n * ```\n */\nexport type GameRef<_V> = Ref.Ref<Game>;\n\nexport const GameRef = <S extends Type.AnyObj>(_variantType: S) =>\n Ref.Ref(Game) as Schema.Schema<GameRef<Type.InstanceType<S>>, any, never>;\n\n/**\n * Build a base `Game` object referencing the given variant-state ECHO object.\n *\n * The variant is stored as a `Ref` so the underlying state (e.g. `Chess.State`,\n * `TicTacToe.State`) lives as its own ECHO object alongside the Game.\n *\n * @param name Optional display name shown in the graph node and Properties form.\n * @param variant Variant-specific state object (e.g. `Chess.State`, `TicTacToe.State`).\n * @param players Optional initial players; copied into a mutable array on the Game.\n * @returns A new `Game` object with `variant` stored as a Ref.\n */\nexport const make = ({\n name,\n players,\n variant,\n}: {\n name?: string;\n players?: ReadonlyArray<Player>;\n variant: Obj.Unknown;\n}): Game => {\n return Obj.make(Game, {\n name,\n players: players ? [...players] : [],\n variant: Ref.make(variant),\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,IAAa,SAAS,OAAO,OAAO;CAClC,MAAM,OAAO,OAAO,YAAY,EAC9B,aAAa,uDACf,CAAC;CACD,UAAU,OAAO,SACf,OAAO,OAAO,YAAY,EACxB,aAAa,mDACf,CAAC,CACH;CACA,MAAM,OAAO,SACX,OAAO,OAAO,YAAY,EACxB,aAAa,wCACf,CAAC,CACH;AACF,CAAC;;;;;;AASD,IAAa,OAAb,cAA0B,KAAK,WAAiB,IAAI,KAAK,sBAAsB,OAAO,CAAC,CAAC,CACtF,OAAO,OAAO;CACZ,MAAM,OAAO,SAAS,OAAO,MAAM;CACnC,SAAS,OAAO,QAAQ,OAAO,MAAM,MAAM,CAAC,CAAA,CACzC,YAAY,EAAE,aAAa,uBAAuB,CAAC,CAAA,CACnD,KAAK,oBAAoB,IAAI,KAAK,GAAG,OAAO,QAAQ;CACvD,SAAS,IAAI,IAAI,IAAI,OAAO,CAAA,CACzB,YAAY,EAAE,aAAa,8CAA8C,CAAC,CAAA,CAC1E,KAAK,oBAAoB,IAAI,KAAK,CAAC;AACxC,CAAC,CAAC,CAAC,KACD,gBAAgB,IAAI,CAAC,MAAM,CAAC,GAC5B,WAAW,eAAe,IAAI;CAAE,MAAM;CAAsB,KAAK;AAAS,CAAC,GAC3E,eAAe,IAAI,IAAI,GAGvB,WAAW,sBAAsB,IAAI,SAAS,CAChD,CACF,CAAC,CAAC,CAAC;AAqBH,IAAa,WAAkC,iBAC7C,IAAI,IAAI,IAAI;;;;;;;;;;;;AAad,IAAa,QAAQ,EACnB,MACA,SACA,cAKU;CACV,OAAO,IAAI,KAAK,MAAM;EACpB;EACA,SAAS,UAAU,CAAC,GAAG,OAAO,IAAI,CAAC;EACnC,SAAS,IAAI,KAAK,OAAO;CAC3B,CAAC;AACH"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
2
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
3
|
+
import { meta } from "#meta";
|
|
4
|
+
//#region src/types/GameCapabilities.ts
|
|
5
|
+
var GameCapabilities_exports = /* @__PURE__ */ __exportAll({ VariantProvider: () => VariantProvider });
|
|
6
|
+
/**
|
|
7
|
+
* A game variant contribution. Each variant plugin (chess, tic-tac-toe, ...)
|
|
8
|
+
* contributes one of these via `Capability.contribute(GameCapabilities.VariantProvider, variant)`.
|
|
9
|
+
* Multi capability: more than one variant plugin provides it. Consumers iterate via
|
|
10
|
+
* `Capability.getAll(GameCapabilities.VariantProvider)` (Effect) or
|
|
11
|
+
* `useCapabilities(GameCapabilities.VariantProvider)` (React).
|
|
12
|
+
*/
|
|
13
|
+
var VariantProvider = Capability.make()(`${meta.profile.key}.capability.variant`);
|
|
14
|
+
//#endregion
|
|
15
|
+
export { VariantProvider, GameCapabilities_exports as t };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=GameCapabilities.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameCapabilities.mjs","names":[],"sources":["../../src/types/GameCapabilities.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport type * as Effect from 'effect/Effect';\nimport type * as Schema from 'effect/Schema';\nimport type { ComponentType } from 'react';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport type { Database, Obj, Type } from '@dxos/echo';\n\nimport { meta } from '#meta';\n\nimport * as Game from './Game';\n\n/**\n * A game variant contribution. Each variant plugin (chess, tic-tac-toe, ...)\n * contributes one of these via `Capability.contribute(GameCapabilities.VariantProvider, variant)`.\n * Multi capability: more than one variant plugin provides it. Consumers iterate via\n * `Capability.getAll(GameCapabilities.VariantProvider)` (Effect) or\n * `useCapabilities(GameCapabilities.VariantProvider)` (React).\n */\nexport const VariantProvider = Capability.make<GameVariant>()(`${meta.profile.key}.capability.variant`);\n\n/**\n * Contribution from a variant plugin (e.g. plugin-chess).\n * Defines how a game variant is created, rendered, and the roles its players take.\n */\nexport type GameVariant = {\n /** Stable id, typically the variant state typename (e.g. 'org.dxos.type.chess.state'). */\n id: string;\n /** Human-readable variant name (e.g. 'Chess'). */\n label: string;\n /** Optional Phosphor icon name (e.g. 'ph--shield-chevron--regular'). */\n icon?: string;\n /** ECHO Type entity of the variant state object referenced by `Game.variant`. */\n variantType: Type.AnyObj;\n /**\n * Optional Effect Schema rendered as a form after the user picks the variant.\n * To use a `Type.Type` entity, extract its schema first via `Type.getSchema(...)`.\n */\n inputSchema?: Schema.Schema.AnyNoContext;\n /** Roles a player may take in this variant (e.g. ['white', 'black']). */\n roles: readonly string[];\n /**\n * Build the variant state object from the user's form input. May allocate ECHO\n * objects, run effects, etc. Returned object is added to the database alongside the Game.\n */\n createVariant: (input: Record<string, any>) => Effect.Effect<Obj.Any, Error, Database.Service>;\n /** Optional Card surface component for this variant. */\n card?: ComponentType<GameVariantSurfaceProps>;\n /** Optional Article/Section surface component for this variant. */\n article?: ComponentType<GameVariantSurfaceProps>;\n};\n\nexport type GameVariantSurfaceProps = {\n /** The base Game object (may be a snapshot from useObject/Surface). */\n game: Obj.Snapshot<Game.Game> | Game.Game;\n /**\n * The resolved variant state object, live rather than a snapshot so variants can write to it.\n * Reads must subscribe via `useObject(variant, prop)` — the host re-renders only when the ref\n * resolves, not on every mutation.\n */\n variant: Obj.Unknown;\n /** Surface role passed through from the host. */\n role?: string;\n /** Attendable id passed through from the host. */\n attendableId?: string;\n};\n"],"mappings":";;;;;;;;;;;;AAsBA,IAAa,kBAAkB,WAAW,KAAkB,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,oBAAoB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
2
|
+
import { meta } from "#meta";
|
|
3
|
+
import * as ActivationEvent from "@dxos/app-framework/ActivationEvent";
|
|
4
|
+
//#region src/types/GameEvents.ts
|
|
5
|
+
var GameEvents_exports = /* @__PURE__ */ __exportAll({ Start: () => Start });
|
|
6
|
+
/**
|
|
7
|
+
* The feature's start event: cross-plugin contributions consumed by this feature activate here,
|
|
8
|
+
* alongside the plugin's own start-gated modules. Fired on demand and by the host's idle trickle.
|
|
9
|
+
*/
|
|
10
|
+
var Start = ActivationEvent.pluginStart(meta.profile.key);
|
|
11
|
+
//#endregion
|
|
12
|
+
export { Start, GameEvents_exports as t };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=GameEvents.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameEvents.mjs","names":[],"sources":["../../src/types/GameEvents.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as ActivationEvent from '@dxos/app-framework/ActivationEvent';\n\nimport { meta } from '#meta';\n\n/**\n * The feature's start event: cross-plugin contributions consumed by this feature activate here,\n * alongside the plugin's own start-gated modules. Fired on demand and by the host's idle trickle.\n */\nexport const Start = ActivationEvent.pluginStart(meta.profile.key);\n"],"mappings":";;;;;;;;;AAcA,IAAa,QAAQ,gBAAgB,YAAY,KAAK,QAAQ,GAAG"}
|
package/dist/lib/GamePlugin.mjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Game } from "./Game.mjs";
|
|
2
2
|
import { meta } from "#meta";
|
|
3
|
-
import
|
|
3
|
+
import * as Plugin from "@dxos/app-framework/Plugin";
|
|
4
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
4
5
|
import { CreateObject, ReactSurface } from "#capabilities";
|
|
5
6
|
import { translations } from "#translations";
|
|
6
|
-
import { Game } from "#types";
|
|
7
7
|
//#endregion
|
|
8
8
|
//#region src/GamePlugin.tsx
|
|
9
|
-
var GamePlugin = Plugin.define(meta).pipe(
|
|
9
|
+
var GamePlugin = Plugin.define(meta).pipe(Plugin.addModule(CreateObject), Plugin.addModule(AppCapability.schema([Game])), Plugin.addModule(ReactSurface), Plugin.addModule(AppCapability.translations(translations)), Plugin.addModule(AppCapability.pluginAsset({
|
|
10
10
|
pluginId: meta.profile.key,
|
|
11
11
|
path: "PLUGIN.mdl",
|
|
12
12
|
content: "---\nid: org.dxos.plugin.game\nname: GamePlugin\nversion: 0.1.0\n---\n\nA generic game host plugin for `DXOS` Composer that provides shared infrastructure for\nmulti-player, local-first turn-based games. Variant plugins (e.g. plugin-chess,\nplugin-tictactoe) contribute a `GameVariant` capability and game-specific surfaces;\nplugin-game supplies the `Game` ECHO type, create flow, and dispatch scaffolding.\n\n## Extensions\n\nThe following extension dialects are used in this document.\nEach extension is defined in the Appendix or resolved via its URI.\n\n| Term | URI |\n|-------------|--------------------------------|\n| `type` | `org.dxos.mdl.type@1.0` |\n| `feat` | `org.dxos.mdl.feat@1.0` |\n| `test` | `org.dxos.mdl.test@1.0` |\n| `component` | `org.dxos.mdl.component@1.0` |\n| `op` | `org.dxos.mdl.op@1.0` |\n\n## Types\n\n```mdl\ntype Player\n fields:\n role: string # variant-defined (e.g. \"white\", \"x\"); required\n identity?: string # DID of a human player; absent for AI / empty seats\n name?: string # display label for AI or guest players\n```\n\n```mdl\ntype Game\n fields:\n name?: string\n players?: Player[] # populated during or after creation\n variant: Ref<Unknown> # reference to variant-specific state object (e.g. Chess.State)\n typename: org.dxos.type.game\n version: 0.1.0\n```\n\n```mdl\ntype GameVariant\n desc: |\n Contribution interface from a variant plugin. Registered via\n `Capability.contributes(GameCapabilities.VariantProvider, variant)`.\n fields:\n id: string # stable variant id; matches the variant state typename\n label: string # human-readable name shown in the picker\n icon?: string # Phosphor icon name\n variantSchema: Schema # Effect/Schema for the ECHO state object\n inputSchema?: Schema # optional form schema shown after variant is selected\n roles: string[] # player roles (e.g. [\"white\", \"black\"])\n createVariant: Effect # factory that builds the variant ECHO state object\n card?: ComponentType # optional Card surface component\n article?: ComponentType # optional Article/Section surface component\n```\n\n## Components\n\n```mdl\ncomponent CreateGamePanel\n desc: |\n Two-stage creation panel. Stage 1 shows a searchable variant picker.\n Stage 2 (optional) shows a form rendered from the variant's inputSchema.\n props:\n target: Space | Obj\n onCreateObject: (args: { variantId: string; input?: Record }) => void\n variants?: GameVariant[] # override; defaults to GameCapabilities.VariantProvider\n state:\n selectedId?: string # id of the variant chosen in stage 1\n actions:\n selectVariant(id: string)\n submitForm(input: Record)\n layout: |\n ┌─────────────────────────┐\n │ Stage 1: Variant Picker │\n │ ┌───────────────────┐ │\n │ │ Search input │ │\n │ ├───────────────────┤ │\n │ │ variant row │ │\n │ │ variant row │ │\n │ └───────────────────┘ │\n ├─────────────────────────┤\n │ Stage 2: Input Form │\n │ (rendered from schema) │\n │ [Submit] │\n └─────────────────────────┘\n```\n\n```mdl\ncomponent GameArticle\n desc: |\n Article / Section surface for Game objects. Resolves the variant via\n `game.variant` ref, finds the matching `GameVariant` by typename, and\n delegates rendering to `variant.article`.\n props:\n game: Game\n role?: string\n attendableId?: string\n state:\n variant: Unknown # live variant state object from the Ref\n match?: GameVariant # resolved GameVariant from capabilities\n layout: |\n ┌─────────────────────────┐\n │ [variant.article] │\n │ (fallback: unsupported │\n │ variant message) │\n └─────────────────────────┘\n```\n\n```mdl\ncomponent GameCard\n desc: |\n Card surface for Game objects. Follows the same variant-resolution\n logic as GameArticle and delegates to `variant.card`.\n props:\n game: Game\n role?: string\n state:\n variant: Unknown\n match?: GameVariant\n```\n\n## Operations\n\n```mdl\nop createGame\n desc: |\n Creates a variant state object via `variant.createVariant`, adds it\n to the space as a hidden object, then wraps it in a top-level Game.\n If the second write fails the variant state object is rolled back.\n input:\n variantId: string\n input?: Record # variant-specific form values\n target: Space | Obj\n targetNodeId?: string\n output: Game\n errors:\n UnknownVariant: no registered GameVariant matches variantId\n effects: [echo:write]\n requires: [GameCapabilities.VariantProvider, SpaceOperation.AddObject, SpaceOperation.RemoveObjects]\n note: |\n Invoked by CreateObjectEntry.createObject.\n Variant state is added with `hidden: true` so it does not appear\n as a top-level item in the user's space graph.\n```\n\n## Features\n\n```mdl\nfeat F-1: Variant Registration\n\n req F-1.1:\n when: a variant plugin loads\n then: it contributes a GameVariant via `Capability.contributes(GameCapabilities.VariantProvider, …)`\n\n req F-1.2:\n when: GameCapabilities.VariantProvider contributions are queried\n then: all registered variants are returned as an ordered list\n```\n\n```mdl\nfeat F-2: Game Creation\n\n req F-2.1:\n when: user opens the create-object flow for type `org.dxos.type.game`\n then: CreateGamePanel is shown with a searchable list of available variants\n\n req F-2.2:\n when: user selects a variant with no inputSchema\n then: op:createGame is invoked immediately with empty input\n\n req F-2.3:\n when: user selects a variant that has an inputSchema\n then: a form rendered from the schema is shown; op:createGame is invoked on submit\n\n req F-2.4:\n when: op:createGame completes\n then: a Game object appears in the space graph; variant state is hidden\n```\n\n```mdl\nfeat F-3: Game Article / Card Rendering\n\n req F-3.1:\n when: Composer navigates to a Game object\n then: GameArticle resolves `game.variant` and delegates to the matching `variant.article`\n\n req F-3.2:\n when: a Game object is shown in a Card layout\n then: GameCard resolves `game.variant` and delegates to `variant.card`\n\n req F-3.3:\n when: no matching variant is found for the loaded state object\n then: GameArticle renders an \"Unsupported game variant\" fallback message\n\n req F-3.4:\n when: the variant ref is not yet loaded\n then: neither GameArticle nor GameCard renders (returns null)\n```\n\n## Acceptance\n\n```mdl\ntest T-1: Variant picker shows all contributions\n given: two variant plugins have contributed GameVariants\n when: the user opens the create-game panel\n then:\n - CreateGamePanel lists both variants\n - variants are sorted alphabetically\n```\n\n```mdl\ntest T-2: Create game without form\n given: a variant with no inputSchema is selected\n when: user clicks the variant item\n then:\n - onCreateObject is called immediately with { variantId }\n - no form is shown\n```\n\n```mdl\ntest T-3: Create game with form\n given: a variant with an inputSchema is selected\n when: user fills and submits the form\n then:\n - onCreateObject is called with { variantId, input: <form values> }\n```\n\n```mdl\ntest T-4: Atomic game creation\n given: a valid variantId and target space\n when: op:createGame is invoked\n then:\n - variant state object added to space (hidden)\n - Game object added with game.variant pointing to the state object\n - both writes are visible to other peers via ECHO replication\n```\n\n```mdl\ntest T-5: Rollback on second write failure\n given: variant state is successfully written\n when: the second write (Game object) fails\n then:\n - RemoveObjects is invoked for the variant state\n - no orphaned state object remains in the space\n```\n\n```mdl\ntest T-6: Unknown variant rejected\n given: op:createGame is invoked with an unregistered variantId\n when: the handler runs\n then: UnknownVariant error is returned; no ECHO writes occur\n```\n\n```mdl\ntest T-7: Unsupported variant fallback\n given: a Game whose variant typename has no registered GameVariant\n when: GameArticle renders\n then: \"Unsupported game variant\" message is shown instead of crashing\n```\n\n---\n\n## Appendix: Extension Definitions\n\nExtension block types used in this document are defined below using\nthe core `ext` primitive — the only construct the base language provides.\n\n```mdl\next type\n uri: org.dxos.mdl.type@1.0\n desc: A named data structure with typed fields and optional literals.\n fields:\n desc?: Prose\n fields?: FieldMap # name[?]: TypeExpr (# inline comment)\n literals?: UnionList # a | b | c\n extends?: TypeRef[]\n```\n\n```mdl\next feat\n uri: org.dxos.mdl.feat@1.0\n desc: A named feature grouping one or more requirements.\n fields:\n desc?: Prose\n req: RequirementList\n nesting: self # feat blocks may contain feat blocks\n```\n\n```mdl\next test\n uri: org.dxos.mdl.test@1.0\n desc: An acceptance scenario expressed as given / when / then steps.\n fields:\n given?: Step | Step[]\n when?: Step | Step[]\n then: Step | Step[]\n tags?: TagList\n```\n\n```mdl\next component\n uri: org.dxos.mdl.component@1.0\n desc: A UI component with props, internal state, slots, actions, and events.\n fields:\n desc?: Prose\n props?: FieldMap # external inputs (immutable inside component)\n state?: FieldMap # internal reactive state\n slots?: FieldMap # named ReactNode injection points\n actions?: ActionMap # methods the component exposes or handles\n emits?: EventMap # events the component raises to its parent\n layout?: CodeBlock # ASCII sketch of visual structure (non-normative)\n```\n\n```mdl\next op\n uri: org.dxos.mdl.op@1.0\n desc: |\n A named operation with typed inputs, outputs, and declared errors.\n Pure ops have no effects or requires. Effectful ops declare both.\n fields:\n desc?: Prose\n input?: FieldMap # named input parameters\n output?: TypeExpr # return type\n errors?: ErrorMap # name: Prose (when this error occurs)\n effects?: EffectList # echo:read | echo:write | http | fs | ...\n requires?: ServiceList # injected service dependencies\n note?: Prose # implementation guidance (non-normative)\n```\n",
|
|
13
13
|
mimeType: "application/x-mdl"
|
|
14
|
-
}
|
|
14
|
+
})), Plugin.make);
|
|
15
15
|
//#endregion
|
|
16
16
|
export { GamePlugin, GamePlugin as default };
|
|
17
17
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GamePlugin.mjs","names":[],"sources":["../../src/GamePlugin.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport
|
|
1
|
+
{"version":3,"file":"GamePlugin.mjs","names":[],"sources":["../../src/GamePlugin.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Plugin from '@dxos/app-framework/Plugin';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\n\nimport { CreateObject, ReactSurface } from '#capabilities';\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../PLUGIN.mdl?raw';\nimport * as Game from './types/Game';\n\nexport const GamePlugin = Plugin.define(meta).pipe(\n Plugin.addModule(CreateObject),\n Plugin.addModule(AppCapability.schema([Game.Game])),\n Plugin.addModule(ReactSurface),\n Plugin.addModule(AppCapability.translations(translations)),\n Plugin.addModule(\n AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n }),\n ),\n Plugin.make,\n);\n\nexport default GamePlugin;\n"],"mappings":";;;;;;;;AAeA,IAAa,aAAa,OAAO,OAAO,IAAI,CAAC,CAAC,KAC5C,OAAO,UAAU,YAAY,GAC7B,OAAO,UAAU,cAAc,OAAO,CAAC,IAAS,CAAC,CAAC,GAClD,OAAO,UAAU,YAAY,GAC7B,OAAO,UAAU,cAAc,aAAa,YAAY,CAAC,GACzD,OAAO,UACL,cAAc,YAAY;CACxB,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC,CACH,GACA,OAAO,IACT"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Game } from "./Game.mjs";
|
|
2
2
|
import { meta } from "#meta";
|
|
3
|
-
import
|
|
3
|
+
import * as Plugin from "@dxos/app-framework/Plugin";
|
|
4
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
4
5
|
import { translations } from "#translations";
|
|
5
|
-
import { Game } from "#types";
|
|
6
6
|
//#region src/GamePlugin.node.tsx
|
|
7
7
|
/**
|
|
8
8
|
* Headless variant of GamePlugin (no React surfaces / CreateObject panel).
|
|
@@ -10,7 +10,7 @@ import { Game } from "#types";
|
|
|
10
10
|
* the full variant lazy-loads `CreateGamePanel` from `react-ui-search` which
|
|
11
11
|
* downstream bundlers don't resolve cleanly under nested pnpm symlinks.
|
|
12
12
|
*/
|
|
13
|
-
var GamePlugin = Plugin.define(meta).pipe(
|
|
13
|
+
var GamePlugin = Plugin.define(meta).pipe(Plugin.addModule(AppCapability.schema([Game])), Plugin.addModule(AppCapability.translations(translations)), Plugin.make);
|
|
14
14
|
//#endregion
|
|
15
15
|
export { GamePlugin, GamePlugin as default };
|
|
16
16
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GamePlugin.node.mjs","names":[],"sources":["../../src/GamePlugin.node.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport
|
|
1
|
+
{"version":3,"file":"GamePlugin.node.mjs","names":[],"sources":["../../src/GamePlugin.node.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Plugin from '@dxos/app-framework/Plugin';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\nimport * as Game from './types/Game';\n\n/**\n * Headless variant of GamePlugin (no React surfaces / CreateObject panel).\n * Used in node contexts (CLI, agents, tests) where rendering is unavailable —\n * the full variant lazy-loads `CreateGamePanel` from `react-ui-search` which\n * downstream bundlers don't resolve cleanly under nested pnpm symlinks.\n */\nexport const GamePlugin = Plugin.define(meta).pipe(\n Plugin.addModule(AppCapability.schema([Game.Game])),\n Plugin.addModule(AppCapability.translations(translations)),\n Plugin.make,\n);\n\nexport default GamePlugin;\n"],"mappings":";;;;;;;;;;;;AAkBA,IAAa,aAAa,OAAO,OAAO,IAAI,CAAC,CAAC,KAC5C,OAAO,UAAU,cAAc,OAAO,CAAC,IAAS,CAAC,CAAC,GAClD,OAAO,UAAU,cAAc,aAAa,YAAY,CAAC,GACzD,OAAO,IACT"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Game } from "./Game.mjs";
|
|
2
2
|
import { meta } from "#meta";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import * as Plugin from "@dxos/app-framework/Plugin";
|
|
4
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
5
5
|
//#region src/GamePlugin.workerd.tsx
|
|
6
|
-
var GamePlugin = Plugin.define(meta).pipe(
|
|
6
|
+
var GamePlugin = Plugin.define(meta).pipe(Plugin.addModule(AppCapability.schema([Game])), Plugin.make);
|
|
7
7
|
//#endregion
|
|
8
8
|
export { GamePlugin, GamePlugin as default };
|
|
9
9
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GamePlugin.workerd.mjs","names":[],"sources":["../../src/GamePlugin.workerd.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport
|
|
1
|
+
{"version":3,"file":"GamePlugin.workerd.mjs","names":[],"sources":["../../src/GamePlugin.workerd.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Plugin from '@dxos/app-framework/Plugin';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\n\nimport { meta } from '#meta';\n\nimport * as Game from './types/Game';\n\nexport const GamePlugin = Plugin.define(meta).pipe(Plugin.addModule(AppCapability.schema([Game.Game])), Plugin.make);\n\nexport default GamePlugin;\n"],"mappings":";;;;;AAWA,IAAa,aAAa,OAAO,OAAO,IAAI,CAAC,CAAC,KAAK,OAAO,UAAU,cAAc,OAAO,CAAC,IAAS,CAAC,CAAC,GAAG,OAAO,IAAI"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
1
2
|
import { Database, Obj, Type } from "@dxos/echo";
|
|
2
3
|
import * as Effect from "effect/Effect";
|
|
3
4
|
//#region src/util/load-game.ts
|
|
5
|
+
var load_game_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
GameVariantMismatchError: () => GameVariantMismatchError,
|
|
7
|
+
loadGame: () => loadGame
|
|
8
|
+
});
|
|
4
9
|
var GameVariantMismatchError = class extends Error {
|
|
5
10
|
gameId;
|
|
6
11
|
expectedTypename;
|
|
@@ -33,6 +38,6 @@ var loadGame = (ref, variantType) => Effect.gen(function* () {
|
|
|
33
38
|
};
|
|
34
39
|
});
|
|
35
40
|
//#endregion
|
|
36
|
-
export { loadGame
|
|
41
|
+
export { GameVariantMismatchError, loadGame, load_game_exports as t };
|
|
37
42
|
|
|
38
|
-
//# sourceMappingURL=
|
|
43
|
+
//# sourceMappingURL=GameUtil.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameUtil.mjs","names":[],"sources":["../../src/util/load-game.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Database, Obj, type Ref, Type } from '@dxos/echo';\n\nimport * as Game from '../types/Game';\n\nexport class GameVariantMismatchError extends Error {\n readonly _tag = 'GameVariantMismatchError';\n constructor(\n readonly gameId: string,\n readonly expectedTypename: string,\n readonly actualTypename: string,\n ) {\n super(`Game ${gameId} variant typename mismatch: expected ${expectedTypename}, got ${actualTypename}.`);\n }\n}\n\n/**\n * Loads a Game from a Ref and resolves its variant state, asserting the variant matches\n * the expected type. Returns the typed pair.\n *\n * Use in operation handlers that declare `input.game: GameRef<MyVariantState>`.\n */\nexport const loadGame = <S extends Type.AnyObj>(\n ref: Ref.Ref<Game.Game>,\n variantType: S,\n): Effect.Effect<{ game: Game.Game; variant: Type.InstanceType<S> }, Error, Database.Service> =>\n Effect.gen(function* () {\n const game = yield* Database.load(ref);\n const variant = yield* Database.load(game.variant);\n if (!Obj.instanceOf(variantType, variant)) {\n const expected = Type.getTypename(variantType) ?? 'unknown';\n const actual = Obj.getTypename(variant as Obj.Any) ?? 'unknown';\n return yield* Effect.fail(new GameVariantMismatchError(game.id, expected, actual));\n }\n return { game, variant: variant as Type.InstanceType<S> };\n });\n"],"mappings":";;;;;;;;AAUA,IAAa,2BAAb,cAA8C,MAAM;CAGvC;CACA;CACA;CAJX,OAAgB;CAChB,YACE,QACA,kBACA,gBACA;EACA,MAAM,QAAQ,OAAO,uCAAuC,iBAAiB,QAAQ,eAAe,EAAE;EAJ7F,KAAA,SAAA;EACA,KAAA,mBAAA;EACA,KAAA,iBAAA;CAGX;AACF;;;;;;;AAQA,IAAa,YACX,KACA,gBAEA,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO,SAAS,KAAK,GAAG;CACrC,MAAM,UAAU,OAAO,SAAS,KAAK,KAAK,OAAO;CACjD,IAAI,CAAC,IAAI,WAAW,aAAa,OAAO,GAAG;EACzC,MAAM,WAAW,KAAK,YAAY,WAAW,KAAK;EAClD,MAAM,SAAS,IAAI,YAAY,OAAkB,KAAK;EACtD,OAAO,OAAO,OAAO,KAAK,IAAI,yBAAyB,KAAK,IAAI,UAAU,MAAM,CAAC;CACnF;CACA,OAAO;EAAE;EAAe;CAAgC;AAC1D,CAAC"}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
2
|
+
import * as SpaceCapability from "@dxos/plugin-space/SpaceCapability";
|
|
2
3
|
//#region src/capabilities/index.ts
|
|
3
|
-
var CreateObject =
|
|
4
|
-
var ReactSurface =
|
|
4
|
+
var CreateObject = SpaceCapability.createObject(() => import("./chunk-create-object.mjs"));
|
|
5
|
+
var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: [
|
|
6
|
+
"org.dxos.role.article",
|
|
7
|
+
"org.dxos.role.cardContent",
|
|
8
|
+
"org.dxos.role.section"
|
|
9
|
+
] });
|
|
5
10
|
//#endregion
|
|
6
11
|
export { CreateObject, ReactSurface };
|
|
7
12
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport
|
|
1
|
+
{"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\n\nexport const CreateObject = SpaceCapability.createObject(() => import('./create-object'));\nexport const ReactSurface = AppCapability.surface(() => import('./react-surface'), {\n roles: ['org.dxos.role.article', 'org.dxos.role.cardContent', 'org.dxos.role.section'],\n});\n"],"mappings":";;;AAOA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,4BAAkB;AACxF,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAoB,EACjF,OAAO;CAAC;CAAyB;CAA6B;AAAuB,EACvF,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { VariantProvider } from "./GameCapabilities.mjs";
|
|
1
2
|
import { Obj } from "@dxos/echo";
|
|
2
3
|
import { meta } from "#meta";
|
|
3
|
-
import { GameCapabilities } from "#types";
|
|
4
4
|
import "react";
|
|
5
5
|
import { useCapabilities } from "@dxos/app-framework/ui";
|
|
6
6
|
import { useTranslation } from "@dxos/react-ui";
|
|
@@ -9,7 +9,7 @@ import { useResolveRef } from "@dxos/echo-react";
|
|
|
9
9
|
//#region src/containers/GameArticle/GameArticle.tsx
|
|
10
10
|
var GameArticle = ({ role, attendableId, subject: game }) => {
|
|
11
11
|
const { t } = useTranslation(meta.profile.key);
|
|
12
|
-
const variants = useCapabilities(
|
|
12
|
+
const variants = useCapabilities(VariantProvider);
|
|
13
13
|
const variant = useResolveRef(game.variant);
|
|
14
14
|
if (!variant) return null;
|
|
15
15
|
const variantTypename = Obj.getTypename(variant);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-GameArticle.mjs","names":[],"sources":["../../src/containers/GameArticle/GameArticle.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport { useCapabilities } from '@dxos/app-framework/ui';\nimport { type AppSurface } from '@dxos/app-toolkit/ui';\nimport { Obj } from '@dxos/echo';\nimport { useResolveRef } from '@dxos/echo-react';\nimport { useTranslation } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\nimport
|
|
1
|
+
{"version":3,"file":"chunk-GameArticle.mjs","names":[],"sources":["../../src/containers/GameArticle/GameArticle.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport { useCapabilities } from '@dxos/app-framework/ui';\nimport { type AppSurface } from '@dxos/app-toolkit/ui';\nimport { Obj } from '@dxos/echo';\nimport { useResolveRef } from '@dxos/echo-react';\nimport { useTranslation } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\n\nimport type * as Game from '../../types/Game';\nimport * as GameCapabilities from '../../types/GameCapabilities';\n\nexport type GameArticleProps = AppSurface.ObjectArticleProps<Game.Game>;\n\nexport const GameArticle = ({ role, attendableId, subject: game }: GameArticleProps) => {\n const { t } = useTranslation(meta.profile.key);\n const variants = useCapabilities(GameCapabilities.VariantProvider);\n // Resolved live rather than as a snapshot: variants mutate their state, and a snapshot is frozen.\n const variant = useResolveRef(game.variant);\n\n if (!variant) {\n return null;\n }\n\n const variantTypename = Obj.getTypename(variant);\n const match = variants.find((v) => v.id === variantTypename);\n if (!match?.article) {\n return (\n <div className='p-4 text-sm'>{t('unsupported-variant.label', { defaultValue: 'Unsupported game variant' })}</div>\n );\n }\n\n const Component = match.article;\n return <Component game={game} variant={variant} role={role} attendableId={attendableId} />;\n};\n\nGameArticle.displayName = 'GameArticle';\n"],"mappings":";;;;;;;;;AAmBA,IAAa,eAAe,EAAE,MAAM,cAAc,SAAS,WAA6B;CACtF,MAAM,EAAE,MAAM,eAAe,KAAK,QAAQ,GAAG;CAC7C,MAAM,WAAW,gBAAgB,eAAgC;CAEjE,MAAM,UAAU,cAAc,KAAK,OAAO;CAE1C,IAAI,CAAC,SACH,OAAO;CAGT,MAAM,kBAAkB,IAAI,YAAY,OAAO;CAC/C,MAAM,QAAQ,SAAS,MAAM,MAAM,EAAE,OAAO,eAAe;CAC3D,IAAI,CAAC,OAAO,SACV,OACE,oBAAC,OAAD;EAAK,WAAU;YAAe,EAAE,6BAA6B,EAAE,cAAc,2BAA2B,CAAC;CAAO,CAAA;CAIpH,MAAM,YAAY,MAAM;CACxB,OAAO,oBAAC,WAAD;EAAiB;EAAe;EAAe;EAAoB;CAAe,CAAA;AAC3F;AAEA,YAAY,cAAc"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { VariantProvider } from "./GameCapabilities.mjs";
|
|
1
2
|
import { Obj } from "@dxos/echo";
|
|
2
|
-
import { GameCapabilities } from "#types";
|
|
3
3
|
import "react";
|
|
4
4
|
import { useCapabilities } from "@dxos/app-framework/ui";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
import { useResolveRef } from "@dxos/echo-react";
|
|
7
7
|
//#region src/containers/GameCard/GameCard.tsx
|
|
8
8
|
var GameCard = ({ role, subject: game }) => {
|
|
9
|
-
const variants = useCapabilities(
|
|
9
|
+
const variants = useCapabilities(VariantProvider);
|
|
10
10
|
const variant = useResolveRef(game.variant);
|
|
11
11
|
if (!variant) return null;
|
|
12
12
|
const variantTypename = Obj.getTypename(variant);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-GameCard.mjs","names":[],"sources":["../../src/containers/GameCard/GameCard.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport { useCapabilities } from '@dxos/app-framework/ui';\nimport { type AppSurface } from '@dxos/app-toolkit/ui';\nimport { Obj } from '@dxos/echo';\nimport { useResolveRef } from '@dxos/echo-react';\n\nimport
|
|
1
|
+
{"version":3,"file":"chunk-GameCard.mjs","names":[],"sources":["../../src/containers/GameCard/GameCard.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport { useCapabilities } from '@dxos/app-framework/ui';\nimport { type AppSurface } from '@dxos/app-toolkit/ui';\nimport { Obj } from '@dxos/echo';\nimport { useResolveRef } from '@dxos/echo-react';\n\nimport type * as Game from '../../types/Game';\nimport * as GameCapabilities from '../../types/GameCapabilities';\n\nexport type GameCardProps = AppSurface.ObjectCardProps<Game.Game>;\n\nexport const GameCard = ({ role, subject: game }: GameCardProps) => {\n const variants = useCapabilities(GameCapabilities.VariantProvider);\n // Resolved live rather than as a snapshot: variants mutate their state, and a snapshot is frozen.\n const variant = useResolveRef(game.variant);\n\n if (!variant) {\n return null;\n }\n\n const variantTypename = Obj.getTypename(variant);\n const match = variants.find((v) => v.id === variantTypename);\n if (!match?.card) {\n return null;\n }\n\n const Component = match.card;\n return <Component game={game} variant={variant} role={role} />;\n};\n\nGameCard.displayName = 'GameCard';\n"],"mappings":";;;;;;;AAgBA,IAAa,YAAY,EAAE,MAAM,SAAS,WAA0B;CAClE,MAAM,WAAW,gBAAgB,eAAgC;CAEjE,MAAM,UAAU,cAAc,KAAK,OAAO;CAE1C,IAAI,CAAC,SACH,OAAO;CAGT,MAAM,kBAAkB,IAAI,YAAY,OAAO;CAC/C,MAAM,QAAQ,SAAS,MAAM,MAAM,EAAE,OAAO,eAAe;CAC3D,IAAI,CAAC,OAAO,MACV,OAAO;CAGT,MAAM,YAAY,MAAM;CACxB,OAAO,oBAAC,WAAD;EAAiB;EAAe;EAAe;CAAO,CAAA;AAC/D;AAEA,SAAS,cAAc"}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Game, make } from "./Game.mjs";
|
|
2
|
+
import { VariantProvider } from "./GameCapabilities.mjs";
|
|
3
3
|
import { Database, Type } from "@dxos/echo";
|
|
4
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
4
5
|
import * as Effect from "effect/Effect";
|
|
5
|
-
import
|
|
6
|
+
import * as Operation from "@dxos/compute/Operation";
|
|
6
7
|
import { invariant } from "@dxos/invariant";
|
|
7
|
-
import {
|
|
8
|
+
import { SpaceOperation } from "@dxos/plugin-space";
|
|
9
|
+
import * as SpaceCapabilities from "@dxos/plugin-space/SpaceCapabilities";
|
|
8
10
|
import { CreateGamePanel } from "#components";
|
|
9
11
|
//#region src/capabilities/create-object.ts
|
|
10
12
|
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-game/src/capabilities/create-object.ts";
|
|
11
13
|
var create_object_default = Capability.makeModule(Effect.fnUntraced(function* () {
|
|
12
|
-
return Capability.
|
|
14
|
+
return Capability.contribute(SpaceCapabilities.CreateObjectEntry, {
|
|
13
15
|
id: Type.getTypename(Game),
|
|
14
16
|
customPanel: CreateGamePanel,
|
|
15
17
|
createObject: ({ variantId, input }, options) => Effect.gen(function* () {
|
|
@@ -17,7 +19,7 @@ var create_object_default = Capability.makeModule(Effect.fnUntraced(function* ()
|
|
|
17
19
|
invariant(variant, `Unknown game variant: ${variantId}`, {
|
|
18
20
|
"~LogMeta": "~LogMeta",
|
|
19
21
|
F: __dxlog_file,
|
|
20
|
-
L:
|
|
22
|
+
L: 33,
|
|
21
23
|
S: this,
|
|
22
24
|
A: ["variant", "`Unknown game variant: ${variantId}`"]
|
|
23
25
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-create-object.mjs","names":[],"sources":["../../src/capabilities/create-object.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport
|
|
1
|
+
{"version":3,"file":"chunk-create-object.mjs","names":[],"sources":["../../src/capabilities/create-object.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, Type } from '@dxos/echo';\nimport { invariant } from '@dxos/invariant';\nimport { SpaceOperation } from '@dxos/plugin-space';\nimport * as SpaceCapabilities from '@dxos/plugin-space/SpaceCapabilities';\n\nimport { CreateGamePanel } from '#components';\n\nimport * as Game from '../types/Game';\nimport * as GameCapabilities from '../types/GameCapabilities';\n\ntype CreateOptions = Parameters<SpaceCapabilities.CreateObjectEntry['createObject']>[1];\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return Capability.contribute(SpaceCapabilities.CreateObjectEntry, {\n id: Type.getTypename(Game.Game),\n customPanel: CreateGamePanel,\n createObject: (\n { variantId, input }: { variantId: string; input?: Record<string, any> },\n options: CreateOptions,\n ) =>\n Effect.gen(function* () {\n const variants = yield* Capability.getAll(GameCapabilities.VariantProvider);\n const variant = variants.find((v) => v.id === variantId);\n invariant(variant, `Unknown game variant: ${variantId}`);\n\n // Build variant state object via the variant's factory.\n const stateObject = yield* variant\n .createVariant(input ?? {})\n .pipe(Effect.provideService(Database.Service, Database.makeService(options.db)));\n\n // Add variant state to the database. Stays hidden — it's referenced by Game and\n // shouldn't appear as a top-level item in the user's space.\n yield* Operation.invoke(SpaceOperation.AddObject, {\n object: stateObject,\n target: options.target,\n targetNodeId: options.targetNodeId,\n });\n\n const game = Game.make({\n name: typeof input?.name === 'string' ? input.name : undefined,\n variant: stateObject,\n });\n\n // Add the user-facing Game wrapper. Not hidden — this is the object the user sees\n // and navigates to. If this second write fails, roll back the variant state so we\n // don't leak an orphaned object into the space.\n return yield* Operation.invoke(SpaceOperation.AddObject, {\n object: game,\n target: options.target,\n targetNodeId: options.targetNodeId,\n }).pipe(\n Effect.tapError(() =>\n Operation.invoke(SpaceOperation.RemoveObjects, { objects: [stateObject] }).pipe(Effect.ignore),\n ),\n );\n }),\n });\n }),\n);\n"],"mappings":";;;;;;;;;;;;AAoBA,IAAA,wBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,OAAO,WAAW,WAAW,kBAAkB,mBAAmB;EAChE,IAAI,KAAK,YAAY,IAAS;EAC9B,aAAa;EACb,eACE,EAAE,WAAW,SACb,YAEA,OAAO,IAAI,aAAa;GAEtB,MAAM,WAAU,OADQ,WAAW,OAAO,eAAgC,EAAA,CACjD,MAAM,MAAM,EAAE,OAAO,SAAS;GACvD,UAAU,SAAS,yBAAyB,aAAU;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,CAAA,WAAA,sCAAA;GAAA,CAAC;GAGvD,MAAM,cAAc,OAAO,QACxB,cAAc,SAAS,CAAC,CAAC,CAAA,CACzB,KAAK,OAAO,eAAe,SAAS,SAAS,SAAS,YAAY,QAAQ,EAAE,CAAC,CAAC;GAIjF,OAAO,UAAU,OAAO,eAAe,WAAW;IAChD,QAAQ;IACR,QAAQ,QAAQ;IAChB,cAAc,QAAQ;GACxB,CAAC;GAED,MAAM,OAAO,KAAU;IACrB,MAAM,OAAO,OAAO,SAAS,WAAW,MAAM,OAAO,KAAA;IACrD,SAAS;GACX,CAAC;GAKD,OAAO,OAAO,UAAU,OAAO,eAAe,WAAW;IACvD,QAAQ;IACR,QAAQ,QAAQ;IAChB,cAAc,QAAQ;GACxB,CAAC,CAAC,CAAC,KACD,OAAO,eACL,UAAU,OAAO,eAAe,eAAe,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,KAAK,OAAO,MAAM,CAC/F,CACF;EACF,CAAC;CACL,CAAC;AACH,CAAC,CACH"}
|
package/dist/lib/chunk-meta.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-meta.mjs","names":[],"sources":["../../dx.config.ts","../../src/meta.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Config2 } from '@dxos/app-framework/config';\nimport { trim } from '@dxos/util';\n\nexport default Config2.make({\n plugin: {\n key: 'org.dxos.plugin.game',\n name: 'Game',\n author: 'DXOS',\n description: trim`\n Generic game host plugin that provides shared infrastructure for local-first,\n multi-player turn-based games inside DXOS Composer. The plugin owns the base\n \\`Game\\` ECHO type — which stores players and a reference to variant-specific\n state — and drives the two-stage game-creation flow (variant picker + optional\n input form).\n\n Game variants (chess, tic-tac-toe, and others) are contributed by separate\n plugins via the \\`GameCapabilities.VariantProvider\\` capability. Each variant supplies\n its own state schema, player roles, create factory, and surface components\n (Article and Card). Plugin-game resolves the correct variant at runtime and\n delegates rendering, keeping the host layer fully decoupled from game logic.\n\n Variant state objects are stored as hidden ECHO objects alongside the top-level\n \\`Game\\`, ensuring they replicate to all peers but do not appear as independent\n items in the user's space graph. The entire creation flow is atomic: if the\n Game write fails, the variant state is rolled back automatically.\n `,\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-game',\n icon: { key: 'ph--sword--regular', hue: 'indigo' },\n spec: 'PLUGIN.mdl',\n screenshots: [\n {\n dark: 'https://customer-5rxcjpyab08avpmn.cloudflarestream.com/2797d56edc9658d018ad75fe48a47f27/iframe?poster=https%3A%2F%2Fcustomer-5rxcjpyab08avpmn.cloudflarestream.com%2F2797d56edc9658d018ad75fe48a47f27%2Fthumbnails%2Fthumbnail.jpg%3Ftime%3D%26height%3D600',\n },\n ],\n tags: ['alpha'],\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport
|
|
1
|
+
{"version":3,"file":"chunk-meta.mjs","names":[],"sources":["../../dx.config.ts","../../src/meta.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Config2 } from '@dxos/app-framework/config';\nimport { trim } from '@dxos/util';\n\nexport default Config2.make({\n plugin: {\n key: 'org.dxos.plugin.game',\n name: 'Game',\n author: 'DXOS',\n description: trim`\n Generic game host plugin that provides shared infrastructure for local-first,\n multi-player turn-based games inside DXOS Composer. The plugin owns the base\n \\`Game\\` ECHO type — which stores players and a reference to variant-specific\n state — and drives the two-stage game-creation flow (variant picker + optional\n input form).\n\n Game variants (chess, tic-tac-toe, and others) are contributed by separate\n plugins via the \\`GameCapabilities.VariantProvider\\` capability. Each variant supplies\n its own state schema, player roles, create factory, and surface components\n (Article and Card). Plugin-game resolves the correct variant at runtime and\n delegates rendering, keeping the host layer fully decoupled from game logic.\n\n Variant state objects are stored as hidden ECHO objects alongside the top-level\n \\`Game\\`, ensuring they replicate to all peers but do not appear as independent\n items in the user's space graph. The entire creation flow is atomic: if the\n Game write fails, the variant state is rolled back automatically.\n `,\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-game',\n icon: { key: 'ph--sword--regular', hue: 'indigo' },\n spec: 'PLUGIN.mdl',\n screenshots: [\n {\n dark: 'https://customer-5rxcjpyab08avpmn.cloudflarestream.com/2797d56edc9658d018ad75fe48a47f27/iframe?poster=https%3A%2F%2Fcustomer-5rxcjpyab08avpmn.cloudflarestream.com%2F2797d56edc9658d018ad75fe48a47f27%2Fthumbnails%2Fthumbnail.jpg%3Ftime%3D%26height%3D600',\n },\n ],\n tags: ['alpha'],\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Plugin from '@dxos/app-framework/Plugin';\n\nimport config from '../dx.config';\n\nexport const meta = Plugin.getMetaFromConfig(config);\n"],"mappings":";;;;AAOA,IAAA,oBAAe,QAAQ,KAAK,EAC1B,QAAQ;CACN,KAAK;CACL,MAAM;CACN,QAAQ;CACR,aAAa,IAAI;;;;;;;;;;;;;;;;;;CAkBjB,QAAQ;CACR,MAAM;EAAE,KAAK;EAAsB,KAAK;CAAS;CACjD,MAAM;CACN,aAAa,CACX,EACE,MAAM,8PACR,CACF;CACA,MAAM,CAAC,OAAO;AAChB,EACF,CAAC;;;AChCD,IAAa,OAAO,OAAO,kBAAkB,iBAAM"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { Game } from "./Game.mjs";
|
|
2
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
4
|
import { Surface } from "@dxos/app-framework/ui";
|
|
5
|
+
import * as Capabilities from "@dxos/app-framework/Capabilities";
|
|
5
6
|
import { AppSurface } from "@dxos/app-toolkit/ui";
|
|
6
7
|
import { GameArticle, GameCard } from "#containers";
|
|
7
8
|
//#region src/capabilities/react-surface.ts
|
|
8
|
-
var react_surface_default = Capability.makeModule(() => Effect.succeed(Capability.
|
|
9
|
+
var react_surface_default = Capability.makeModule(() => Effect.succeed(Capability.contribute(Capabilities.ReactSurface, [Surface.create({
|
|
9
10
|
id: "game",
|
|
10
11
|
filter: AppSurface.oneOf(AppSurface.object(AppSurface.Article, Game), AppSurface.object(AppSurface.Section, Game)),
|
|
11
12
|
component: GameArticle,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-react-surface.mjs","names":[],"sources":["../../src/capabilities/react-surface.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport
|
|
1
|
+
{"version":3,"file":"chunk-react-surface.mjs","names":[],"sources":["../../src/capabilities/react-surface.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport { Surface } from '@dxos/app-framework/ui';\nimport { AppSurface } from '@dxos/app-toolkit/ui';\n\nimport { GameArticle, GameCard } from '#containers';\n\nimport * as Game from '../types/Game';\n\nexport default Capability.makeModule(() =>\n Effect.succeed(\n Capability.contribute(Capabilities.ReactSurface, [\n Surface.create({\n id: 'game',\n filter: AppSurface.oneOf(\n AppSurface.object(AppSurface.Article, Game.Game),\n AppSurface.object(AppSurface.Section, Game.Game),\n ),\n component: GameArticle,\n props: ({ role, data: { subject, attendableId } }) => ({ role, subject, attendableId }),\n }),\n Surface.create({\n id: 'gameCard',\n filter: AppSurface.object(AppSurface.CardContent, Game.Game),\n component: GameCard,\n props: ({ role, data: { subject } }) => ({ role, subject }),\n }),\n ]),\n ),\n);\n"],"mappings":";;;;;;;;AAeA,IAAA,wBAAe,WAAW,iBACxB,OAAO,QACL,WAAW,WAAW,aAAa,cAAc,CAC/C,QAAQ,OAAO;CACb,IAAI;CACJ,QAAQ,WAAW,MACjB,WAAW,OAAO,WAAW,SAAS,IAAS,GAC/C,WAAW,OAAO,WAAW,SAAS,IAAS,CACjD;CACA,WAAW;CACX,QAAQ,EAAE,MAAM,MAAM,EAAE,SAAS,sBAAsB;EAAE;EAAM;EAAS;CAAa;AACvF,CAAC,GACD,QAAQ,OAAO;CACb,IAAI;CACJ,QAAQ,WAAW,OAAO,WAAW,aAAa,IAAS;CAC3D,WAAW;CACX,QAAQ,EAAE,MAAM,MAAM,EAAE,iBAAiB;EAAE;EAAM;CAAQ;AAC3D,CAAC,CACH,CAAC,CACH,CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __exportAll = (all, no_symbols) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) __defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true
|
|
8
|
+
});
|
|
9
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
10
|
+
return target;
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { __exportAll as t };
|
package/dist/lib/components.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { VariantProvider } from "./GameCapabilities.mjs";
|
|
1
2
|
import { Obj } from "@dxos/echo";
|
|
2
3
|
import { meta } from "#meta";
|
|
3
|
-
import { GameCapabilities } from "#types";
|
|
4
4
|
import { useCallback, useMemo, useState } from "react";
|
|
5
5
|
import { useCapabilities } from "@dxos/app-framework/ui";
|
|
6
6
|
import { Column, useTranslation } from "@dxos/react-ui";
|
|
@@ -10,7 +10,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
10
10
|
//#region src/components/CreateGamePanel.tsx
|
|
11
11
|
/**
|
|
12
12
|
* Two-stage create panel for games:
|
|
13
|
-
* 1. Variant picker (SearchList over contributed `GameVariant[]`).
|
|
13
|
+
* 1. Variant picker (SearchList over contributed `GameCapabilities.GameVariant[]`).
|
|
14
14
|
* 2. Variant-specific input form (rendered from variant.inputSchema).
|
|
15
15
|
*
|
|
16
16
|
* On submit, calls `onCreateObject({ variantId, name, input })` where `input` is the
|
|
@@ -19,7 +19,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
19
19
|
* it in a Game.
|
|
20
20
|
*/
|
|
21
21
|
var CreateGamePanel = ({ target, onCreateObject, variants: variantsProp }) => {
|
|
22
|
-
const capabilityVariants = useCapabilities(
|
|
22
|
+
const capabilityVariants = useCapabilities(VariantProvider);
|
|
23
23
|
const variants = variantsProp ?? capabilityVariants;
|
|
24
24
|
const [selectedId, setSelectedId] = useState(void 0);
|
|
25
25
|
const selected = useMemo(() => variants.find((v) => v.id === selectedId), [variants, selectedId]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.mjs","names":[],"sources":["../../src/components/CreateGamePanel.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport { useCapabilities } from '@dxos/app-framework/ui';\nimport { Obj } from '@dxos/echo';\nimport
|
|
1
|
+
{"version":3,"file":"components.mjs","names":[],"sources":["../../src/components/CreateGamePanel.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport { useCapabilities } from '@dxos/app-framework/ui';\nimport { Obj } from '@dxos/echo';\nimport type * as SpaceCapabilities from '@dxos/plugin-space/SpaceCapabilities';\nimport { Column, useTranslation } from '@dxos/react-ui';\nimport { Form, omitId } from '@dxos/react-ui-form';\nimport { SearchList, useSearchListResults } from '@dxos/react-ui-search';\n\nimport { meta } from '#meta';\n\nimport * as GameCapabilities from '../types/GameCapabilities';\n\nexport type CreateGamePanelProps = SpaceCapabilities.CreateObjectCustomPanelProps & {\n /** Optional override (primarily for stories/tests). Defaults to GameCapabilities.VariantProvider. */\n variants?: GameCapabilities.GameVariant[];\n};\n\n/**\n * Two-stage create panel for games:\n * 1. Variant picker (SearchList over contributed `GameCapabilities.GameVariant[]`).\n * 2. Variant-specific input form (rendered from variant.inputSchema).\n *\n * On submit, calls `onCreateObject({ variantId, name, input })` where `input` is the\n * variant-specific form values. Plugin-game's CreateObjectEntry.createObject resolves\n * the variantId, builds the variant state object via variant.createVariant, then wraps\n * it in a Game.\n */\nexport const CreateGamePanel = ({ target, onCreateObject, variants: variantsProp }: CreateGamePanelProps) => {\n const capabilityVariants = useCapabilities(GameCapabilities.VariantProvider);\n const variants = variantsProp ?? capabilityVariants;\n const [selectedId, setSelectedId] = useState<string | undefined>(undefined);\n const selected = useMemo(() => variants.find((v) => v.id === selectedId), [variants, selectedId]);\n\n const handleSelect = useCallback(\n (id: string) => {\n const variant = variants.find((v) => v.id === id);\n if (!variant) {\n return;\n }\n if (!variant.inputSchema) {\n void onCreateObject({ variantId: id });\n return;\n }\n setSelectedId(id);\n },\n [variants, onCreateObject],\n );\n\n const handleSubmit = useCallback(\n (input: Record<string, any>) => {\n if (!selected) {\n return;\n }\n void onCreateObject({ variantId: selected.id, input });\n },\n [selected, onCreateObject],\n );\n\n if (!selected) {\n return <VariantPicker variants={variants} onSelect={handleSelect} />;\n }\n\n const schema = selected.inputSchema ? omitId(selected.inputSchema) : undefined;\n if (!schema) {\n return null;\n }\n\n return (\n <Form.Root\n autoFocus\n schema={schema}\n defaultValues={{}}\n db={Obj.isObject(target) ? Obj.getDatabase(target) : target}\n onSave={handleSubmit}\n testId='create-game-form'\n >\n {/* Rendered inside the create dialog's Dialog.Body (which owns the gutter Column); use\n Column.Center to align with the dialog title rather than nesting another Column.Root. */}\n <Column.Center>\n <Form.Content>\n <Form.FieldSet />\n <Form.Submit />\n </Form.Content>\n </Column.Center>\n </Form.Root>\n );\n};\n\ntype VariantPickerProps = {\n variants: GameCapabilities.GameVariant[];\n onSelect: (id: string) => void;\n};\n\nconst VariantPicker = ({ variants, onSelect }: VariantPickerProps) => {\n const { t } = useTranslation(meta.profile.key);\n const sorted = useMemo(() => [...variants].sort((a, b) => a.label.localeCompare(b.label)), [variants]);\n const { results, handleSearch } = useSearchListResults({\n items: sorted,\n extract: (variant) => variant.label,\n });\n\n return (\n <SearchList.Root onSearch={handleSearch}>\n <SearchList.Input\n classNames='mb-form-gap'\n autoFocus\n data-testid='create-game-panel.variant-input'\n placeholder={t('create-panel.variant.placeholder')}\n />\n <SearchList.Viewport>\n {results.map((variant) => (\n <SearchList.Item\n key={variant.id}\n value={variant.id}\n label={variant.label}\n icon={variant.icon ?? 'ph--sword--regular'}\n onSelect={() => onSelect(variant.id)}\n />\n ))}\n </SearchList.Viewport>\n </SearchList.Root>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAgCA,IAAa,mBAAmB,EAAE,QAAQ,gBAAgB,UAAU,mBAAyC;CAC3G,MAAM,qBAAqB,gBAAgB,eAAgC;CAC3E,MAAM,WAAW,gBAAgB;CACjC,MAAM,CAAC,YAAY,iBAAiB,SAA6B,KAAA,CAAS;CAC1E,MAAM,WAAW,cAAc,SAAS,MAAM,MAAM,EAAE,OAAO,UAAU,GAAG,CAAC,UAAU,UAAU,CAAC;CAEhG,MAAM,eAAe,aAClB,OAAe;EACd,MAAM,UAAU,SAAS,MAAM,MAAM,EAAE,OAAO,EAAE;EAChD,IAAI,CAAC,SACH;EAEF,IAAI,CAAC,QAAQ,aAAa;GACxB,eAAoB,EAAE,WAAW,GAAG,CAAC;GACrC;EACF;EACA,cAAc,EAAE;CAClB,GACA,CAAC,UAAU,cAAc,CAC3B;CAEA,MAAM,eAAe,aAClB,UAA+B;EAC9B,IAAI,CAAC,UACH;EAEF,eAAoB;GAAE,WAAW,SAAS;GAAI;EAAM,CAAC;CACvD,GACA,CAAC,UAAU,cAAc,CAC3B;CAEA,IAAI,CAAC,UACH,OAAO,oBAAC,eAAD;EAAyB;EAAU,UAAU;CAAe,CAAA;CAGrE,MAAM,SAAS,SAAS,cAAc,OAAO,SAAS,WAAW,IAAI,KAAA;CACrE,IAAI,CAAC,QACH,OAAO;CAGT,OACE,oBAAC,KAAK,MAAN;EACE,WAAA;EACQ;EACR,eAAe,CAAC;EAChB,IAAI,IAAI,SAAS,MAAM,IAAI,IAAI,YAAY,MAAM,IAAI;EACrD,QAAQ;EACR,QAAO;YAIP,oBAAC,OAAO,QAAR,EAAA,UACE,qBAAC,KAAK,SAAN,EAAA,UAAA,CACE,oBAAC,KAAK,UAAN,CAAgB,CAAA,GAChB,oBAAC,KAAK,QAAN,CAAc,CAAA,CACF,EAAA,CAAA,EACD,CAAA;CACN,CAAA;AAEf;AAOA,IAAM,iBAAiB,EAAE,UAAU,eAAmC;CACpE,MAAM,EAAE,MAAM,eAAe,KAAK,QAAQ,GAAG;CAE7C,MAAM,EAAE,SAAS,iBAAiB,qBAAqB;EACrD,OAFa,cAAc,CAAC,GAAG,QAAQ,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,CAE3F;EACP,UAAU,YAAY,QAAQ;CAChC,CAAC;CAED,OACE,qBAAC,WAAW,MAAZ;EAAiB,UAAU;YAA3B,CACE,oBAAC,WAAW,OAAZ;GACE,YAAW;GACX,WAAA;GACA,eAAY;GACZ,aAAa,EAAE,kCAAkC;EAClD,CAAA,GACD,oBAAC,WAAW,UAAZ,EAAA,UACG,QAAQ,KAAK,YACZ,oBAAC,WAAW,MAAZ;GAEE,OAAO,QAAQ;GACf,OAAO,QAAQ;GACf,MAAM,QAAQ,QAAQ;GACtB,gBAAgB,SAAS,QAAQ,EAAE;EACpC,GALM,QAAQ,EAKd,CACF,EACkB,CAAA,CACN;;AAErB"}
|
package/dist/lib/index.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as Game_exports } from "./Game.mjs";
|
|
2
|
+
import { t as GameCapabilities_exports } from "./GameCapabilities.mjs";
|
|
3
|
+
import { t as GameEvents_exports } from "./GameEvents.mjs";
|
|
4
|
+
import { t as load_game_exports } from "./GameUtil.mjs";
|
|
2
5
|
import { t as meta } from "./chunk-meta.mjs";
|
|
3
|
-
|
|
4
|
-
export { Game_exports as Game, GameCapabilities_exports as GameCapabilities, GameVariantMismatchError, loadGame, meta };
|
|
6
|
+
export { Game_exports as Game, GameCapabilities_exports as GameCapabilities, GameEvents_exports as GameEvents, load_game_exports as GameUtil, meta };
|
package/dist/lib/plugin.mjs
CHANGED
package/dist/lib/plugin.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.mjs","names":[],"sources":["../../src/plugin.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":[],"sources":["../../src/plugin.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Plugin from '@dxos/app-framework/Plugin';\n\nimport { meta } from './meta';\n\nexport const GamePlugin = Plugin.lazy(meta, () => import('#plugin'));\n"],"mappings":";;;AAQA,IAAa,aAAa,OAAO,KAAK,YAAY,OAAO,UAAU"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { Game } from "./Game.mjs";
|
|
1
2
|
import { Type } from "@dxos/echo";
|
|
2
3
|
import { meta } from "#meta";
|
|
3
|
-
import { Game } from "#types";
|
|
4
4
|
//#region src/translations.ts
|
|
5
5
|
var translations = [{ "en-US": {
|
|
6
|
-
[Type.getTypename(Game
|
|
6
|
+
[Type.getTypename(Game)]: {
|
|
7
7
|
"typename.label": "Game",
|
|
8
8
|
"typename.label_zero": "Games",
|
|
9
9
|
"typename.label_one": "Game",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translations.mjs","names":[],"sources":["../../src/translations.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Type } from '@dxos/echo';\nimport { type Resource } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\nimport
|
|
1
|
+
{"version":3,"file":"translations.mjs","names":[],"sources":["../../src/translations.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Type } from '@dxos/echo';\nimport { type Resource } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\n\nimport * as Game from './types/Game';\n\nexport const translations = [\n {\n 'en-US': {\n [Type.getTypename(Game.Game)]: {\n 'typename.label': 'Game',\n 'typename.label_zero': 'Games',\n 'typename.label_one': 'Game',\n 'typename.label_other': 'Games',\n 'object-name.placeholder': 'New game',\n 'add-object.label': 'Add game',\n 'rename-object.label': 'Rename game',\n 'delete-object.label': 'Delete game',\n 'object-deleted.label': 'Game deleted',\n },\n [meta.profile.key]: {\n 'plugin.name': 'Game',\n 'create-panel.variant.label': 'Select variant',\n 'create-panel.variant.placeholder': 'Search variants...',\n 'create-panel.submit.label': 'Create',\n 'unsupported-variant.label': 'Unsupported game variant',\n },\n },\n },\n] as const satisfies Resource[];\n"],"mappings":";;;;AAWA,IAAa,eAAe,CAC1B,EACE,SAAS;EACN,KAAK,YAAY,IAAS,IAAI;EAC7B,kBAAkB;EAClB,uBAAuB;EACvB,sBAAsB;EACtB,wBAAwB;EACxB,2BAA2B;EAC3B,oBAAoB;EACpB,uBAAuB;EACvB,uBAAuB;EACvB,wBAAwB;CAC1B;EACC,KAAK,QAAQ,MAAM;EAClB,eAAe;EACf,8BAA8B;EAC9B,oCAAoC;EACpC,6BAA6B;EAC7B,6BAA6B;CAC/B;AACF,EACF,CACF"}
|
package/dist/lib/util.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GameVariantMismatchError, loadGame } from "./GameUtil.mjs";
|
|
2
2
|
export { GameVariantMismatchError, loadGame };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GamePlugin.d.ts","sourceRoot":"","sources":["../../../src/GamePlugin.tsx"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"GamePlugin.d.ts","sourceRoot":"","sources":["../../../src/GamePlugin.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,MAAM,4BAA4B,CAAC;AAWrD,eAAO,MAAM,UAAU,4BActB,CAAC;eAEa,UAAU"}
|