@things-factory/board-service 10.1.40 → 10.1.41
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/client/entries/headless-scene-components.js +19 -0
- package/client/index.js +6 -0
- package/dist-server/headless-entry.test.d.ts +1 -0
- package/dist-server/headless-entry.test.js +43 -0
- package/dist-server/headless-entry.test.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The scene runtime for board-service's own headless views (`views/internal-label-command-view.html`,
|
|
3
|
+
* `views/internal-board-service-view.html`), served as `/headless-scene-components.js`.
|
|
4
|
+
*
|
|
5
|
+
* It came only from board-ui's entries. An app that left board-ui (plant, 2026-09-19) built no such file, so
|
|
6
|
+
* the label page loaded a 404 and stood blank: labels could not be drawn (seen on :4000, 2026-09-24). The
|
|
7
|
+
* views are board-service's, so the script they load is too.
|
|
8
|
+
*
|
|
9
|
+
* board-ui keeps the same entry for its players, which import it by relative path. The builder takes one file
|
|
10
|
+
* per entry name, so an app with both builds one; test/headless-entry.test.ts keeps the two copies the same.
|
|
11
|
+
*/
|
|
12
|
+
import 'core-js/stable'
|
|
13
|
+
import 'regenerator-runtime/runtime'
|
|
14
|
+
import * as _sceneModule from '@hatiolab/things-scene'
|
|
15
|
+
|
|
16
|
+
// webpack 모듈 네임스페이스를 plain object로 변환하여 window.scene에 노출
|
|
17
|
+
window.scene = { ..._sceneModule }
|
|
18
|
+
|
|
19
|
+
import 'things-scene-components'
|
package/client/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* board-service has no screens of its own. This file exists so the package can name a browser side
|
|
3
|
+
* (`browser` in package.json): the builder collects every module's `entries/` from beside that path, and
|
|
4
|
+
* board-service's headless views need one of its own — see `entries/headless-scene-components.js`.
|
|
5
|
+
*/
|
|
6
|
+
export {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* board-service's headless views load a script board-service itself provides.
|
|
5
|
+
*
|
|
6
|
+
* `/headless-scene-components.js` came only from board-ui's entries, so an app without board-ui (plant) served a 404
|
|
7
|
+
* and the label page stood blank (2026-09-24). The builder collects `entries/` from beside each module's `browser`
|
|
8
|
+
* path (builder/controller/entries-builder.js), so that is what these tests follow.
|
|
9
|
+
*/
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const path_1 = require("path");
|
|
12
|
+
const root = (0, path_1.join)(__dirname, '..');
|
|
13
|
+
const pkg = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(root, 'package.json'), 'utf8'));
|
|
14
|
+
/* Where the builder looks: `entries/` beside the browser entry. */
|
|
15
|
+
const entries = (0, path_1.join)((0, path_1.dirname)((0, path_1.join)(root, pkg.browser ?? '')), 'entries');
|
|
16
|
+
const scriptsOf = (view) => [...(0, fs_1.readFileSync)((0, path_1.join)(root, 'views', view), 'utf8').matchAll(/<script src="\/([\w-]+)\.js"><\/script>/g)].map(m => m[1]);
|
|
17
|
+
const code = (text) => text
|
|
18
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
19
|
+
.split('\n')
|
|
20
|
+
.map(line => line.trim())
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.join('\n');
|
|
23
|
+
describe('the headless views load scripts board-service builds', () => {
|
|
24
|
+
test('board-service names a browser side, so the builder collects its entries', () => {
|
|
25
|
+
expect(pkg.browser).toBeTruthy();
|
|
26
|
+
expect((0, fs_1.existsSync)(entries)).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
test.each(['internal-label-command-view.html', 'internal-board-service-view.html'])('%s — every local script is an entry here', view => {
|
|
29
|
+
const scripts = scriptsOf(view);
|
|
30
|
+
expect(scripts).toContain('headless-scene-components');
|
|
31
|
+
for (const name of scripts)
|
|
32
|
+
expect((0, fs_1.existsSync)((0, path_1.join)(entries, `${name}.js`))).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
test('the entry imports what board-service declares', () => {
|
|
35
|
+
expect(pkg.dependencies['@hatiolab/things-scene']).toBeTruthy();
|
|
36
|
+
});
|
|
37
|
+
test('the same entry in board-ui is the same code — one name, one file wins, so the two must not drift', () => {
|
|
38
|
+
const own = (0, fs_1.readFileSync)((0, path_1.join)(entries, 'headless-scene-components.js'), 'utf8');
|
|
39
|
+
const boardUi = (0, fs_1.readFileSync)((0, path_1.join)(root, '..', 'board-ui', 'client', 'entries', 'headless-scene-components.js'), 'utf8');
|
|
40
|
+
expect(code(own)).toBe(code(boardUi));
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=headless-entry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headless-entry.test.js","sourceRoot":"","sources":["../server/headless-entry.test.ts"],"names":[],"mappings":";;AAAA;;;;;;GAMG;AACH,2BAA6C;AAC7C,+BAA8C;AAE9C,MAAM,IAAI,GAAG,IAAA,WAAI,EAAC,SAAS,EAAE,IAAI,CAAC,CAAA;AAClC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;AACxE,mEAAmE;AACnE,MAAM,OAAO,GAAG,IAAA,WAAI,EAAC,IAAA,cAAO,EAAC,IAAA,WAAI,EAAC,IAAI,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;AAEvE,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAE,CACjC,CAAC,GAAG,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,0CAA0C,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAE1H,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAC5B,IAAI;KACD,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;KAChC,KAAK,CAAC,IAAI,CAAC;KACX,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;KACxB,MAAM,CAAC,OAAO,CAAC;KACf,IAAI,CAAC,IAAI,CAAC,CAAA;AAEf,QAAQ,CAAC,sDAAsD,EAAE,GAAG,EAAE;IACpE,IAAI,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACnF,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,CAAA;QAChC,MAAM,CAAC,IAAA,eAAU,EAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,IAAI,CAAC,CAAC,kCAAkC,EAAE,kCAAkC,CAAC,CAAC,CAAC,0CAA0C,EAAE,IAAI,CAAC,EAAE;QACrI,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;QAC/B,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAA;QACtD,KAAK,MAAM,IAAI,IAAI,OAAO;YAAE,MAAM,CAAC,IAAA,eAAU,EAAC,IAAA,WAAI,EAAC,OAAO,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxF,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,wBAAwB,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;IACjE,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,kGAAkG,EAAE,GAAG,EAAE;QAC5G,MAAM,GAAG,GAAG,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,OAAO,EAAE,8BAA8B,CAAC,EAAE,MAAM,CAAC,CAAA;QAC/E,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,IAAA,WAAI,EAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,8BAA8B,CAAC,EAAE,MAAM,CAAC,CAAA;QACvH,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["/**\n * board-service's headless views load a script board-service itself provides.\n *\n * `/headless-scene-components.js` came only from board-ui's entries, so an app without board-ui (plant) served a 404\n * and the label page stood blank (2026-09-24). The builder collects `entries/` from beside each module's `browser`\n * path (builder/controller/entries-builder.js), so that is what these tests follow.\n */\nimport { existsSync, readFileSync } from 'fs'\nimport { basename, dirname, join } from 'path'\n\nconst root = join(__dirname, '..')\nconst pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))\n/* Where the builder looks: `entries/` beside the browser entry. */\nconst entries = join(dirname(join(root, pkg.browser ?? '')), 'entries')\n\nconst scriptsOf = (view: string) =>\n [...readFileSync(join(root, 'views', view), 'utf8').matchAll(/<script src=\"\\/([\\w-]+)\\.js\"><\\/script>/g)].map(m => m[1])\n\nconst code = (text: string) =>\n text\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .split('\\n')\n .map(line => line.trim())\n .filter(Boolean)\n .join('\\n')\n\ndescribe('the headless views load scripts board-service builds', () => {\n test('board-service names a browser side, so the builder collects its entries', () => {\n expect(pkg.browser).toBeTruthy()\n expect(existsSync(entries)).toBe(true)\n })\n\n test.each(['internal-label-command-view.html', 'internal-board-service-view.html'])('%s — every local script is an entry here', view => {\n const scripts = scriptsOf(view)\n expect(scripts).toContain('headless-scene-components')\n for (const name of scripts) expect(existsSync(join(entries, `${name}.js`))).toBe(true)\n })\n\n test('the entry imports what board-service declares', () => {\n expect(pkg.dependencies['@hatiolab/things-scene']).toBeTruthy()\n })\n\n test('the same entry in board-ui is the same code — one name, one file wins, so the two must not drift', () => {\n const own = readFileSync(join(entries, 'headless-scene-components.js'), 'utf8')\n const boardUi = readFileSync(join(root, '..', 'board-ui', 'client', 'entries', 'headless-scene-components.js'), 'utf8')\n expect(code(own)).toBe(code(boardUi))\n })\n})\n"]}
|