@mpgd/cli 0.6.0 → 0.7.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/dist/game-acceptance.d.ts +65 -0
- package/dist/game-acceptance.js +245 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +404 -3
- package/dist/production-target-readiness.d.ts +8 -0
- package/dist/production-target-readiness.js +207 -0
- package/package.json +11 -11
- package/templates/phaser-game/README.md +71 -1
- package/templates/phaser-game/agent/acceptance.md +12 -6
- package/templates/phaser-game/agent/brief.md +3 -1
- package/templates/phaser-game/agent/game-manifest.json +7 -0
- package/templates/phaser-game/apps/target-devvit/README.md +30 -0
- package/templates/phaser-game/apps/target-devvit/devvit.json +7 -0
- package/templates/phaser-game/apps/target-devvit/package.json +8 -5
- package/templates/phaser-game/apps/target-devvit/src/server/postOperationStore.ts +9 -0
- package/templates/phaser-game/game.html +13 -0
- package/templates/phaser-game/gitignore +2 -0
- package/templates/phaser-game/index.html +2 -2
- package/templates/phaser-game/mpgd.game.json +8 -0
- package/templates/phaser-game/mpgd.targets.json +6 -0
- package/templates/phaser-game/package.json +7 -1
- package/templates/phaser-game/public/manifest.webmanifest +1 -0
- package/templates/phaser-game/src/entry.ts +7 -0
- package/templates/phaser-game/src/env.d.ts +3 -0
- package/templates/phaser-game/src/gameEntry.ts +3 -0
- package/templates/phaser-game/src/main.ts +11 -2
- package/templates/phaser-game/src/platform/buildGatewayModule.ts +5 -0
- package/templates/phaser-game/src/platform/buildGateways/ait.ts +11 -0
- package/templates/phaser-game/src/platform/buildGateways/aitSandbox.ts +12 -0
- package/templates/phaser-game/src/platform/buildGateways/browser.ts +8 -0
- package/templates/phaser-game/src/platform/buildGateways/capacitorAndroid.ts +12 -0
- package/templates/phaser-game/src/platform/buildGateways/capacitorIos.ts +12 -0
- package/templates/phaser-game/src/platform/buildGateways/reddit.ts +11 -0
- package/templates/phaser-game/src/platform/buildGateways/redditSandbox.ts +15 -0
- package/templates/phaser-game/src/platform/devvitEntrypoint.ts +57 -0
- package/templates/phaser-game/src/platform/devvitInlinePreview.css +75 -0
- package/templates/phaser-game/src/platform/gameServices.ts +18 -61
- package/templates/phaser-game/src/platform/installPlatform.ts +6 -50
- package/templates/phaser-game/src/platform/microsoftStorePwa.ts +99 -0
- package/templates/phaser-game/tools/run-game-acceptance.mjs +22 -0
- package/templates/phaser-game/vite.config.ts +106 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mpgd/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Gunshi CLI for mpgd-kit starter generation and target workflow orchestration.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -49,18 +49,18 @@
|
|
|
49
49
|
"@types/node": "^24.0.0",
|
|
50
50
|
"ttsc": "0.16.9",
|
|
51
51
|
"typescript": "7.0.1-rc",
|
|
52
|
-
"@mpgd/adapter-
|
|
53
|
-
"@mpgd/adapter-devvit": "0.
|
|
54
|
-
"@mpgd/
|
|
55
|
-
"@mpgd/
|
|
56
|
-
"@mpgd/adapter-
|
|
52
|
+
"@mpgd/adapter-ait": "0.4.1",
|
|
53
|
+
"@mpgd/adapter-devvit": "0.5.0",
|
|
54
|
+
"@mpgd/analytics": "0.3.4",
|
|
55
|
+
"@mpgd/adapter-browser": "0.4.1",
|
|
56
|
+
"@mpgd/adapter-capacitor": "0.4.1",
|
|
57
57
|
"@mpgd/bridge": "0.5.0",
|
|
58
|
-
"@mpgd/catalog": "0.3.
|
|
59
|
-
"@mpgd/
|
|
60
|
-
"@mpgd/
|
|
58
|
+
"@mpgd/catalog": "0.3.4",
|
|
59
|
+
"@mpgd/game-services": "0.5.0",
|
|
60
|
+
"@mpgd/i18n": "0.5.0",
|
|
61
|
+
"@mpgd/platform": "0.5.0",
|
|
61
62
|
"@mpgd/phaser-assets": "0.4.0",
|
|
62
|
-
"@mpgd/
|
|
63
|
-
"@mpgd/target-config": "0.5.0"
|
|
63
|
+
"@mpgd/target-config": "0.6.0"
|
|
64
64
|
},
|
|
65
65
|
"main": "./dist/index.js",
|
|
66
66
|
"types": "./dist/index.d.ts",
|
|
@@ -32,6 +32,7 @@ pnpm exec mpgd target build-all \
|
|
|
32
32
|
--targets-file ./mpgd.targets.json \
|
|
33
33
|
--kit-path ../mpgd-kit \
|
|
34
34
|
--targets web,microsoft-store,ait,reddit \
|
|
35
|
+
--profile staging \
|
|
35
36
|
--ait-variant wrapper
|
|
36
37
|
pnpm exec mpgd target smoke-all \
|
|
37
38
|
--targets-file ./mpgd.targets.json \
|
|
@@ -51,6 +52,7 @@ pnpm --dir ../mpgd-kit mpgd target build-all \
|
|
|
51
52
|
--targets-file "$PWD/mpgd.targets.json" \
|
|
52
53
|
--kit-path ../mpgd-kit \
|
|
53
54
|
--targets web,microsoft-store,ait,reddit \
|
|
55
|
+
--profile staging \
|
|
54
56
|
--ait-variant wrapper
|
|
55
57
|
```
|
|
56
58
|
|
|
@@ -58,10 +60,37 @@ pnpm --dir ../mpgd-kit mpgd target build-all \
|
|
|
58
60
|
into `.mpgd.targets.generated.json` before calling the kit's existing target
|
|
59
61
|
build and smoke scripts.
|
|
60
62
|
|
|
63
|
+
The starter's Apps in Toss and Capacitor entries intentionally point at kit
|
|
64
|
+
reference wrappers, so their reusable validation builds use the `staging`
|
|
65
|
+
profile. Before an AIT, Android, or iOS production build, copy or create the
|
|
66
|
+
wrapper/shell under this game directory, update `mpgd.targets.json`, and set
|
|
67
|
+
`VITE_MPGD_GAME_SERVICES_URL` to a public HTTPS endpoint without embedded
|
|
68
|
+
credentials. Production preflight resolves real paths, rejects wrappers or
|
|
69
|
+
shells outside the game root (including symbolic-link escapes), and blocks
|
|
70
|
+
localhost plus literal private or reserved IP addresses.
|
|
71
|
+
|
|
61
72
|
`mpgd target doctor` verifies that release manifest artifact paths stay under
|
|
62
73
|
this game directory, even when a build used the kit reference Apps in Toss or
|
|
63
74
|
Capacitor wrappers.
|
|
64
75
|
|
|
76
|
+
## Acceptance Handoff
|
|
77
|
+
|
|
78
|
+
Run the reusable acceptance workflow before handing the game off:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
pnpm accept
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The command runs `check`, an optional `test` script, `build`, the kit's ttsc
|
|
85
|
+
graph preflight, an optional game-owned `playtest` script, and the configured
|
|
86
|
+
target build/smoke matrix. Results are written as JSON and Markdown under
|
|
87
|
+
`artifacts/acceptance`. Add a non-interactive `playtest` package script when the
|
|
88
|
+
game has an automated browser scenario; interactive platform playtests remain
|
|
89
|
+
separate operator workflows.
|
|
90
|
+
Each command has a 30-minute timeout by default. Pass `--timeout-ms` to the
|
|
91
|
+
underlying `mpgd game accept` command when a target matrix needs a different
|
|
92
|
+
per-step limit.
|
|
93
|
+
|
|
65
94
|
## Assets
|
|
66
95
|
|
|
67
96
|
Static assets live under `src/assets` and are declared in
|
|
@@ -116,6 +145,24 @@ soft rotate prompt on mismatch. The generated PWA manifest also declares
|
|
|
116
145
|
that manifest value aligned with the runtime policy if you make a portrait-first
|
|
117
146
|
game.
|
|
118
147
|
|
|
148
|
+
## App Icons
|
|
149
|
+
|
|
150
|
+
`mpgd.game.json` owns one canonical PNG or SVG app icon source. Target profiles
|
|
151
|
+
derive each platform's required sizes, safe zones, alpha policy, and native or
|
|
152
|
+
wrapper staging files.
|
|
153
|
+
|
|
154
|
+
```sh
|
|
155
|
+
pnpm icons:generate
|
|
156
|
+
pnpm icons:verify
|
|
157
|
+
pnpm icons:inspect
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Use each target's optional `icon` object in `mpgd.targets.json` for a profile,
|
|
161
|
+
background, source, or variant override. The release evidence still records the
|
|
162
|
+
shared canonical source separately from an override render source. Before an
|
|
163
|
+
Apps in Toss production package build, upload the generated 600x600 icon in the
|
|
164
|
+
console and configure the returned HTTPS URL as `ait.icon.externalUrl`.
|
|
165
|
+
|
|
119
166
|
## Reddit Devvit
|
|
120
167
|
|
|
121
168
|
This starter owns its Devvit app root in `apps/target-devvit`. That directory
|
|
@@ -126,10 +173,17 @@ The generated `devvit.json` app name is a Devvit-safe slug derived from the game
|
|
|
126
173
|
directory name; edit it before `devvit:init` if you need a different Reddit app
|
|
127
174
|
name.
|
|
128
175
|
|
|
176
|
+
The default post entry builds a lightweight inline preview without importing
|
|
177
|
+
Phaser. Its Play button requests the separate `game` entrypoint, whose
|
|
178
|
+
`game.html` document starts the Phaser bundle directly. Keep these physical
|
|
179
|
+
entries separate when customizing the preview so Reddit cards do not pay the
|
|
180
|
+
game runtime cost before expansion.
|
|
181
|
+
|
|
129
182
|
First-time Devvit setup:
|
|
130
183
|
|
|
131
184
|
```sh
|
|
132
185
|
pnpm install -w
|
|
186
|
+
pnpm icons:generate:devvit:production
|
|
133
187
|
pnpm devvit:login
|
|
134
188
|
pnpm devvit:whoami
|
|
135
189
|
pnpm devvit:init
|
|
@@ -218,7 +272,14 @@ submission.
|
|
|
218
272
|
- Microsoft Store is a game-owned PWA target that reuses the browser adapter and
|
|
219
273
|
writes to `artifacts/microsoft-store` with `manifest.webmanifest` for
|
|
220
274
|
PWABuilder packaging. Replace the starter icon and manifest metadata before
|
|
221
|
-
Store submission.
|
|
275
|
+
Store submission. Production builds also emit `pwa-release.json` and an
|
|
276
|
+
atomic offline `service-worker.js`; its deterministic revision covers every
|
|
277
|
+
precached artifact plus the game and kit Git provenance. Updates intentionally
|
|
278
|
+
wait while any old app window remains open. Listen for
|
|
279
|
+
`mpgd:pwa-update-ready` to tell players to close every window and reopen the
|
|
280
|
+
app; do not force activation with `skipWaiting()`. Keep the web manifest `id`
|
|
281
|
+
game-specific because the cache namespace uses it to isolate apps sharing an
|
|
282
|
+
origin.
|
|
222
283
|
- Reddit Devvit is game-owned in `apps/target-devvit`.
|
|
223
284
|
- Apps in Toss currently uses the kit reference wrapper at
|
|
224
285
|
`${MPGD_KIT_PATH}/apps/target-ait` for smoke packaging. Before a real Toss
|
|
@@ -242,3 +303,12 @@ VITE_MPGD_GAME_SERVICES_TRANSPORT=http
|
|
|
242
303
|
|
|
243
304
|
Use `VITE_MPGD_GAME_SERVICES_TRANSPORT=orpc` with a `/rpc` URL to test the oRPC
|
|
244
305
|
client path.
|
|
306
|
+
|
|
307
|
+
The generated starter uses `createGameServicesRuntime` for backend selection
|
|
308
|
+
and treats only the exact Vite `production` profile as production authority.
|
|
309
|
+
Production fails closed when the URL is absent or is not public HTTPS without
|
|
310
|
+
credentials: Game Services reports `missing_authoritative_backend` or
|
|
311
|
+
`invalid_authoritative_backend` and does not create a client. Process-local
|
|
312
|
+
backends require both a non-production authority mode and an explicit
|
|
313
|
+
`allowLocalBackend` opt-in, so they cannot manufacture successful production
|
|
314
|
+
purchase, rewarded-ad, or leaderboard ledger results.
|
|
@@ -3,22 +3,28 @@
|
|
|
3
3
|
Run these checks before handing off a generated game starter:
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
|
-
pnpm
|
|
7
|
-
pnpm
|
|
8
|
-
pnpm
|
|
9
|
-
pnpm --dir ../mpgd-kit mpgd target smoke-all --targets-file "$PWD/mpgd.targets.json" --targets web,microsoft-store,ait,reddit
|
|
10
|
-
pnpm --dir ../mpgd-kit mpgd target doctor --targets-file "$PWD/mpgd.targets.json" --targets web,microsoft-store,ait,reddit
|
|
6
|
+
pnpm icons:generate
|
|
7
|
+
pnpm icons:verify
|
|
8
|
+
pnpm accept
|
|
11
9
|
```
|
|
12
10
|
|
|
11
|
+
`pnpm accept` runs the configured game check, optional test and playtest scripts,
|
|
12
|
+
game build, kit TypeScript graph preflight, and the reusable target build/smoke
|
|
13
|
+
matrix. It writes `artifacts/acceptance/acceptance-report.json` and
|
|
14
|
+
`acceptance-report.md` for handoff. Missing optional `test` or `playtest` scripts
|
|
15
|
+
are recorded as skipped; check and build remain required.
|
|
16
|
+
|
|
13
17
|
For Apps in Toss changes, use the apps-in-toss MCP before implementation and
|
|
14
18
|
keep SDK calls inside adapters or target wrappers.
|
|
15
19
|
Resolve identity and launch intents during bootstrap, treat inbound share data as
|
|
16
20
|
untrusted, and keep notification delivery on the server.
|
|
17
21
|
|
|
18
|
-
For Reddit Devvit changes, keep Devvit SDK calls inside the target wrapper and
|
|
22
|
+
For Reddit Devvit changes, keep Devvit SDK calls inside the adapter or target wrapper and
|
|
19
23
|
continue to expose game-facing behavior through `PlatformGateway`. The Devvit
|
|
20
24
|
app root is game-owned in `apps/target-devvit`; run `pnpm devvit:init` once
|
|
21
25
|
after login before upload or playtest.
|
|
26
|
+
Verify the default post entry renders only the lightweight inline preview and
|
|
27
|
+
the `game` entry opens the separate expanded Phaser document.
|
|
22
28
|
|
|
23
29
|
For Microsoft Store changes, keep the first pass as a PWA/web target that uses
|
|
24
30
|
the browser adapter. Add a dedicated Store commerce adapter only when wiring
|
|
@@ -18,7 +18,9 @@ Useful commands:
|
|
|
18
18
|
pnpm dev
|
|
19
19
|
pnpm check
|
|
20
20
|
pnpm build
|
|
21
|
-
pnpm
|
|
21
|
+
pnpm icons:generate
|
|
22
|
+
pnpm icons:verify
|
|
23
|
+
pnpm exec mpgd target build-all --targets-file ./mpgd.targets.json --kit-path ../mpgd-kit --targets web,microsoft-store,ait,reddit --profile staging --ait-variant wrapper
|
|
22
24
|
pnpm devvit:login
|
|
23
25
|
pnpm devvit:init
|
|
24
26
|
pnpm devvit:playtest
|
|
@@ -37,6 +37,10 @@
|
|
|
37
37
|
"id": "platform.devvit.app-root",
|
|
38
38
|
"owner": "apps/target-devvit"
|
|
39
39
|
},
|
|
40
|
+
{
|
|
41
|
+
"id": "platform.devvit.surface-split",
|
|
42
|
+
"owner": "src/platform/devvitEntrypoint.ts"
|
|
43
|
+
},
|
|
40
44
|
{
|
|
41
45
|
"id": "services.backend.game-services",
|
|
42
46
|
"owner": "src/platform/gameServices.ts"
|
|
@@ -51,6 +55,9 @@
|
|
|
51
55
|
}
|
|
52
56
|
],
|
|
53
57
|
"acceptance": [
|
|
58
|
+
"pnpm accept",
|
|
59
|
+
"pnpm icons:generate",
|
|
60
|
+
"pnpm icons:verify",
|
|
54
61
|
"pnpm check",
|
|
55
62
|
"pnpm build"
|
|
56
63
|
]
|
|
@@ -29,3 +29,33 @@ The client bundle is copied into `dist/client` by the mpgd target build. The ser
|
|
|
29
29
|
compiled to `dist/server/index.cjs` and keeps Devvit SDK imports out of Phaser scenes.
|
|
30
30
|
The game root pins `@mpgd/cli`, so these commands use the same CLI version as the generated
|
|
31
31
|
starter's other `@mpgd/*` dependencies.
|
|
32
|
+
|
|
33
|
+
The default post entry uses `index.html` for a lightweight inline preview. Its
|
|
34
|
+
Play button requests the `game` entrypoint, which loads the separate
|
|
35
|
+
`game.html` Phaser document. Keep inline UI free of game runtime imports so the
|
|
36
|
+
card remains lightweight before expansion.
|
|
37
|
+
|
|
38
|
+
## Durable Post Operations
|
|
39
|
+
|
|
40
|
+
Use `src/server/postOperationStore.ts` with `@mpgd/adapter-devvit/server` for a
|
|
41
|
+
server action or scheduler that may receive the same custom-post operation more
|
|
42
|
+
than once. Use `{ appScope, subredditId }` as the scope, a stable `operationType`
|
|
43
|
+
in the definition, and an `operationId` for each logical publication slot. Validate
|
|
44
|
+
the public payload and launch parameters, then inject the Redis-backed store into
|
|
45
|
+
`createDevvitPostOperationCoordinator`.
|
|
46
|
+
|
|
47
|
+
The contract is duplicate-safe and ambiguity-safe, not exactly-once. It persists
|
|
48
|
+
the attempt before invoking Reddit. If Reddit accepts the post but its response is
|
|
49
|
+
lost, or the process stops before the receipt is saved, repeating `execute` returns
|
|
50
|
+
`reconciliation-required` and never blindly calls the submit function again. An
|
|
51
|
+
explicit recovery endpoint or scheduler calls `reconcile`, which requires an exact
|
|
52
|
+
match of the full canonical envelope. A missing match from a bounded listing
|
|
53
|
+
remains unresolved rather than restoring submit permission.
|
|
54
|
+
|
|
55
|
+
Keep operation definitions and `@devvit/web/server` imports inside this target
|
|
56
|
+
app. The canonical `{ mpgd, launch, payload }` envelope is public and untrusted;
|
|
57
|
+
keep private content and authoritative records in server-side storage. Exercise
|
|
58
|
+
first success, duplicate calls, interruption,
|
|
59
|
+
response loss, lease expiry with concurrent reconciliation, malformed durable
|
|
60
|
+
state, invalid launch metadata, and cross-scope key isolation before enabling a
|
|
61
|
+
scheduled or user-triggered publication flow.
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://developers.reddit.com/schema/config-file.v1.json",
|
|
3
3
|
"name": "__DEVVIT_APP_NAME__",
|
|
4
|
+
"marketingAssets": {
|
|
5
|
+
"icon": "generated/marketing-icon.png"
|
|
6
|
+
},
|
|
4
7
|
"post": {
|
|
5
8
|
"dir": "dist/client",
|
|
6
9
|
"entrypoints": {
|
|
7
10
|
"default": {
|
|
8
11
|
"entry": "index.html",
|
|
9
12
|
"height": "tall"
|
|
13
|
+
},
|
|
14
|
+
"game": {
|
|
15
|
+
"entry": "game.html",
|
|
16
|
+
"height": "tall"
|
|
10
17
|
}
|
|
11
18
|
}
|
|
12
19
|
},
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
"version": "0.0.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
7
|
+
"prepare:icon": "pnpm --dir ../.. icons:generate:devvit",
|
|
8
|
+
"prepare:icon:production": "pnpm --dir ../.. icons:generate:devvit:production",
|
|
9
|
+
"init": "pnpm run prepare:icon:production && devvit upload --config devvit.json",
|
|
10
|
+
"init:copy-paste": "pnpm run prepare:icon:production && devvit upload --copy-paste --config devvit.json",
|
|
11
|
+
"dev": "pnpm run prepare:icon && devvit playtest --config devvit.json",
|
|
10
12
|
"dev:prepare": "pnpm --dir ../.. build:devvit:staging",
|
|
11
13
|
"dev:client": "APP_TARGET=reddit APP_VERSION=0.0.0-dev BUILD_ID=devvit-watch pnpm --dir ../.. exec vite build --mode staging --watch --outDir apps/target-devvit/dist/client",
|
|
12
14
|
"dev:server": "vite build --config vite.server.config.ts --watch",
|
|
@@ -14,8 +16,8 @@
|
|
|
14
16
|
"build": "pnpm --dir ../.. build:devvit",
|
|
15
17
|
"build:server": "vite build --config vite.server.config.ts",
|
|
16
18
|
"whoami": "devvit whoami",
|
|
17
|
-
"upload": "devvit upload --config devvit.json",
|
|
18
|
-
"publish": "devvit publish --config devvit.json",
|
|
19
|
+
"upload": "pnpm run prepare:icon:production && devvit upload --config devvit.json",
|
|
20
|
+
"publish": "pnpm run prepare:icon:production && devvit publish --config devvit.json",
|
|
19
21
|
"check": "ttsc --noEmit -p tsconfig.json",
|
|
20
22
|
"lint": "ttsc --noEmit -p tsconfig.json",
|
|
21
23
|
"format": "ttsc format",
|
|
@@ -23,6 +25,7 @@
|
|
|
23
25
|
},
|
|
24
26
|
"dependencies": {
|
|
25
27
|
"@devvit/web": "0.13.6",
|
|
28
|
+
"@mpgd/adapter-devvit": "__MPGD_DEPENDENCY_VERSION_ADAPTER_DEVVIT__",
|
|
26
29
|
"@mpgd/bridge": "__MPGD_DEPENDENCY_VERSION_BRIDGE__",
|
|
27
30
|
"express": "^5.2.1",
|
|
28
31
|
"helmet": "^8.1.0"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { redis } from '@devvit/web/server';
|
|
2
|
+
import {
|
|
3
|
+
createDevvitRedisPostOperationStore,
|
|
4
|
+
type DevvitDurableOperationStore,
|
|
5
|
+
} from '@mpgd/adapter-devvit/server';
|
|
6
|
+
|
|
7
|
+
export function createPostOperationStore(): DevvitDurableOperationStore {
|
|
8
|
+
return createDevvitRedisPostOperationStore(redis);
|
|
9
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta name="theme-color" content="#0f172a" />
|
|
7
|
+
<title>__GAME_TITLE__</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="game"></div>
|
|
11
|
+
<script type="module" src="/src/gameEntry.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta name="theme-color" content="#0f172a" />
|
|
7
|
-
<link rel="manifest" href="
|
|
7
|
+
<link rel="manifest" href="./manifest.webmanifest" />
|
|
8
8
|
<title>__GAME_TITLE__</title>
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="game"></div>
|
|
12
|
-
<script type="module" src="/src/
|
|
12
|
+
<script type="module" src="/src/entry.ts"></script>
|
|
13
13
|
</body>
|
|
14
14
|
</html>
|
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
"kind": "web",
|
|
5
5
|
"gameApp": ".",
|
|
6
6
|
"adapter": "browser",
|
|
7
|
+
"icon": { "profile": "web-preview" },
|
|
7
8
|
"output": "artifacts/web-preview"
|
|
8
9
|
},
|
|
9
10
|
"microsoft-store": {
|
|
10
11
|
"kind": "web",
|
|
11
12
|
"gameApp": ".",
|
|
12
13
|
"adapter": "browser",
|
|
14
|
+
"icon": { "profile": "microsoft-pwa" },
|
|
13
15
|
"output": "artifacts/microsoft-store"
|
|
14
16
|
},
|
|
15
17
|
"android": {
|
|
@@ -17,6 +19,7 @@
|
|
|
17
19
|
"gameApp": ".",
|
|
18
20
|
"shellApp": "${MPGD_KIT_PATH}/apps/mobile-capacitor",
|
|
19
21
|
"adapter": "capacitor",
|
|
22
|
+
"icon": { "profile": "android" },
|
|
20
23
|
"webDir": "${MPGD_KIT_PATH}/apps/mobile-capacitor/www",
|
|
21
24
|
"artifact": "aab"
|
|
22
25
|
},
|
|
@@ -25,6 +28,7 @@
|
|
|
25
28
|
"gameApp": ".",
|
|
26
29
|
"shellApp": "${MPGD_KIT_PATH}/apps/mobile-capacitor",
|
|
27
30
|
"adapter": "capacitor",
|
|
31
|
+
"icon": { "profile": "ios" },
|
|
28
32
|
"webDir": "${MPGD_KIT_PATH}/apps/mobile-capacitor/www",
|
|
29
33
|
"artifact": "ipa"
|
|
30
34
|
},
|
|
@@ -33,6 +37,7 @@
|
|
|
33
37
|
"gameApp": ".",
|
|
34
38
|
"wrapperApp": "${MPGD_KIT_PATH}/apps/target-ait",
|
|
35
39
|
"adapter": "ait",
|
|
40
|
+
"icon": { "profile": "ait" },
|
|
36
41
|
"webDir": "${MPGD_KIT_PATH}/apps/target-ait/public/game",
|
|
37
42
|
"artifact": ".ait"
|
|
38
43
|
},
|
|
@@ -41,6 +46,7 @@
|
|
|
41
46
|
"gameApp": ".",
|
|
42
47
|
"wrapperApp": "apps/target-devvit",
|
|
43
48
|
"adapter": "devvit",
|
|
49
|
+
"icon": { "profile": "devvit" },
|
|
44
50
|
"webDir": "apps/target-devvit/dist/client",
|
|
45
51
|
"artifact": "devvit"
|
|
46
52
|
}
|
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
"dev": "__WORKSPACE_I18N_BUILD_PREFIX__vite --host 0.0.0.0",
|
|
9
9
|
"dev:ait": "APP_TARGET=ait APP_VERSION=0.0.0-dev BUILD_ID=ait-sandbox sh -c '__WORKSPACE_I18N_BUILD_PREFIX__vite --host 0.0.0.0'",
|
|
10
10
|
"build": "__WORKSPACE_I18N_BUILD_PREFIX__vite build",
|
|
11
|
-
"
|
|
11
|
+
"accept": "node ./tools/run-game-acceptance.mjs",
|
|
12
|
+
"icons:generate": "pnpm exec mpgd game icons generate . --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
|
|
13
|
+
"icons:generate:devvit": "pnpm exec mpgd game icons generate . --targets reddit --profile development --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
|
|
14
|
+
"icons:generate:devvit:production": "pnpm exec mpgd game icons generate . --targets reddit --profile production --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
|
|
15
|
+
"icons:verify": "pnpm exec mpgd game icons verify . --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
|
|
16
|
+
"icons:inspect": "pnpm exec mpgd game icons inspect . --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
|
|
17
|
+
"build:ait": "pnpm exec mpgd target build ait staging --variant wrapper --targets-file ./mpgd.targets.json --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
|
|
12
18
|
"build:ait:package": "pnpm exec mpgd target build ait production --targets-file ./mpgd.targets.json --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
|
|
13
19
|
"smoke:ait": "pnpm exec mpgd target smoke ait --targets-file ./mpgd.targets.json --kit-path ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}",
|
|
14
20
|
"ait:wrapper:dev": "pnpm --dir ${MPGD_KIT_PATH:-__DEFAULT_KIT_PATH__}/apps/target-ait run dev",
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
declare const __APP_TARGET__: string;
|
|
4
4
|
declare const __MPGD_CONFIG_TARGET__: string;
|
|
5
|
+
declare const __MPGD_PLATFORM_TARGET__:
|
|
6
|
+
| import('@mpgd/target-config').EffectivePlatformTargetMetadata
|
|
7
|
+
| undefined;
|
|
5
8
|
declare const __APP_VERSION__: string;
|
|
6
9
|
declare const __BUILD_ID__: string;
|
|
7
10
|
declare const __SOURCE_GIT_SHA__: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import './styles.css';
|
|
2
2
|
|
|
3
3
|
import { createAnalyticsReporter, createBufferedAnalyticsSink } from '@mpgd/analytics';
|
|
4
|
-
import {
|
|
4
|
+
import { resolveTargetMpgdLocale, type Locale } from '@mpgd/i18n';
|
|
5
5
|
import type { IdentitySession, LaunchIntent, PlatformGateway } from '@mpgd/platform';
|
|
6
6
|
import {
|
|
7
7
|
resolveTargetViewportPlan,
|
|
@@ -14,11 +14,13 @@ import { createStarterGame } from './runtime/createGame';
|
|
|
14
14
|
import { detectRuntime } from './platform/runtimeDetector';
|
|
15
15
|
import { createStarterGameServices } from './platform/gameServices';
|
|
16
16
|
import { installPlatform } from './platform/installPlatform';
|
|
17
|
+
import { installMicrosoftStorePwa } from './platform/microsoftStorePwa';
|
|
17
18
|
|
|
18
19
|
await bootstrap();
|
|
19
20
|
|
|
20
21
|
async function bootstrap(): Promise<void> {
|
|
21
22
|
let locale: Locale = 'en';
|
|
23
|
+
let disposeMicrosoftStorePwa: (() => void) | undefined;
|
|
22
24
|
|
|
23
25
|
try {
|
|
24
26
|
if (__APP_TARGET__ === 'ait') {
|
|
@@ -27,6 +29,7 @@ async function bootstrap(): Promise<void> {
|
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
const runtimeConfig = detectRuntime();
|
|
32
|
+
disposeMicrosoftStorePwa = installMicrosoftStorePwa(runtimeConfig);
|
|
30
33
|
const platform = await installPlatform(runtimeConfig);
|
|
31
34
|
const runtime = await platform.getTargetRuntime();
|
|
32
35
|
const orientationPolicy = {
|
|
@@ -46,7 +49,12 @@ async function bootstrap(): Promise<void> {
|
|
|
46
49
|
resolveIdentitySession(platform, player.playerId),
|
|
47
50
|
resolveLaunchIntent(platform),
|
|
48
51
|
]);
|
|
49
|
-
locale =
|
|
52
|
+
locale = resolveTargetMpgdLocale({
|
|
53
|
+
capabilities: runtime.capabilities,
|
|
54
|
+
fallbackLocale:
|
|
55
|
+
runtime.effectiveConfig?.localization.fallbackLocale
|
|
56
|
+
?? runtime.config.localization.fallbackLocale,
|
|
57
|
+
});
|
|
50
58
|
const analyticsSink = createBufferedAnalyticsSink();
|
|
51
59
|
const analytics = createAnalyticsReporter({
|
|
52
60
|
target: platform.target,
|
|
@@ -82,6 +90,7 @@ async function bootstrap(): Promise<void> {
|
|
|
82
90
|
},
|
|
83
91
|
});
|
|
84
92
|
} catch (error) {
|
|
93
|
+
disposeMicrosoftStorePwa?.();
|
|
85
94
|
renderBootstrapError(error, locale);
|
|
86
95
|
console.error('[bootstrap]', error);
|
|
87
96
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createAitPlatformGateway } from '@mpgd/adapter-ait';
|
|
2
|
+
import type { PlatformGateway } from '@mpgd/platform';
|
|
3
|
+
|
|
4
|
+
import type { RuntimeConfig } from '../runtimeDetector';
|
|
5
|
+
|
|
6
|
+
export async function createBuildGateway(runtime: RuntimeConfig): Promise<PlatformGateway> {
|
|
7
|
+
return createAitPlatformGateway({
|
|
8
|
+
appVersion: runtime.appVersion,
|
|
9
|
+
buildId: runtime.buildId,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createAitPlatformGateway, createAitSandboxBridge } from '@mpgd/adapter-ait';
|
|
2
|
+
import type { PlatformGateway } from '@mpgd/platform';
|
|
3
|
+
|
|
4
|
+
import type { RuntimeConfig } from '../runtimeDetector';
|
|
5
|
+
|
|
6
|
+
export async function createBuildGateway(runtime: RuntimeConfig): Promise<PlatformGateway> {
|
|
7
|
+
return createAitPlatformGateway({
|
|
8
|
+
appVersion: runtime.appVersion,
|
|
9
|
+
buildId: runtime.buildId,
|
|
10
|
+
fallbackBridge: createAitSandboxBridge(),
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createBrowserPlatformGateway } from '@mpgd/adapter-browser';
|
|
2
|
+
import type { PlatformGateway } from '@mpgd/platform';
|
|
3
|
+
|
|
4
|
+
import type { RuntimeConfig } from '../runtimeDetector';
|
|
5
|
+
|
|
6
|
+
export async function createBuildGateway(_runtime: RuntimeConfig): Promise<PlatformGateway> {
|
|
7
|
+
return createBrowserPlatformGateway();
|
|
8
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createCapacitorPlatformGateway } from '@mpgd/adapter-capacitor';
|
|
2
|
+
import type { PlatformGateway } from '@mpgd/platform';
|
|
3
|
+
|
|
4
|
+
import type { RuntimeConfig } from '../runtimeDetector';
|
|
5
|
+
|
|
6
|
+
export async function createBuildGateway(runtime: RuntimeConfig): Promise<PlatformGateway> {
|
|
7
|
+
return createCapacitorPlatformGateway({
|
|
8
|
+
target: 'android',
|
|
9
|
+
appVersion: runtime.appVersion,
|
|
10
|
+
buildId: runtime.buildId,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createCapacitorPlatformGateway } from '@mpgd/adapter-capacitor';
|
|
2
|
+
import type { PlatformGateway } from '@mpgd/platform';
|
|
3
|
+
|
|
4
|
+
import type { RuntimeConfig } from '../runtimeDetector';
|
|
5
|
+
|
|
6
|
+
export async function createBuildGateway(runtime: RuntimeConfig): Promise<PlatformGateway> {
|
|
7
|
+
return createCapacitorPlatformGateway({
|
|
8
|
+
target: 'ios',
|
|
9
|
+
appVersion: runtime.appVersion,
|
|
10
|
+
buildId: runtime.buildId,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createDevvitPlatformGateway } from '@mpgd/adapter-devvit';
|
|
2
|
+
import type { PlatformGateway } from '@mpgd/platform';
|
|
3
|
+
|
|
4
|
+
import type { RuntimeConfig } from '../runtimeDetector';
|
|
5
|
+
|
|
6
|
+
export async function createBuildGateway(runtime: RuntimeConfig): Promise<PlatformGateway> {
|
|
7
|
+
return createDevvitPlatformGateway({
|
|
8
|
+
appVersion: runtime.appVersion,
|
|
9
|
+
buildId: runtime.buildId,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createDevvitPlatformGateway,
|
|
3
|
+
createDevvitSandboxBridge,
|
|
4
|
+
} from '@mpgd/adapter-devvit';
|
|
5
|
+
import type { PlatformGateway } from '@mpgd/platform';
|
|
6
|
+
|
|
7
|
+
import type { RuntimeConfig } from '../runtimeDetector';
|
|
8
|
+
|
|
9
|
+
export async function createBuildGateway(runtime: RuntimeConfig): Promise<PlatformGateway> {
|
|
10
|
+
return createDevvitPlatformGateway({
|
|
11
|
+
appVersion: runtime.appVersion,
|
|
12
|
+
buildId: runtime.buildId,
|
|
13
|
+
fallbackBridge: createDevvitSandboxBridge(),
|
|
14
|
+
});
|
|
15
|
+
}
|