@forgeax/engine-project 0.1.2
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/LICENSE +202 -0
- package/README.md +82 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/__tests__/ac14-migration.test.d.ts +2 -0
- package/dist/__tests__/ac14-migration.test.d.ts.map +1 -0
- package/dist/__tests__/errors.test-d.d.ts +2 -0
- package/dist/__tests__/errors.test-d.d.ts.map +1 -0
- package/dist/__tests__/errors.test.d.ts +2 -0
- package/dist/__tests__/errors.test.d.ts.map +1 -0
- package/dist/__tests__/loader.test.d.ts +2 -0
- package/dist/__tests__/loader.test.d.ts.map +1 -0
- package/dist/__tests__/resolve.test.d.ts +2 -0
- package/dist/__tests__/resolve.test.d.ts.map +1 -0
- package/dist/__tests__/schema.test.d.ts +2 -0
- package/dist/__tests__/schema.test.d.ts.map +1 -0
- package/dist/__tests__/structural.test.d.ts +2 -0
- package/dist/__tests__/structural.test.d.ts.map +1 -0
- package/dist/errors.d.ts +84 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +291 -0
- package/dist/index.mjs.map +1 -0
- package/dist/loader.d.ts +99 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/paths.d.ts +3 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/schema.d.ts +216 -0
- package/dist/schema.d.ts.map +1 -0
- package/package.json +65 -0
- package/src/__tests__/ac14-migration.test.ts +124 -0
- package/src/__tests__/errors.test-d.ts +77 -0
- package/src/__tests__/errors.test.ts +254 -0
- package/src/__tests__/fixtures/games/cow-level/forge.json +7 -0
- package/src/__tests__/fixtures/games/cow-survivor/forge.json +8 -0
- package/src/__tests__/fixtures/games/fps/forge.json +7 -0
- package/src/__tests__/fixtures/games/hellforge/forge.json +24 -0
- package/src/__tests__/fixtures/games/shoot-opt/forge.json +6 -0
- package/src/__tests__/fixtures/games/spin-cube/forge.json +6 -0
- package/src/__tests__/loader.test.ts +364 -0
- package/src/__tests__/resolve.test.ts +160 -0
- package/src/__tests__/schema.test.ts +317 -0
- package/src/__tests__/structural.test.ts +175 -0
- package/src/errors.ts +129 -0
- package/src/index.ts +37 -0
- package/src/loader.ts +344 -0
- package/src/paths.ts +7 -0
- package/src/schema.ts +149 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { AssetGuid } from '@forgeax/engine-pack/guid';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
// src/errors.ts
|
|
5
|
+
var GameProjectErrorClass = class extends Error {
|
|
6
|
+
code;
|
|
7
|
+
expected;
|
|
8
|
+
hint;
|
|
9
|
+
detail;
|
|
10
|
+
constructor(args) {
|
|
11
|
+
super(`[GameProjectError ${args.code}] expected: ${args.expected}; hint: ${args.hint}`);
|
|
12
|
+
this.name = "GameProjectError";
|
|
13
|
+
this.code = args.code;
|
|
14
|
+
this.expected = args.expected;
|
|
15
|
+
this.hint = args.hint;
|
|
16
|
+
this.detail = args.detail;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var GameProjectError = GameProjectErrorClass;
|
|
20
|
+
|
|
21
|
+
// src/paths.ts
|
|
22
|
+
var FORGE_JSON = "forge.json";
|
|
23
|
+
var GuidString = z.string().refine(
|
|
24
|
+
(val) => AssetGuid.parse(val).ok,
|
|
25
|
+
(val) => {
|
|
26
|
+
const parsed = AssetGuid.parse(val);
|
|
27
|
+
const message = !parsed.ok ? parsed.error.hint : `invalid GUID: ${val}`;
|
|
28
|
+
return { message };
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
var PhysicsUnion = z.union([z.enum(["3d", "2d", "rapier-3d", "rapier-2d"]), z.boolean()]);
|
|
32
|
+
var SkinSchema = z.object({
|
|
33
|
+
sceneGuid: z.string().optional(),
|
|
34
|
+
clipGuids: z.array(z.string()).optional(),
|
|
35
|
+
clipDefault: z.string().optional(),
|
|
36
|
+
scale: z.number().optional(),
|
|
37
|
+
pos: z.array(z.number()).optional()
|
|
38
|
+
}).passthrough();
|
|
39
|
+
var PreviewSchema = z.object({ skin: SkinSchema }).passthrough();
|
|
40
|
+
var NpcBudgetSchema = z.object({
|
|
41
|
+
maxCallsPerMinute: z.number().int().positive().optional(),
|
|
42
|
+
maxTokensPerMinute: z.number().int().positive().optional(),
|
|
43
|
+
maxConcurrent: z.number().int().positive().optional()
|
|
44
|
+
}).strict();
|
|
45
|
+
var NpcConfigSchema = z.object({
|
|
46
|
+
model: z.string().min(1).optional(),
|
|
47
|
+
maxTokens: z.number().int().positive().optional(),
|
|
48
|
+
budget: NpcBudgetSchema.optional()
|
|
49
|
+
}).strict();
|
|
50
|
+
var PluginRealmSchema = z.enum(["host", "engine", "build"]);
|
|
51
|
+
var PluginInjectSchema = z.union([
|
|
52
|
+
z.array(z.string().min(1)),
|
|
53
|
+
z.record(z.string().min(1), z.unknown())
|
|
54
|
+
]);
|
|
55
|
+
var PluginEntryBase = z.object({
|
|
56
|
+
id: z.string().min(1),
|
|
57
|
+
name: z.string().min(1),
|
|
58
|
+
disabled: z.boolean().nullable().optional(),
|
|
59
|
+
inject: PluginInjectSchema.nullable().optional(),
|
|
60
|
+
realm: PluginRealmSchema.optional()
|
|
61
|
+
});
|
|
62
|
+
var GameProjectPluginEntrySchema = z.lazy(
|
|
63
|
+
() => z.union([
|
|
64
|
+
PluginEntryBase.extend({
|
|
65
|
+
group: z.literal(true),
|
|
66
|
+
config: z.array(GameProjectPluginEntrySchema)
|
|
67
|
+
}).strict(),
|
|
68
|
+
PluginEntryBase.extend({
|
|
69
|
+
group: z.union([z.literal(false), z.null()]).optional(),
|
|
70
|
+
config: z.unknown().optional()
|
|
71
|
+
}).strict()
|
|
72
|
+
])
|
|
73
|
+
);
|
|
74
|
+
var GameProjectPluginsSchema = z.array(GameProjectPluginEntrySchema).superRefine((entries, ctx) => {
|
|
75
|
+
const seen = /* @__PURE__ */ new Set();
|
|
76
|
+
const visit = (items) => {
|
|
77
|
+
for (const entry of items) {
|
|
78
|
+
if (seen.has(entry.id)) {
|
|
79
|
+
ctx.addIssue({
|
|
80
|
+
code: z.ZodIssueCode.custom,
|
|
81
|
+
message: `duplicate plugin entry id: ${entry.id}`
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
seen.add(entry.id);
|
|
85
|
+
if (entry.group === true) visit(entry.config);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
visit(entries);
|
|
89
|
+
});
|
|
90
|
+
var GameProjectSchema = z.object({
|
|
91
|
+
/** Stable game slug; matches the `.forgeax/games/<id>/` directory name. */
|
|
92
|
+
id: z.string(),
|
|
93
|
+
/** Human-facing display name (may contain any unicode). */
|
|
94
|
+
name: z.string(),
|
|
95
|
+
/** forge.json schema version, e.g. "1.0.0" — required so loaders can gate on format. */
|
|
96
|
+
schemaVersion: z.string(),
|
|
97
|
+
/** Optional bootstrap hook: entry module relative to game root (e.g. "main.ts", "src/main.ts"). */
|
|
98
|
+
entry: z.string().optional(),
|
|
99
|
+
/** Optional realm-local ExecutionBootstrapEntry module relative to game root. */
|
|
100
|
+
executionEntry: z.string().optional(),
|
|
101
|
+
/** Optional GUID of the scene to load first; must be a real scene asset GUID (GuidString-validated). */
|
|
102
|
+
defaultScene: GuidString.optional(),
|
|
103
|
+
/** Optional physics backend: enum tag ('3d'/'2d'/'rapier-3d'/'rapier-2d') or boolean on/off. */
|
|
104
|
+
physics: PhysicsUnion.optional(),
|
|
105
|
+
/** Optional flag requesting pointer-lock (FPS-style mouse capture) at play time. */
|
|
106
|
+
pointerLock: z.boolean().optional(),
|
|
107
|
+
/** Optional input scheme hint consumed by play-runtime (e.g. "fps"). */
|
|
108
|
+
input: z.string().optional(),
|
|
109
|
+
/** Optional editor preview config (skin scene/clips for the launcher card). */
|
|
110
|
+
preview: PreviewSchema.optional(),
|
|
111
|
+
/** Native DeepSeek Harness Entry tree, plus the ForgeaX build-only realm selector. */
|
|
112
|
+
plugins: GameProjectPluginsSchema.optional(),
|
|
113
|
+
/** Optional Digital Life NPC Brain policy consumed by the server adapter. */
|
|
114
|
+
npc: NpcConfigSchema.optional()
|
|
115
|
+
}).strict();
|
|
116
|
+
|
|
117
|
+
// src/loader.ts
|
|
118
|
+
function err(code, expected, hint, detail) {
|
|
119
|
+
return { ok: false, error: new GameProjectError({ code, expected, hint, detail }) };
|
|
120
|
+
}
|
|
121
|
+
function ok(value) {
|
|
122
|
+
return { ok: true, value };
|
|
123
|
+
}
|
|
124
|
+
function readerFailureToken(error) {
|
|
125
|
+
if (typeof error !== "object" || error === null) {
|
|
126
|
+
return void 0;
|
|
127
|
+
}
|
|
128
|
+
const metadata = error;
|
|
129
|
+
if (typeof metadata.code === "string") {
|
|
130
|
+
return metadata.code;
|
|
131
|
+
}
|
|
132
|
+
if (typeof metadata.name === "string") {
|
|
133
|
+
return metadata.name;
|
|
134
|
+
}
|
|
135
|
+
return void 0;
|
|
136
|
+
}
|
|
137
|
+
function readerFailureCause(token) {
|
|
138
|
+
switch (token) {
|
|
139
|
+
case "EACCES":
|
|
140
|
+
case "EPERM":
|
|
141
|
+
case "PermissionDeniedError":
|
|
142
|
+
case "NotAllowedError":
|
|
143
|
+
case "SecurityError":
|
|
144
|
+
return "permission-denied";
|
|
145
|
+
case "EAGAIN":
|
|
146
|
+
case "EBUSY":
|
|
147
|
+
case "EINTR":
|
|
148
|
+
case "ECONNABORTED":
|
|
149
|
+
case "ECONNREFUSED":
|
|
150
|
+
case "ECONNRESET":
|
|
151
|
+
case "EHOSTUNREACH":
|
|
152
|
+
case "ENETDOWN":
|
|
153
|
+
case "ENETUNREACH":
|
|
154
|
+
case "ETIMEDOUT":
|
|
155
|
+
case "EPIPE":
|
|
156
|
+
case "ABORT_ERR":
|
|
157
|
+
case "AbortError":
|
|
158
|
+
case "TimeoutError":
|
|
159
|
+
return "transient";
|
|
160
|
+
default:
|
|
161
|
+
return "unknown";
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function readerFailure(error) {
|
|
165
|
+
const token = readerFailureToken(error);
|
|
166
|
+
if (token === "ENOENT") {
|
|
167
|
+
return err(
|
|
168
|
+
"forge-missing",
|
|
169
|
+
"forge.json file to exist at the game root",
|
|
170
|
+
"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",
|
|
171
|
+
{ path: FORGE_JSON }
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
return err(
|
|
175
|
+
"forge-read-failed",
|
|
176
|
+
"forge.json reader to complete without refusal",
|
|
177
|
+
"retry the project reader; if the refusal persists, verify access to the game directory",
|
|
178
|
+
{ path: FORGE_JSON, cause: readerFailureCause(token) }
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
function validateGameProject(raw) {
|
|
182
|
+
let parsed;
|
|
183
|
+
try {
|
|
184
|
+
parsed = JSON.parse(raw);
|
|
185
|
+
} catch (e) {
|
|
186
|
+
return err(
|
|
187
|
+
"forge-parse-failed",
|
|
188
|
+
"forge.json to be valid JSON",
|
|
189
|
+
"check forge.json for JSON syntax errors (trailing commas, unquoted keys, etc.)",
|
|
190
|
+
{
|
|
191
|
+
path: FORGE_JSON,
|
|
192
|
+
rawMessage: e instanceof Error ? e.message : String(e)
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
const schemaResult = GameProjectSchema.safeParse(parsed);
|
|
197
|
+
if (!schemaResult.success) {
|
|
198
|
+
const zodErrors = schemaResult.error.issues;
|
|
199
|
+
const unknownFieldIssues = zodErrors.filter((i) => i.code === "unrecognized_keys");
|
|
200
|
+
if (unknownFieldIssues.length > 0) {
|
|
201
|
+
const fieldNames = unknownFieldIssues.flatMap((i) => i.keys ?? []);
|
|
202
|
+
return err(
|
|
203
|
+
"forge-unknown-field",
|
|
204
|
+
"forge.json to not contain unknown fields (e.g. scenes[])",
|
|
205
|
+
"remove unknown fields from forge.json; refer to GameProjectSchema in @forgeax/engine-project for the authoritative field list",
|
|
206
|
+
{ path: FORGE_JSON, fieldNames }
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
const guidFieldIssues = zodErrors.filter(
|
|
210
|
+
(i) => Array.isArray(i.path) && i.path.includes("defaultScene")
|
|
211
|
+
);
|
|
212
|
+
if (guidFieldIssues.length > 0) {
|
|
213
|
+
const rawInput = typeof parsed.defaultScene === "string" ? String(parsed.defaultScene) : "";
|
|
214
|
+
return err(
|
|
215
|
+
"forge-guid-malformed",
|
|
216
|
+
"defaultScene to be a valid 36-char RFC 4122 dash-form UUID",
|
|
217
|
+
"use a valid scene GUID; find it in the scene pack.json assets[].guid where kind=scene",
|
|
218
|
+
{
|
|
219
|
+
field: "defaultScene",
|
|
220
|
+
rawInput
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
return err(
|
|
225
|
+
"forge-schema-invalid",
|
|
226
|
+
"forge.json to satisfy GameProjectSchema",
|
|
227
|
+
"check forge.json against GameProjectSchema (z.infer for types); required fields: id, name, schemaVersion (all strings)",
|
|
228
|
+
{ path: FORGE_JSON, zodErrors }
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
return ok(schemaResult.data);
|
|
232
|
+
}
|
|
233
|
+
async function loadGameProject(read) {
|
|
234
|
+
let raw;
|
|
235
|
+
try {
|
|
236
|
+
raw = await read(FORGE_JSON);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
return readerFailure(error);
|
|
239
|
+
}
|
|
240
|
+
return validateGameProject(raw);
|
|
241
|
+
}
|
|
242
|
+
function loadGameProjectSync(read) {
|
|
243
|
+
let raw;
|
|
244
|
+
try {
|
|
245
|
+
raw = read(FORGE_JSON);
|
|
246
|
+
} catch (error) {
|
|
247
|
+
return readerFailure(error);
|
|
248
|
+
}
|
|
249
|
+
return validateGameProject(raw);
|
|
250
|
+
}
|
|
251
|
+
async function resolveDefaultScene(opts) {
|
|
252
|
+
const { read, resolveGuid } = opts;
|
|
253
|
+
const gpResult = await loadGameProject(read);
|
|
254
|
+
if (!gpResult.ok) {
|
|
255
|
+
return gpResult;
|
|
256
|
+
}
|
|
257
|
+
const gp = gpResult.value;
|
|
258
|
+
const defaultSceneGuid = gp.defaultScene;
|
|
259
|
+
if (defaultSceneGuid === void 0 || defaultSceneGuid === null) {
|
|
260
|
+
return err(
|
|
261
|
+
"forge-scene-unresolved",
|
|
262
|
+
"a defaultScene field in forge.json to resolve",
|
|
263
|
+
"add a defaultScene with a valid scene asset GUID to forge.json, or select a scene at runtime",
|
|
264
|
+
{ guid: "" }
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
const guidStr = defaultSceneGuid;
|
|
268
|
+
const resolveResult = await resolveGuid(guidStr);
|
|
269
|
+
if (!resolveResult.ok) {
|
|
270
|
+
return err(
|
|
271
|
+
"forge-scene-unresolved",
|
|
272
|
+
"the defaultScene GUID to resolve to an existing scene asset",
|
|
273
|
+
"verify the defaultScene GUID matches a scene asset's pack.json assets[].guid (where kind=scene)",
|
|
274
|
+
{ guid: guidStr }
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
const asset = resolveResult.value;
|
|
278
|
+
if (asset.kind !== "scene") {
|
|
279
|
+
return err(
|
|
280
|
+
"forge-scene-unresolved",
|
|
281
|
+
"the defaultScene GUID to point to a scene asset (kind=scene)",
|
|
282
|
+
`resolved asset kind is "${asset.kind}", not "scene"; verify the GUID points to a scene pack entry`,
|
|
283
|
+
{ guid: guidStr }
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
return ok({ guid: guidStr, kind: "scene" });
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export { FORGE_JSON, GameProjectError, GameProjectPluginEntrySchema, GameProjectPluginsSchema, GameProjectSchema, PluginRealmSchema, loadGameProject, loadGameProjectSync, resolveDefaultScene };
|
|
290
|
+
//# sourceMappingURL=index.mjs.map
|
|
291
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/paths.ts","../src/schema.ts","../src/loader.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// errors.ts — GameProjectError closed error surface (D-2)\n//\n// Four-field surface: .code / .expected / .hint / .detail\n// Structurally parallel to PackError (engine-pack) — same interface shape\n// (charter P4 consistent abstraction), but own code union (D-2: pipe isolation).\n// GUID format failure translates PackError → GameProjectError(code='forge-guid-malformed')\n// so PackError never leaks to engine-project public surface.\n//\n// AI users consume via exhaustive switch on .code — no default case needed:\n// ```ts\n// switch (err.code) {\n// case 'forge-missing': console.error(err.detail.path); break;\n// case 'forge-read-failed': console.error(err.detail.path, err.detail.cause); break;\n// case 'forge-parse-failed': console.error(err.detail.rawMessage); break;\n// // ... all 7 cases\n// }\n// ```\n\nimport type { z } from 'zod';\n\n/** forge.json file not found at the expected path. */\nexport interface ForgeMissingDetail {\n readonly path: string;\n}\n\n/** Why the injected forge.json reader refused without exposing source details. */\nexport type ForgeReadFailureCauseCode = 'permission-denied' | 'transient' | 'unknown';\n\n/** forge.json could not be read for a reason other than a missing file. */\nexport interface ForgeReadFailedDetail {\n readonly path: string;\n readonly cause: ForgeReadFailureCauseCode;\n}\n\n/** forge.json exists but contains invalid JSON. */\nexport interface ForgeParseFailedDetail {\n readonly path: string;\n readonly rawMessage: string;\n}\n\n/** forge.json is valid JSON but fails zod schema validation (missing required fields, wrong types). */\nexport interface ForgeSchemaInvalidDetail {\n readonly path: string;\n /** The zod issues from `safeParse(...).error.issues` — each names the failing path + reason. */\n readonly zodErrors: readonly z.ZodIssue[];\n}\n\n/** forge.json has .strict() rejected an unknown field (e.g. scenes[]). */\nexport interface ForgeUnknownFieldDetail {\n readonly path: string;\n readonly fieldNames: string[];\n}\n\n/** defaultScene GUID string is not a valid 36-char RFC 4122 dash-form UUID.\n * cause is the original PackError from AssetGuid.parse (for debugging), NOT part of reserved union. */\nexport interface ForgeGuidMalformedDetail {\n readonly field: string;\n readonly rawInput: string;\n readonly cause?: unknown; // PackError from engine-pack, optional for debugging (D-2)\n}\n\n/** defaultScene GUID is valid format but resolveGuid could not find it or found wrong kind. */\nexport interface ForgeSceneUnresolvedDetail {\n readonly guid: string;\n}\n\ntype GameProjectErrorDetailByCode = {\n 'forge-missing': ForgeMissingDetail;\n 'forge-read-failed': ForgeReadFailedDetail;\n 'forge-parse-failed': ForgeParseFailedDetail;\n 'forge-schema-invalid': ForgeSchemaInvalidDetail;\n 'forge-unknown-field': ForgeUnknownFieldDetail;\n 'forge-guid-malformed': ForgeGuidMalformedDetail;\n 'forge-scene-unresolved': ForgeSceneUnresolvedDetail;\n};\n\nexport type GameProjectErrorCode = keyof GameProjectErrorDetailByCode;\nexport type GameProjectErrorDetail = GameProjectErrorDetailByCode[GameProjectErrorCode];\n\n// ── constructor args ────────────────────────────────────────────────────────\n\nexport type GameProjectErrorArgs<C extends GameProjectErrorCode = GameProjectErrorCode> = {\n readonly code: C;\n readonly expected: string;\n readonly hint: string;\n readonly detail: GameProjectErrorDetailByCode[C];\n};\n\n// ── GameProjectError class (D-2) ─────────────────────────────────────────────\n\n/**\n * Structured error for the @forgeax/engine-project loader + resolve layer.\n *\n * AI users consume via exhaustive switch on .code — no default case needed.\n * Aligns with PackError four-field surface (.code/.expected/.hint/.detail)\n * per charter P4 (consistent abstraction) and AC-10.\n */\nclass GameProjectErrorClass extends Error {\n readonly code: GameProjectErrorCode;\n readonly expected: string;\n readonly hint: string;\n readonly detail: GameProjectErrorDetail;\n\n constructor(args: GameProjectErrorArgs) {\n super(`[GameProjectError ${args.code}] expected: ${args.expected}; hint: ${args.hint}`);\n this.name = 'GameProjectError';\n this.code = args.code;\n this.expected = args.expected;\n this.hint = args.hint;\n this.detail = args.detail;\n }\n}\n\ntype GameProjectErrorVariant<C extends GameProjectErrorCode> = GameProjectErrorClass & {\n readonly code: C;\n readonly detail: GameProjectErrorDetailByCode[C];\n};\n\nexport type GameProjectError = {\n [C in GameProjectErrorCode]: GameProjectErrorVariant<C>;\n}[GameProjectErrorCode];\n\ninterface GameProjectErrorConstructor {\n new <C extends GameProjectErrorCode>(args: GameProjectErrorArgs<C>): GameProjectErrorVariant<C>;\n readonly prototype: GameProjectErrorClass;\n}\n\nexport const GameProjectError: GameProjectErrorConstructor =\n GameProjectErrorClass as unknown as GameProjectErrorConstructor;\n","// paths.ts — path constants SSOT (D-8 bottom tier)\n//\n// All path literals for forge.json live here as the single authoritative source.\n// Consumers import FORGE_JSON rather than hardcoding 'forge.json' strings.\n\n/** The forge.json manifest filename, relative to a game root directory. */\nexport const FORGE_JSON = 'forge.json' as const;\n","// schema.ts — GameProjectSchema + GuidString refinement (D-4, D-7)\n//\n// D-4 fields: id:string / name:string / schemaVersion:string / entry?:string /\n// executionEntry?:string /\n// defaultScene?:GuidString / physics?:union(enum+bool) / pointerLock?:bool /\n// input?:string / preview?:nested-object. .strict() rejects unknown fields.\n//\n// D-7: GuidString refinement lives here (engine-project), calls\n// AssetGuid.parse from engine-pack, translates PackError to zod error message.\n\nimport { AssetGuid } from '@forgeax/engine-pack/guid';\nimport { z } from 'zod';\n\n// ── GuidString: zod refinement calling AssetGuid.parse (AC-04) ──────────────\nexport const GuidString = z.string().refine(\n (val) => AssetGuid.parse(val).ok,\n (val) => {\n const parsed = AssetGuid.parse(val);\n const message = !parsed.ok ? parsed.error.hint : `invalid GUID: ${val}`;\n return { message };\n },\n);\n\n// ── physics union: all 5 known values (D-4) ─────────────────────────────────\nconst PhysicsUnion = z.union([z.enum(['3d', '2d', 'rapier-3d', 'rapier-2d']), z.boolean()]);\n\n// ── preview.skin nested object (D-4) ────────────────────────────────────────\nconst SkinSchema = z\n .object({\n sceneGuid: z.string().optional(),\n clipGuids: z.array(z.string()).optional(),\n clipDefault: z.string().optional(),\n scale: z.number().optional(),\n pos: z.array(z.number()).optional(),\n })\n .passthrough();\n\nconst PreviewSchema = z.object({ skin: SkinSchema }).passthrough();\n\n// Digital Life NPC runtime policy embedded in forge.json. The Brain owns\n// prompt/model execution; the game manifest only declares the bounded model\n// and governor ceilings consumed by the server-side NPC adapter.\nconst NpcBudgetSchema = z\n .object({\n maxCallsPerMinute: z.number().int().positive().optional(),\n maxTokensPerMinute: z.number().int().positive().optional(),\n maxConcurrent: z.number().int().positive().optional(),\n })\n .strict();\n\nconst NpcConfigSchema = z\n .object({\n model: z.string().min(1).optional(),\n maxTokens: z.number().int().positive().optional(),\n budget: NpcBudgetSchema.optional(),\n })\n .strict();\n\nexport const PluginRealmSchema = z.enum(['host', 'engine', 'build']);\n\nconst PluginInjectSchema = z.union([\n z.array(z.string().min(1)),\n z.record(z.string().min(1), z.unknown()),\n]);\n\nconst PluginEntryBase = z.object({\n id: z.string().min(1),\n name: z.string().min(1),\n disabled: z.boolean().nullable().optional(),\n inject: PluginInjectSchema.nullable().optional(),\n realm: PluginRealmSchema.optional(),\n});\n\nexport interface GameProjectPluginEntry {\n readonly id: string;\n readonly name: string;\n readonly config?: unknown;\n readonly group?: boolean | null | undefined;\n readonly disabled?: boolean | null | undefined;\n readonly inject?: readonly string[] | Readonly<Record<string, unknown>> | null | undefined;\n readonly realm?: z.infer<typeof PluginRealmSchema> | undefined;\n}\n\nexport const GameProjectPluginEntrySchema: z.ZodType<GameProjectPluginEntry> = z.lazy(() =>\n z.union([\n PluginEntryBase.extend({\n group: z.literal(true),\n config: z.array(GameProjectPluginEntrySchema),\n }).strict(),\n PluginEntryBase.extend({\n group: z.union([z.literal(false), z.null()]).optional(),\n config: z.unknown().optional(),\n }).strict(),\n ]),\n);\n\nexport const GameProjectPluginsSchema = z\n .array(GameProjectPluginEntrySchema)\n .superRefine((entries, ctx) => {\n const seen = new Set<string>();\n const visit = (items: readonly GameProjectPluginEntry[]): void => {\n for (const entry of items) {\n if (seen.has(entry.id)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `duplicate plugin entry id: ${entry.id}`,\n });\n }\n seen.add(entry.id);\n if (entry.group === true) visit(entry.config as readonly GameProjectPluginEntry[]);\n }\n };\n visit(entries);\n });\n\n// ── GameProjectSchema: strict zod object (AC-03, AC-05) ─────────────────────\n// This schema is the authoritative field list for forge.json (charter P2) —\n// read it instead of prose docs. Each field carries its contract inline.\nexport const GameProjectSchema = z\n .object({\n /** Stable game slug; matches the `.forgeax/games/<id>/` directory name. */\n id: z.string(),\n /** Human-facing display name (may contain any unicode). */\n name: z.string(),\n /** forge.json schema version, e.g. \"1.0.0\" — required so loaders can gate on format. */\n schemaVersion: z.string(),\n /** Optional bootstrap hook: entry module relative to game root (e.g. \"main.ts\", \"src/main.ts\"). */\n entry: z.string().optional(),\n /** Optional realm-local ExecutionBootstrapEntry module relative to game root. */\n executionEntry: z.string().optional(),\n /** Optional GUID of the scene to load first; must be a real scene asset GUID (GuidString-validated). */\n defaultScene: GuidString.optional(),\n /** Optional physics backend: enum tag ('3d'/'2d'/'rapier-3d'/'rapier-2d') or boolean on/off. */\n physics: PhysicsUnion.optional(),\n /** Optional flag requesting pointer-lock (FPS-style mouse capture) at play time. */\n pointerLock: z.boolean().optional(),\n /** Optional input scheme hint consumed by play-runtime (e.g. \"fps\"). */\n input: z.string().optional(),\n /** Optional editor preview config (skin scene/clips for the launcher card). */\n preview: PreviewSchema.optional(),\n /** Native DeepSeek Harness Entry tree, plus the ForgeaX build-only realm selector. */\n plugins: GameProjectPluginsSchema.optional(),\n /** Optional Digital Life NPC Brain policy consumed by the server adapter. */\n npc: NpcConfigSchema.optional(),\n })\n .strict();\n\n// ── GameProject type: z.infer-derived (AC-02, AC-05) ────────────────────────\nexport type GameProject = z.infer<typeof GameProjectSchema>;\n","// loader.ts — loadGameProject + resolveDefaultScene (D-6, AC-06/07/08/09)\n//\n// loadGameProject: injection-only `read:(path)=>Promise<string>`, returns\n// GuidResult<GameProject, GameProjectError>. Reader failures preserve ENOENT\n// as forge-missing and classify all other refusals as forge-read-failed;\n// validation then has the remaining five return paths:\n// 2. JSON.parse fails → ok:false, error(code='forge-parse-failed')\n// 3. schema.parse fails (missing fields) → ok:false, error(code='forge-schema-invalid')\n// 3b. schema.parse fails (unknown fields via .strict()) → ok:false, error(code='forge-unknown-field')\n// 4. defaultScene GUID format invalid → ok:false, error(code='forge-guid-malformed')\n// 5. all valid → ok:true, value:GameProject\n//\n// resolveDefaultScene: {read, resolveGuid} dual-injection (AC-07). Independent\n// of loadGameProject (does NOT call resolveGuid internally).\n//\n// D-6: return type GuidResult<T,E> — same as AssetGuid.parse (engine-pack).\n// D-2: PackError→GameProjectError translation for GUID format failures.\n\nimport type { GuidResult } from '@forgeax/engine-pack/guid';\nimport {\n type ForgeReadFailureCauseCode,\n GameProjectError,\n type GameProjectErrorArgs,\n type GameProjectErrorCode,\n} from './errors.js';\nimport { FORGE_JSON } from './paths.js';\nimport type { GameProject } from './schema.js';\nimport { GameProjectSchema } from './schema.js';\n\n// ── helpers ─────────────────────────────────────────────────────────────────\n\nfunction err<C extends GameProjectErrorCode>(\n code: C,\n expected: string,\n hint: string,\n detail: GameProjectErrorArgs<C>['detail'],\n) {\n return { ok: false as const, error: new GameProjectError({ code, expected, hint, detail }) };\n}\n\nfunction ok<T>(value: T) {\n return { ok: true as const, value };\n}\n\ntype ReaderErrorMetadata = {\n readonly code?: unknown;\n readonly name?: unknown;\n};\n\nfunction readerFailureToken(error: unknown): string | undefined {\n if (typeof error !== 'object' || error === null) {\n return undefined;\n }\n\n const metadata = error as ReaderErrorMetadata;\n if (typeof metadata.code === 'string') {\n return metadata.code;\n }\n if (typeof metadata.name === 'string') {\n return metadata.name;\n }\n return undefined;\n}\n\nfunction readerFailureCause(token: string | undefined): ForgeReadFailureCauseCode {\n switch (token) {\n case 'EACCES':\n case 'EPERM':\n case 'PermissionDeniedError':\n case 'NotAllowedError':\n case 'SecurityError':\n return 'permission-denied';\n case 'EAGAIN':\n case 'EBUSY':\n case 'EINTR':\n case 'ECONNABORTED':\n case 'ECONNREFUSED':\n case 'ECONNRESET':\n case 'EHOSTUNREACH':\n case 'ENETDOWN':\n case 'ENETUNREACH':\n case 'ETIMEDOUT':\n case 'EPIPE':\n case 'ABORT_ERR':\n case 'AbortError':\n case 'TimeoutError':\n return 'transient';\n default:\n return 'unknown';\n }\n}\n\nfunction readerFailure(error: unknown) {\n const token = readerFailureToken(error);\n if (token === 'ENOENT') {\n return err(\n 'forge-missing',\n 'forge.json file to exist at the game root',\n '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',\n { path: FORGE_JSON },\n );\n }\n\n return err(\n 'forge-read-failed',\n 'forge.json reader to complete without refusal',\n 'retry the project reader; if the refusal persists, verify access to the game directory',\n { path: FORGE_JSON, cause: readerFailureCause(token) },\n );\n}\n\n// ── validateGameProject: sync pure core (JSON.parse → schema validate → 5 return paths) ──\n\n/**\n * Validate raw forge.json text against GameProjectSchema.\n * Pure sync function — no I/O, no `read` injection.\n *\n * ## Return paths (4 — missing/read-error handled by callers)\n *\n * | # | Condition | ok | code |\n * |:--|:--|:--|:--|\n * | 1 | `JSON.parse` fails | false | `forge-parse-failed` |\n * | 2a | zod `.strict()` unknown fields (e.g. `scenes[]`) | false | `forge-unknown-field` |\n * | 2b | zod required field missing / wrong type | false | `forge-schema-invalid` |\n * | 2c | `defaultScene` present, GUID format invalid | false | `forge-guid-malformed` |\n * | 3 | all valid | true | — |\n */\nexport function validateGameProject(raw: string): GuidResult<GameProject, GameProjectError> {\n // ── 1. Parse JSON ─────────────────────────────────────────────────────────\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (e: unknown) {\n return err(\n 'forge-parse-failed',\n 'forge.json to be valid JSON',\n 'check forge.json for JSON syntax errors (trailing commas, unquoted keys, etc.)',\n {\n path: FORGE_JSON,\n rawMessage: e instanceof Error ? e.message : String(e),\n },\n );\n }\n\n // ── 2. Schema validate (.strict() rejects unknown fields) ─────────────────\n const schemaResult = GameProjectSchema.safeParse(parsed);\n if (!schemaResult.success) {\n const zodErrors = schemaResult.error.issues;\n\n // 2a: unknown fields (scenes[] etc.) — detect by looking for unrecognized_keys\n const unknownFieldIssues = zodErrors.filter((i) => i.code === 'unrecognized_keys');\n if (unknownFieldIssues.length > 0) {\n const fieldNames = unknownFieldIssues.flatMap((i) => (i as { keys?: string[] }).keys ?? []);\n return err(\n 'forge-unknown-field',\n 'forge.json to not contain unknown fields (e.g. scenes[])',\n 'remove unknown fields from forge.json; refer to GameProjectSchema in @forgeax/engine-project for the authoritative field list',\n { path: FORGE_JSON, fieldNames },\n );\n }\n\n // 2c: GuidString refinement failure → forge-guid-malformed (D-2 translation)\n const guidFieldIssues = zodErrors.filter(\n (i) => Array.isArray(i.path) && i.path.includes('defaultScene'),\n );\n if (guidFieldIssues.length > 0) {\n const rawInput =\n typeof (parsed as Record<string, unknown>).defaultScene === 'string'\n ? String((parsed as Record<string, unknown>).defaultScene)\n : '';\n return err(\n 'forge-guid-malformed',\n 'defaultScene to be a valid 36-char RFC 4122 dash-form UUID',\n 'use a valid scene GUID; find it in the scene pack.json assets[].guid where kind=scene',\n {\n field: 'defaultScene',\n rawInput,\n },\n );\n }\n\n // 2b: missing required fields or wrong types\n return err(\n 'forge-schema-invalid',\n 'forge.json to satisfy GameProjectSchema',\n 'check forge.json against GameProjectSchema (z.infer for types); required fields: id, name, schemaVersion (all strings)',\n { path: FORGE_JSON, zodErrors },\n );\n }\n\n // ── 3. Success ────────────────────────────────────────────────────────────\n return ok(schemaResult.data);\n}\n\n// ── loadGameProject: async (injection-only read) ────────────────────────────────\n\n/**\n * Load and validate a game project manifest from the abstract async reader.\n *\n * Wraps `validateGameProject`: reads `FORGE_JSON` via `read`, then validates.\n * If `read` throws/rejects → `forge-missing` for ENOENT, otherwise\n * `forge-read-failed` with a bounded cause code.\n *\n * ## Return paths (5)\n *\n * | # | Condition | ok | code |\n * |:--|:--|:--|:--|\n * | 1 | `read(FORGE_JSON)` throws / rejects with ENOENT | false | `forge-missing` |\n * | 1b | `read(FORGE_JSON)` refuses for another reason | false | `forge-read-failed` |\n * | 2 | `JSON.parse` fails | false | `forge-parse-failed` |\n * | 3a | zod `.strict()` unknown fields (e.g. `scenes[]`) | false | `forge-unknown-field` |\n * | 3b | zod required field missing / wrong type | false | `forge-schema-invalid` |\n * | 4 | `defaultScene` present, GUID format invalid (AssetGuid.parse fails) | false | `forge-guid-malformed` |\n * | 5 | all valid | true | — |\n *\n * ## Charter mapping\n *\n * - **P3 (explicit failure)**: every failure path returns structured `GameProjectError`\n * with `.code`/`.expected`/`.hint`/`.detail`; no silent catch-and-ignore or fallback.\n * - **P4 (consistent abstraction)**: return shape is `GuidResult` (same alias as\n * `AssetGuid.parse` from engine-pack).\n * - **SSOT**: this is the ONE authoritative forge.json loader — all consumers\n * import it instead of hand-rolling their own fetch+as / JSON.parse+as.\n */\nexport async function loadGameProject(\n read: (path: string) => Promise<string>,\n): Promise<GuidResult<GameProject, GameProjectError>> {\n let raw: string;\n try {\n raw = await read(FORGE_JSON);\n } catch (error: unknown) {\n return readerFailure(error);\n }\n\n return validateGameProject(raw);\n}\n\n// ── loadGameProjectSync: sync companion (for sync-only callers like ContextSlot) ──\n\n/**\n * Synchronous version of loadGameProject — for callers that cannot use async\n * (e.g. sync `ContextSlot` content functions).\n *\n * Accepts a sync `read:(path)=>string` injection (same contract shape,\n * sync return). If `read` throws → `forge-missing` for ENOENT, otherwise\n * `forge-read-failed` with a bounded cause code.\n *\n * Uses the same `validateGameProject` pure core as `loadGameProject`.\n */\nexport function loadGameProjectSync(\n read: (path: string) => string,\n): GuidResult<GameProject, GameProjectError> {\n let raw: string;\n try {\n raw = read(FORGE_JSON);\n } catch (error: unknown) {\n return readerFailure(error);\n }\n\n return validateGameProject(raw);\n}\n\n// ── resolveDefaultScene: {read, resolveGuid} dual injection (AC-07) ─────────\n\n/** Resolved scene asset with GUID and kind='scene' confirmation. */\nexport interface ResolvedScene {\n readonly guid: string;\n readonly kind: 'scene';\n}\n\n/**\n * Resolve the defaultScene GUID to a scene asset using the injected resolveGuid.\n *\n * ## Dual injection (AC-07)\n *\n * - `read`: same `(path)=>Promise<string>` as loadGameProject — reads forge.json.\n * - `resolveGuid`: resolves a GUID string to an asset with `kind` field.\n * Signature: `(guid: string) => Promise<{ok:true, value:{kind:string, guid:string}} | {ok:false, error:unknown}>`\n *\n * `loadGameProject` does NOT call resolveGuid; resolveDefaultScene calls both\n * independently (charter SSOT: two-layer separation, format vs resolve).\n *\n * ## Return paths\n *\n * | Condition | ok | code |\n * |:--|:--|:--|\n * | loadGameProject returns !ok | false | propagated from loader |\n * | no defaultScene | false | `forge-scene-unresolved` |\n * | resolveGuid returns !ok | false | `forge-scene-unresolved` |\n * | resolveGuid returns asset.kind !== 'scene' | false | `forge-scene-unresolved` |\n * | resolveGuid returns asset.kind === 'scene' | true | — |\n */\nexport async function resolveDefaultScene(opts: {\n read: (path: string) => Promise<string>;\n resolveGuid: (\n guid: string,\n ) => Promise<{ ok: true; value: { kind: string; guid: string } } | { ok: false; error: unknown }>;\n}): Promise<GuidResult<ResolvedScene, GameProjectError>> {\n const { read, resolveGuid } = opts;\n\n // 1. Load the game project\n const gpResult = await loadGameProject(read);\n if (!gpResult.ok) {\n return gpResult; // propagate loader error\n }\n\n // 2. Check if defaultScene exists\n const gp = gpResult.value;\n const defaultSceneGuid = gp.defaultScene;\n if (defaultSceneGuid === undefined || defaultSceneGuid === null) {\n return err(\n 'forge-scene-unresolved',\n 'a defaultScene field in forge.json to resolve',\n 'add a defaultScene with a valid scene asset GUID to forge.json, or select a scene at runtime',\n { guid: '' },\n );\n }\n\n // 3. Resolve the GUID\n const guidStr = defaultSceneGuid as string;\n const resolveResult = await resolveGuid(guidStr);\n\n if (!resolveResult.ok) {\n return err(\n 'forge-scene-unresolved',\n 'the defaultScene GUID to resolve to an existing scene asset',\n \"verify the defaultScene GUID matches a scene asset's pack.json assets[].guid (where kind=scene)\",\n { guid: guidStr },\n );\n }\n\n // 4. Verify kind === 'scene'\n const asset = resolveResult.value;\n if (asset.kind !== 'scene') {\n return err(\n 'forge-scene-unresolved',\n 'the defaultScene GUID to point to a scene asset (kind=scene)',\n `resolved asset kind is \"${asset.kind}\", not \"scene\"; verify the GUID points to a scene pack entry`,\n { guid: guidStr },\n );\n }\n\n return ok({ guid: guidStr, kind: 'scene' });\n}\n"]}
|
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { GuidResult } from '@forgeax/engine-pack/guid';
|
|
2
|
+
import { GameProjectError } from './errors.js';
|
|
3
|
+
import type { GameProject } from './schema.js';
|
|
4
|
+
/**
|
|
5
|
+
* Validate raw forge.json text against GameProjectSchema.
|
|
6
|
+
* Pure sync function — no I/O, no `read` injection.
|
|
7
|
+
*
|
|
8
|
+
* ## Return paths (4 — missing/read-error handled by callers)
|
|
9
|
+
*
|
|
10
|
+
* | # | Condition | ok | code |
|
|
11
|
+
* |:--|:--|:--|:--|
|
|
12
|
+
* | 1 | `JSON.parse` fails | false | `forge-parse-failed` |
|
|
13
|
+
* | 2a | zod `.strict()` unknown fields (e.g. `scenes[]`) | false | `forge-unknown-field` |
|
|
14
|
+
* | 2b | zod required field missing / wrong type | false | `forge-schema-invalid` |
|
|
15
|
+
* | 2c | `defaultScene` present, GUID format invalid | false | `forge-guid-malformed` |
|
|
16
|
+
* | 3 | all valid | true | — |
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateGameProject(raw: string): GuidResult<GameProject, GameProjectError>;
|
|
19
|
+
/**
|
|
20
|
+
* Load and validate a game project manifest from the abstract async reader.
|
|
21
|
+
*
|
|
22
|
+
* Wraps `validateGameProject`: reads `FORGE_JSON` via `read`, then validates.
|
|
23
|
+
* If `read` throws/rejects → `forge-missing` for ENOENT, otherwise
|
|
24
|
+
* `forge-read-failed` with a bounded cause code.
|
|
25
|
+
*
|
|
26
|
+
* ## Return paths (5)
|
|
27
|
+
*
|
|
28
|
+
* | # | Condition | ok | code |
|
|
29
|
+
* |:--|:--|:--|:--|
|
|
30
|
+
* | 1 | `read(FORGE_JSON)` throws / rejects with ENOENT | false | `forge-missing` |
|
|
31
|
+
* | 1b | `read(FORGE_JSON)` refuses for another reason | false | `forge-read-failed` |
|
|
32
|
+
* | 2 | `JSON.parse` fails | false | `forge-parse-failed` |
|
|
33
|
+
* | 3a | zod `.strict()` unknown fields (e.g. `scenes[]`) | false | `forge-unknown-field` |
|
|
34
|
+
* | 3b | zod required field missing / wrong type | false | `forge-schema-invalid` |
|
|
35
|
+
* | 4 | `defaultScene` present, GUID format invalid (AssetGuid.parse fails) | false | `forge-guid-malformed` |
|
|
36
|
+
* | 5 | all valid | true | — |
|
|
37
|
+
*
|
|
38
|
+
* ## Charter mapping
|
|
39
|
+
*
|
|
40
|
+
* - **P3 (explicit failure)**: every failure path returns structured `GameProjectError`
|
|
41
|
+
* with `.code`/`.expected`/`.hint`/`.detail`; no silent catch-and-ignore or fallback.
|
|
42
|
+
* - **P4 (consistent abstraction)**: return shape is `GuidResult` (same alias as
|
|
43
|
+
* `AssetGuid.parse` from engine-pack).
|
|
44
|
+
* - **SSOT**: this is the ONE authoritative forge.json loader — all consumers
|
|
45
|
+
* import it instead of hand-rolling their own fetch+as / JSON.parse+as.
|
|
46
|
+
*/
|
|
47
|
+
export declare function loadGameProject(read: (path: string) => Promise<string>): Promise<GuidResult<GameProject, GameProjectError>>;
|
|
48
|
+
/**
|
|
49
|
+
* Synchronous version of loadGameProject — for callers that cannot use async
|
|
50
|
+
* (e.g. sync `ContextSlot` content functions).
|
|
51
|
+
*
|
|
52
|
+
* Accepts a sync `read:(path)=>string` injection (same contract shape,
|
|
53
|
+
* sync return). If `read` throws → `forge-missing` for ENOENT, otherwise
|
|
54
|
+
* `forge-read-failed` with a bounded cause code.
|
|
55
|
+
*
|
|
56
|
+
* Uses the same `validateGameProject` pure core as `loadGameProject`.
|
|
57
|
+
*/
|
|
58
|
+
export declare function loadGameProjectSync(read: (path: string) => string): GuidResult<GameProject, GameProjectError>;
|
|
59
|
+
/** Resolved scene asset with GUID and kind='scene' confirmation. */
|
|
60
|
+
export interface ResolvedScene {
|
|
61
|
+
readonly guid: string;
|
|
62
|
+
readonly kind: 'scene';
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resolve the defaultScene GUID to a scene asset using the injected resolveGuid.
|
|
66
|
+
*
|
|
67
|
+
* ## Dual injection (AC-07)
|
|
68
|
+
*
|
|
69
|
+
* - `read`: same `(path)=>Promise<string>` as loadGameProject — reads forge.json.
|
|
70
|
+
* - `resolveGuid`: resolves a GUID string to an asset with `kind` field.
|
|
71
|
+
* Signature: `(guid: string) => Promise<{ok:true, value:{kind:string, guid:string}} | {ok:false, error:unknown}>`
|
|
72
|
+
*
|
|
73
|
+
* `loadGameProject` does NOT call resolveGuid; resolveDefaultScene calls both
|
|
74
|
+
* independently (charter SSOT: two-layer separation, format vs resolve).
|
|
75
|
+
*
|
|
76
|
+
* ## Return paths
|
|
77
|
+
*
|
|
78
|
+
* | Condition | ok | code |
|
|
79
|
+
* |:--|:--|:--|
|
|
80
|
+
* | loadGameProject returns !ok | false | propagated from loader |
|
|
81
|
+
* | no defaultScene | false | `forge-scene-unresolved` |
|
|
82
|
+
* | resolveGuid returns !ok | false | `forge-scene-unresolved` |
|
|
83
|
+
* | resolveGuid returns asset.kind !== 'scene' | false | `forge-scene-unresolved` |
|
|
84
|
+
* | resolveGuid returns asset.kind === 'scene' | true | — |
|
|
85
|
+
*/
|
|
86
|
+
export declare function resolveDefaultScene(opts: {
|
|
87
|
+
read: (path: string) => Promise<string>;
|
|
88
|
+
resolveGuid: (guid: string) => Promise<{
|
|
89
|
+
ok: true;
|
|
90
|
+
value: {
|
|
91
|
+
kind: string;
|
|
92
|
+
guid: string;
|
|
93
|
+
};
|
|
94
|
+
} | {
|
|
95
|
+
ok: false;
|
|
96
|
+
error: unknown;
|
|
97
|
+
}>;
|
|
98
|
+
}): Promise<GuidResult<ResolvedScene, GameProjectError>>;
|
|
99
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAEL,gBAAgB,EAGjB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAuF/C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAiE1F;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GACtC,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC,CASpD;AAID;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAC7B,UAAU,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAS3C;AAID,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,WAAW,EAAE,CACX,IAAI,EAAE,MAAM,KACT,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACnG,GAAG,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC,CA8CvD"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAKA,2EAA2E;AAC3E,eAAO,MAAM,UAAU,EAAG,YAAqB,CAAC"}
|