@forgeax/engine-project 0.1.3 → 0.1.6

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/src/loader.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  // loader.ts — loadGameProject + resolveDefaultScene (D-6, AC-06/07/08/09)
2
2
  //
3
3
  // loadGameProject: injection-only `read:(path)=>Promise<string>`, returns
4
- // GuidResult<GameProject, GameProjectError>. Reader failures preserve ENOENT
5
- // as forge-missing and classify all other refusals as forge-read-failed;
6
- // validation then has the remaining five return paths:
4
+ // GuidResult<GameProject, GameProjectError>. Five return paths:
5
+ // 1. read throws ok:false, error(code='forge-missing')
7
6
  // 2. JSON.parse fails → ok:false, error(code='forge-parse-failed')
8
7
  // 3. schema.parse fails (missing fields) → ok:false, error(code='forge-schema-invalid')
9
8
  // 3b. schema.parse fails (unknown fields via .strict()) → ok:false, error(code='forge-unknown-field')
@@ -18,7 +17,6 @@
18
17
 
19
18
  import type { GuidResult } from '@forgeax/engine-pack/guid';
20
19
  import {
21
- type ForgeReadFailureCauseCode,
22
20
  GameProjectError,
23
21
  type GameProjectErrorArgs,
24
22
  type GameProjectErrorCode,
@@ -42,73 +40,6 @@ function ok<T>(value: T) {
42
40
  return { ok: true as const, value };
43
41
  }
44
42
 
45
- type ReaderErrorMetadata = {
46
- readonly code?: unknown;
47
- readonly name?: unknown;
48
- };
49
-
50
- function readerFailureToken(error: unknown): string | undefined {
51
- if (typeof error !== 'object' || error === null) {
52
- return undefined;
53
- }
54
-
55
- const metadata = error as ReaderErrorMetadata;
56
- if (typeof metadata.code === 'string') {
57
- return metadata.code;
58
- }
59
- if (typeof metadata.name === 'string') {
60
- return metadata.name;
61
- }
62
- return undefined;
63
- }
64
-
65
- function readerFailureCause(token: string | undefined): ForgeReadFailureCauseCode {
66
- switch (token) {
67
- case 'EACCES':
68
- case 'EPERM':
69
- case 'PermissionDeniedError':
70
- case 'NotAllowedError':
71
- case 'SecurityError':
72
- return 'permission-denied';
73
- case 'EAGAIN':
74
- case 'EBUSY':
75
- case 'EINTR':
76
- case 'ECONNABORTED':
77
- case 'ECONNREFUSED':
78
- case 'ECONNRESET':
79
- case 'EHOSTUNREACH':
80
- case 'ENETDOWN':
81
- case 'ENETUNREACH':
82
- case 'ETIMEDOUT':
83
- case 'EPIPE':
84
- case 'ABORT_ERR':
85
- case 'AbortError':
86
- case 'TimeoutError':
87
- return 'transient';
88
- default:
89
- return 'unknown';
90
- }
91
- }
92
-
93
- function readerFailure(error: unknown) {
94
- const token = readerFailureToken(error);
95
- if (token === 'ENOENT') {
96
- return err(
97
- 'forge-missing',
98
- 'forge.json file to exist at the game root',
99
- 'verify the game directory contains forge.json; if this is a new game, scaffold via the Studio UI or create a forge.json with id, name, schemaVersion fields',
100
- { path: FORGE_JSON },
101
- );
102
- }
103
-
104
- return err(
105
- 'forge-read-failed',
106
- 'forge.json reader to complete without refusal',
107
- 'retry the project reader; if the refusal persists, verify access to the game directory',
108
- { path: FORGE_JSON, cause: readerFailureCause(token) },
109
- );
110
- }
111
-
112
43
  // ── validateGameProject: sync pure core (JSON.parse → schema validate → 5 return paths) ──
113
44
 
114
45
  /**
@@ -198,15 +129,13 @@ export function validateGameProject(raw: string): GuidResult<GameProject, GamePr
198
129
  * Load and validate a game project manifest from the abstract async reader.
199
130
  *
200
131
  * Wraps `validateGameProject`: reads `FORGE_JSON` via `read`, then validates.
201
- * If `read` throws/rejects → `forge-missing` for ENOENT, otherwise
202
- * `forge-read-failed` with a bounded cause code.
132
+ * If `read` throws/rejects → `forge-missing`.
203
133
  *
204
134
  * ## Return paths (5)
205
135
  *
206
136
  * | # | Condition | ok | code |
207
137
  * |:--|:--|:--|:--|
208
- * | 1 | `read(FORGE_JSON)` throws / rejects with ENOENT | false | `forge-missing` |
209
- * | 1b | `read(FORGE_JSON)` refuses for another reason | false | `forge-read-failed` |
138
+ * | 1 | `read(FORGE_JSON)` throws / rejects | false | `forge-missing` |
210
139
  * | 2 | `JSON.parse` fails | false | `forge-parse-failed` |
211
140
  * | 3a | zod `.strict()` unknown fields (e.g. `scenes[]`) | false | `forge-unknown-field` |
212
141
  * | 3b | zod required field missing / wrong type | false | `forge-schema-invalid` |
@@ -228,8 +157,13 @@ export async function loadGameProject(
228
157
  let raw: string;
229
158
  try {
230
159
  raw = await read(FORGE_JSON);
231
- } catch (error: unknown) {
232
- return readerFailure(error);
160
+ } catch (_e: unknown) {
161
+ return err(
162
+ 'forge-missing',
163
+ 'forge.json file to exist at the game root',
164
+ 'verify the game directory contains forge.json; if this is a new game, scaffold via the Studio UI or create a forge.json with id, name, schemaVersion fields',
165
+ { path: FORGE_JSON },
166
+ );
233
167
  }
234
168
 
235
169
  return validateGameProject(raw);
@@ -242,8 +176,7 @@ export async function loadGameProject(
242
176
  * (e.g. sync `ContextSlot` content functions).
243
177
  *
244
178
  * Accepts a sync `read:(path)=>string` injection (same contract shape,
245
- * sync return). If `read` throws → `forge-missing` for ENOENT, otherwise
246
- * `forge-read-failed` with a bounded cause code.
179
+ * sync return). If `read` throws → `forge-missing`.
247
180
  *
248
181
  * Uses the same `validateGameProject` pure core as `loadGameProject`.
249
182
  */
@@ -253,8 +186,13 @@ export function loadGameProjectSync(
253
186
  let raw: string;
254
187
  try {
255
188
  raw = read(FORGE_JSON);
256
- } catch (error: unknown) {
257
- return readerFailure(error);
189
+ } catch (_e: unknown) {
190
+ return err(
191
+ 'forge-missing',
192
+ 'forge.json file to exist at the game root',
193
+ 'verify the game directory contains forge.json; if this is a new game, scaffold via the Studio UI or create a forge.json with id, name, schemaVersion fields',
194
+ { path: FORGE_JSON },
195
+ );
258
196
  }
259
197
 
260
198
  return validateGameProject(raw);