@sjcrh/proteinpaint-front 2.207.1 → 2.208.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/README.md CHANGED
@@ -11,33 +11,30 @@ an embedder.
11
11
 
12
12
  ## Usage
13
13
 
14
- The recommended usage is to include a postinstall script in your project as follows.
15
- ```json
16
- "scripts": {
17
- "postinstall": "proteinpaint-front https://my.host.tld"
18
- }
19
- ```
14
+ This package is used inside a ppfull container (https://github.com/stjude/proteinpaint/pkgs/container/ppfull).
15
+ The container image ensures that a matching proteinpaint-server is used to serve the data as expected by
16
+ proteinpaint-client code. Standalone usage outside of a ppfull container is not recommended. From within
17
+ the container, the command below is used:
20
18
 
21
- You can manually test your project's postinstall lifecyle script by running the following
22
- to extract the Proteinpaint bundles, with the correct public path for the dynamically
23
- loaded Proteinpaint bundles.
24
19
  ```bash
25
20
  npx proteinpaint-front [URL_PUBLIC_PATH]
26
21
  ```
27
22
 
28
- If you omit the URL_PUBLIC_PATH argument above, then it will default to `'.'`, which assumes that the bundle is served by
29
- the same PP server. But note that in this case, the web bundle or server host may NOT be embedded or used as host from
30
- other domains, even if CORS is allowed, since script bundles will not be sourced properly and loaded dynamically.
23
+ See `init.js` for details. If the URL_PUBLIC_PATH argument is omitted above, then it will default to `'.'`,
24
+ which assumes that the bundle is served by the same PP server. But note that in this case, the web bundle or
25
+ server host may NOT be embedded or used as host from other domains, even if CORS is allowed, since script
26
+ bundles will not be sourced properly and loaded dynamically.
31
27
 
32
- Note that you can serve the web bundle using the Proteinpaint server or any web server,
33
- see the example in the Develop section.
34
28
 
35
29
  ## Develop
36
30
 
31
+ The usual dev workflow typically focuses on the client workspace development. For troubleshooting builds
32
+ for production, the following may be performed:
33
+
37
34
  ```bash
38
- # must run the module bundling of proteinpaint-client
39
- cd ../client
40
- npm run rollw
35
+ # must run the module bundling of proteinpaint-client, either from sjpp dev process or below
36
+ cd ../client
37
+ npm run dev
41
38
 
42
39
  # in another terminal
43
40
  cd ../front
package/bundles.tgz CHANGED
Binary file
package/init.js CHANGED
@@ -11,49 +11,98 @@ if (URLPATH.endsWith('/')) URLPATH = URLPATH.slice(0, -1)
11
11
  const publicBinOnly = process.argv.includes('--publicBinOnly')
12
12
 
13
13
  const CWD = process.cwd()
14
+ const PUBLIC_DIR = `${CWD}/public`
15
+ // The client bundle is generated into a PER-CONTAINER dir at CWD/bin — a sibling of public/, in the
16
+ // container's own writable layer, NOT under any mount — and is served at /bin by the server, which
17
+ // routes /bin to CWD/bin when it exists (see the server's serverconfig binDir + app.middlewares.js).
18
+ //
19
+ // It is deliberately NOT written into public/: when several instances bind-mount the SAME public/,
20
+ // regenerating a shared public/bin at startup makes them clobber one another (one instance's recursive
21
+ // rmdir races another's tar extract -> "ENOTEMPTY, Directory not empty: .../public/bin", crashing a
22
+ // startup). Generating per-container removes the shared write entirely, so concurrent starts can't race
23
+ // — no lock or cross-instance key needed. It also makes a rolling deploy safe: init never mutates the
24
+ // shared public/bin, so instances still on an older release keep serving their own public/bin while new
25
+ // instances serve their CWD/bin. An older image that has no CWD/bin also still works — the server falls
26
+ // back to serving /bin from public/bin.
27
+ const BIN_DIR = `${CWD}/bin`
28
+ // A distinctively named marker written LAST, only after the bundle is fully extracted AND its __PP_URL__
29
+ // placeholder is replaced. It serves two purposes:
30
+ // - completion: reuse requires it, so a container that stops mid-generation (after tar creates
31
+ // proteinpaint.js but before the URL rewrite, or on a partial extraction) regenerates on its next
32
+ // start instead of reusing a partial/unpatched bundle forever — which the health gate can't catch,
33
+ // since an unpatched or incomplete proteinpaint.js still returns 200.
34
+ // - ownership: the server publishes CWD/bin at /bin ONLY when this marker is present (see the server's
35
+ // app.middlewares.js), so launching the server package from a consumer project never exposes an
36
+ // unrelated CWD/bin (e.g. that project's own bin/ scripts) over HTTP. The name is distinctive so it
37
+ // won't collide with a consumer's files.
38
+ const BIN_READY = `${BIN_DIR}/.pp-bundle-ready`
14
39
 
15
40
  console.log('CWD', CWD)
16
41
  try {
17
- if (!fs.existsSync(`${CWD}/public`)) {
42
+ if (!fs.existsSync(PUBLIC_DIR)) {
18
43
  console.log(`making a public directory at ${CWD}`)
19
- fs.mkdirSync(`${CWD}/public`)
20
- }
21
- if (fs.existsSync(`${CWD}/public/bin`)) {
22
- console.log(`removing the old public/bin at ${CWD}`)
23
- // should update as part of v16 upgrade
24
- fs.rmdirSync(`${CWD}/public/bin`, { recursive: true, force: true }, () => {})
44
+ fs.mkdirSync(PUBLIC_DIR)
25
45
  }
46
+ // index.html / cards are ensured independently of the bundle below (idempotent, and needed even when
47
+ // the bundle is reused), so a skipped regeneration still leaves the public scaffolding in place.
26
48
  if (!publicBinOnly) {
27
- if (!fs.existsSync(`${CWD}/public/index.html`)) {
49
+ if (!fs.existsSync(`${PUBLIC_DIR}/index.html`)) {
28
50
  console.log(`creating a public/index.html file`)
29
- fs.copyFileSync(path.join(__dirname, './public/index.html'), `${CWD}/public/index.html`)
51
+ fs.copyFileSync(path.join(__dirname, './public/index.html'), `${PUBLIC_DIR}/index.html`)
30
52
  }
31
- if (!fs.existsSync(`${CWD}/public/cards`)) {
53
+ if (!fs.existsSync(`${PUBLIC_DIR}/cards`)) {
32
54
  console.log(`Copying cards into public/cards folder`)
33
- execSync(`cp -r ${CWD}/node_modules/@sjcrh/proteinpaint-front/public/cards ${CWD}/public/cards`, {
55
+ execSync(`cp -r ${CWD}/node_modules/@sjcrh/proteinpaint-front/public/cards ${PUBLIC_DIR}/cards`, {
34
56
  stdio: 'inherit'
35
57
  })
36
58
  }
37
59
  }
38
- const tar = ps.spawnSync('tar', [`-xzf`, `${__dirname}/bundles.tgz`, `-C`, `${CWD}`], { encoding: 'utf8' })
39
- if (tar.status !== 0) {
40
- throw new Error(`Tar command failed with exit code ${tar.status}: ${tar.stderr}`)
41
- }
42
- if (tar.stderr) {
43
- console.warn('Tar command warnings:', tar.stderr)
44
- }
45
- console.log(`Setting the dynamic bundle path to ${URLPATH}`)
46
- const codeFile = `${CWD}/public/bin/proteinpaint.js`
47
- // remember the modified time before setting the bundle public path
48
- const mtime = fs.statSync(codeFile).mtime
49
- const code = fs.readFileSync(codeFile, { encoding: 'utf8' })
50
- const newcode = code.replace(`__PP_URL__`, `${URLPATH}/bin/`)
51
- fs.writeFileSync(codeFile, newcode, { encoding: 'utf8' })
52
- try {
53
- // reset the atime and mtime to the original mtime before setting the bundle publit path
54
- fs.utimesSync(codeFile, mtime, mtime)
55
- } catch (e) {
56
- console.log('--- !!! unable to reset the mtime for the extracted proteinpaint bundle: ', e)
60
+
61
+ // Generate the bundle into CWD/bin only if it isn't already there. CWD/bin is in the container's
62
+ // writable layer, so it persists across restarts of THIS container (reuse) and is empty in any freshly
63
+ // created container (regenerate) — including after an image update, which always yields a new
64
+ // container. Because CWD/bin is per-container, there is no shared directory to race on.
65
+ //
66
+ // NOTE: reuse is keyed on the completion marker (a fully extracted, URL-patched bundle), not on its
67
+ // version or URL. That is correct for the normal container lifecycle (a new image, or a changed URL,
68
+ // arrives with a new container and hence an empty CWD/bin). It would be stale only if the SAME
69
+ // container were reused across a bundle or URL change — e.g. CWD/bin persisted via a mounted volume,
70
+ // or serverconfig.json remounted with a different URL and merely restarted — uncommon, and outside
71
+ // this simple scheme.
72
+ if (fs.existsSync(BIN_READY)) {
73
+ console.log(`bundle already present and complete at ${BIN_DIR}; reusing it`)
74
+ } else {
75
+ if (fs.existsSync(BIN_DIR)) {
76
+ console.log(`removing an incomplete ${BIN_DIR}`)
77
+ fs.rmSync(BIN_DIR, { recursive: true, force: true })
78
+ }
79
+ // bundles.tgz contains public/bin/*; --strip-components=1 drops the leading public/ so the files
80
+ // land in CWD/bin/* (this container's private bin), not in the shared public/.
81
+ const tar = ps.spawnSync('tar', [`-xzf`, `${__dirname}/bundles.tgz`, `-C`, `${CWD}`, `--strip-components=1`], {
82
+ encoding: 'utf8'
83
+ })
84
+ if (tar.status !== 0) {
85
+ throw new Error(`Tar command failed with exit code ${tar.status}: ${tar.stderr}`)
86
+ }
87
+ if (tar.stderr) {
88
+ console.warn('Tar command warnings:', tar.stderr)
89
+ }
90
+ console.log(`Setting the dynamic bundle path to ${URLPATH}`)
91
+ const codeFile = `${BIN_DIR}/proteinpaint.js`
92
+ // remember the modified time before setting the bundle public path
93
+ const mtime = fs.statSync(codeFile).mtime
94
+ const code = fs.readFileSync(codeFile, { encoding: 'utf8' })
95
+ const newcode = code.replace(`__PP_URL__`, `${URLPATH}/bin/`)
96
+ fs.writeFileSync(codeFile, newcode, { encoding: 'utf8' })
97
+ try {
98
+ // reset the atime and mtime to the original mtime before setting the bundle public path
99
+ fs.utimesSync(codeFile, mtime, mtime)
100
+ } catch (e) {
101
+ console.log('--- !!! unable to reset the mtime for the extracted proteinpaint bundle: ', e)
102
+ }
103
+ // mark generation complete LAST (see BIN_READY above): a crash before this leaves no marker, so
104
+ // the next start regenerates rather than reusing a partial or unpatched bundle.
105
+ fs.writeFileSync(BIN_READY, '')
57
106
  }
58
107
  } catch (e) {
59
108
  console.error(e)
package/package.json CHANGED
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-front",
3
- "version": "2.207.1",
3
+ "version": "2.208.0",
4
4
  "browser": "src/app.js",
5
5
  "main": "src/index.js",
6
6
  "bin": "init.js",
7
7
  "scripts": {
8
- "dev": "./dev.sh &",
8
+ "dev": "./dev.sh",
9
9
  "//TODO": "# delete webpack use, once esbuild migration is fully tested and unlikely to be reverted",
10
10
  "client-dist": "if ! -d ../client/dist; then cd ../client; npm pack; fi",
11
- "prepack": "npm run client-dist && rm -rf public/bin && rm -rf *.tgz && webpack && tar -czf bundles.tgz public/bin",
11
+ "prepack": "npm run client-dist && rm -rf public/bin && rm -rf *.tgz && webpack && tar -czf bundles.tgz public/bin && npm pkg set _buildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)",
12
+ "postpack": "npm pkg delete _buildTime",
12
13
  "test:unit": "echo 'TODO: front unit tests'",
13
14
  "test:integration": "echo 'TODO: front integration tests'"
14
15
  },
15
16
  "devDependencies": {
16
- "@sjcrh/proteinpaint-client": "2.207.1",
17
+ "@sjcrh/proteinpaint-client": "2.208.0",
17
18
  "webpack": "^5.76.0",
18
19
  "webpack-cli": "^4.9.2",
19
20
  "webpack-node-externals": "^3.0.0"
@@ -30,5 +31,6 @@
30
31
  "type": "git",
31
32
  "url": "https://github.com/stjude/proteinpaint",
32
33
  "directory": "front"
33
- }
34
+ },
35
+ "_buildTime": "2026-09-13T18:12:02Z"
34
36
  }
package/public/index.html CHANGED
@@ -8,7 +8,7 @@
8
8
  best practice is to use <script defer> or to put script tags before </body> end tag and
9
9
  just before the runproteinpaint() call
10
10
  -->
11
- <script src="/bin/front/proteinpaint.js" charset="utf-8"></script>
11
+ <script src="/bin/proteinpaint.js" charset="utf-8"></script>
12
12
  </head>
13
13
  <body style="margin:0px;width:100%;height:100%">
14
14
 
@@ -18,6 +18,7 @@
18
18
 
19
19
  <script>
20
20
  runproteinpaint({
21
+ //host: 'http://localhost:3000',
21
22
  host: 'https://proteinpaint.stjude.org',
22
23
  holder:document.getElementById('aaa'),
23
24
  parseurl:true,