@bitmagic/world-forger 0.1.43-dev.5 → 0.1.43-dev.7

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.
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Expanding `engine-asset:` URLs to absolute ones, for the Bitmagic writers.
3
+ *
4
+ * A template may name an engine-shipped file as `engine-asset:<path>` (W5.6, decision H-c): the
5
+ * engine resolves it at load time against the active hosting's `contentBaseUrl`, so one template
6
+ * serves every hosting provider. Bitmagic's own writers — the CLI's `init`/`upgrade`/`import` and
7
+ * the agent's template import and switch — do not keep the scheme (decision H-d): they expand it
8
+ * to the Bitmagic content base when they copy a template, so a Bitmagic `world.json`/`game.json`
9
+ * stays byte-identical to what it was before the scheme existed and every offline reader (Creator
10
+ * previews, the agent's world inspection, the CLI's URL collectors, the api-server thumbnails)
11
+ * keeps seeing absolute URLs. See docs/engine-open-source-audit/plans/W5.6-hosting.md §2.3.
12
+ *
13
+ * The scheme string is repeated here on purpose: the engine's `ENGINE_ASSET_SCHEME`
14
+ * (game/src/engine/runtime/hosting.ts) cannot be imported by a shared package. The two are held
15
+ * equal by game/src/bitmagic/__tests__/TemplateExpansion.test.ts.
16
+ */
17
+ /** The prefix that marks a URL as relative to the hosting's content root. */
18
+ export declare const ENGINE_ASSET_URL_SCHEME = "engine-asset:";
19
+ /**
20
+ * `url` with the scheme replaced by `base`, or `url` itself when it does not carry the scheme.
21
+ * The same rule as the engine's `resolveEngineAssetUrl`: leading slashes of the path are dropped
22
+ * and a `/` is supplied when `base` lacks one, so a writer's expansion and the engine's load-time
23
+ * resolution always give the same URL (held by TemplateExpansion.test.ts).
24
+ */
25
+ export declare function expandEngineAssetUrl(url: string, base: string): string;
26
+ /**
27
+ * Every string anywhere in `value` (object values and array items, at any depth — never object
28
+ * keys) that starts with `engine-asset:` expanded by {@link expandEngineAssetUrl}. `base` is a
29
+ * content root, e.g. `BITMAGIC_ENGINE_CONTENT_BASE` from `@bitmagic/asset-core/engine-content`.
30
+ *
31
+ * Pure and copy-on-write: what changes is copied along the path to it, everything else is shared,
32
+ * and when nothing matches the SAME value comes back (`===`), so a caller can tell "nothing to
33
+ * write" from the identity alone.
34
+ */
35
+ export declare function expandEngineAssetUrls<T>(value: T, base: string): T;
36
+ /**
37
+ * The JSON document in `text` with its `engine-asset:` URLs expanded, for a writer that copies a
38
+ * template's `world.json`/`game.json` as text.
39
+ *
40
+ * `text` itself comes back — byte for byte — when the document has nothing to expand (including
41
+ * text that is not JSON: a writer copying a file is not the place to reject it). Otherwise the
42
+ * document is re-serialized with two-space indentation, keeping a trailing newline if the input
43
+ * had one, which is the format every template under templates/ is already in; so expanding a
44
+ * template whose URLs were converted to the scheme gives back exactly the file it was converted
45
+ * from.
46
+ */
47
+ export declare function expandEngineAssetUrlsInJsonText(text: string, base: string): string;
48
+ //# sourceMappingURL=engine-asset-urls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-asset-urls.d.ts","sourceRoot":"","sources":["../src/engine-asset-urls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAItE;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAElE;AAuCD;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAWlF"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Expanding `engine-asset:` URLs to absolute ones, for the Bitmagic writers.
3
+ *
4
+ * A template may name an engine-shipped file as `engine-asset:<path>` (W5.6, decision H-c): the
5
+ * engine resolves it at load time against the active hosting's `contentBaseUrl`, so one template
6
+ * serves every hosting provider. Bitmagic's own writers — the CLI's `init`/`upgrade`/`import` and
7
+ * the agent's template import and switch — do not keep the scheme (decision H-d): they expand it
8
+ * to the Bitmagic content base when they copy a template, so a Bitmagic `world.json`/`game.json`
9
+ * stays byte-identical to what it was before the scheme existed and every offline reader (Creator
10
+ * previews, the agent's world inspection, the CLI's URL collectors, the api-server thumbnails)
11
+ * keeps seeing absolute URLs. See docs/engine-open-source-audit/plans/W5.6-hosting.md §2.3.
12
+ *
13
+ * The scheme string is repeated here on purpose: the engine's `ENGINE_ASSET_SCHEME`
14
+ * (game/src/engine/runtime/hosting.ts) cannot be imported by a shared package. The two are held
15
+ * equal by game/src/bitmagic/__tests__/TemplateExpansion.test.ts.
16
+ */
17
+ /** The prefix that marks a URL as relative to the hosting's content root. */
18
+ export const ENGINE_ASSET_URL_SCHEME = 'engine-asset:';
19
+ /**
20
+ * `url` with the scheme replaced by `base`, or `url` itself when it does not carry the scheme.
21
+ * The same rule as the engine's `resolveEngineAssetUrl`: leading slashes of the path are dropped
22
+ * and a `/` is supplied when `base` lacks one, so a writer's expansion and the engine's load-time
23
+ * resolution always give the same URL (held by TemplateExpansion.test.ts).
24
+ */
25
+ export function expandEngineAssetUrl(url, base) {
26
+ if (!url.startsWith(ENGINE_ASSET_URL_SCHEME))
27
+ return url;
28
+ const rest = url.slice(ENGINE_ASSET_URL_SCHEME.length).replace(/^\/+/, '');
29
+ return `${base.endsWith('/') ? base : `${base}/`}${rest}`;
30
+ }
31
+ /**
32
+ * Every string anywhere in `value` (object values and array items, at any depth — never object
33
+ * keys) that starts with `engine-asset:` expanded by {@link expandEngineAssetUrl}. `base` is a
34
+ * content root, e.g. `BITMAGIC_ENGINE_CONTENT_BASE` from `@bitmagic/asset-core/engine-content`.
35
+ *
36
+ * Pure and copy-on-write: what changes is copied along the path to it, everything else is shared,
37
+ * and when nothing matches the SAME value comes back (`===`), so a caller can tell "nothing to
38
+ * write" from the identity alone.
39
+ */
40
+ export function expandEngineAssetUrls(value, base) {
41
+ return expandValue(value, base);
42
+ }
43
+ function expandValue(value, base) {
44
+ if (typeof value === 'string')
45
+ return expandEngineAssetUrl(value, base);
46
+ if (Array.isArray(value)) {
47
+ let out = null;
48
+ for (let i = 0; i < value.length; i++) {
49
+ const item = value[i];
50
+ const next = expandValue(item, base);
51
+ if (next !== item) {
52
+ out ?? (out = value.slice());
53
+ out[i] = next;
54
+ }
55
+ }
56
+ return out ?? value;
57
+ }
58
+ if (isPlainObject(value)) {
59
+ let out = null;
60
+ for (const key of Object.keys(value)) {
61
+ const item = value[key];
62
+ const next = expandValue(item, base);
63
+ if (next !== item) {
64
+ out ?? (out = { ...value });
65
+ // defineProperty, not assignment: JSON.parse makes `__proto__` an own key, and assigning
66
+ // to it would set the copy's prototype instead of the value.
67
+ Object.defineProperty(out, key, { value: next, writable: true, enumerable: true, configurable: true });
68
+ }
69
+ }
70
+ return out ?? value;
71
+ }
72
+ return value;
73
+ }
74
+ function isPlainObject(value) {
75
+ if (typeof value !== 'object' || value === null)
76
+ return false;
77
+ const proto = Object.getPrototypeOf(value);
78
+ return proto === Object.prototype || proto === null;
79
+ }
80
+ /**
81
+ * The JSON document in `text` with its `engine-asset:` URLs expanded, for a writer that copies a
82
+ * template's `world.json`/`game.json` as text.
83
+ *
84
+ * `text` itself comes back — byte for byte — when the document has nothing to expand (including
85
+ * text that is not JSON: a writer copying a file is not the place to reject it). Otherwise the
86
+ * document is re-serialized with two-space indentation, keeping a trailing newline if the input
87
+ * had one, which is the format every template under templates/ is already in; so expanding a
88
+ * template whose URLs were converted to the scheme gives back exactly the file it was converted
89
+ * from.
90
+ */
91
+ export function expandEngineAssetUrlsInJsonText(text, base) {
92
+ if (!text.includes(ENGINE_ASSET_URL_SCHEME))
93
+ return text;
94
+ let parsed;
95
+ try {
96
+ parsed = JSON.parse(text);
97
+ }
98
+ catch {
99
+ return text;
100
+ }
101
+ const expanded = expandEngineAssetUrls(parsed, base);
102
+ if (expanded === parsed)
103
+ return text;
104
+ return `${JSON.stringify(expanded, null, 2)}${text.endsWith('\n') ? '\n' : ''}`;
105
+ }
106
+ //# sourceMappingURL=engine-asset-urls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-asset-urls.js","sourceRoot":"","sources":["../src/engine-asset-urls.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -24,6 +24,7 @@
24
24
  */
25
25
  export * from './artifact-types.js';
26
26
  export * from './forge-constants.js';
27
+ export * from './engine-asset-urls.js';
27
28
  export * from './physics-mode.js';
28
29
  export * from './terrain-height-grid.js';
29
30
  export * from './world-json-strict-validator.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,4BAA4B,CAAC"}
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@
24
24
  */
25
25
  export * from './artifact-types.js';
26
26
  export * from './forge-constants.js';
27
+ export * from './engine-asset-urls.js';
27
28
  export * from './physics-mode.js';
28
29
  export * from './terrain-height-grid.js';
29
30
  export * from './world-json-strict-validator.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,4BAA4B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitmagic/world-forger",
3
- "version": "0.1.43-dev.5",
3
+ "version": "0.1.43-dev.7",
4
4
  "description": "Client half of the Bitmagic world forger: the forged-level artifact schema, the host seams, and the browser pipeline steps that bake archetypes, bake a level and place its instances.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "Bitmagic Oy",