mikser-io-layouts 3.1.0 → 11.1.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/.github/workflows/publish.yml +73 -0
- package/index.js +41 -3
- package/package.json +4 -3
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Publish to npm without a stored token.
|
|
2
|
+
#
|
|
3
|
+
# npm is retiring tokens that skip the second factor — its own token page says
|
|
4
|
+
# "Publish new versions directly (deprecated — ends January 2027)". This is the
|
|
5
|
+
# replacement: the job proves who it is at publish time with a short-lived
|
|
6
|
+
# credential GitHub issues and npm verifies, so npm trusts "the publish.yml
|
|
7
|
+
# workflow in this repository" rather than a string.
|
|
8
|
+
#
|
|
9
|
+
# There is no NODE_AUTH_TOKEN and no secret to configure. Nothing to leak,
|
|
10
|
+
# expire or rotate — the two ways publishing broke in September 2026.
|
|
11
|
+
#
|
|
12
|
+
# Link it once on npm: the package → Settings → Trusted Publisher → GitHub
|
|
13
|
+
# Actions, naming this repository and this filename. Until that exists the
|
|
14
|
+
# publish step fails rather than falling back to something weaker.
|
|
15
|
+
|
|
16
|
+
name: Publish
|
|
17
|
+
|
|
18
|
+
on:
|
|
19
|
+
push:
|
|
20
|
+
tags: ['v*']
|
|
21
|
+
workflow_dispatch:
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
publish:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
permissions:
|
|
27
|
+
contents: read
|
|
28
|
+
# The whole mechanism. Without it npm has nothing to verify.
|
|
29
|
+
id-token: write
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v4
|
|
32
|
+
|
|
33
|
+
- uses: actions/setup-node@v4
|
|
34
|
+
with:
|
|
35
|
+
node-version: '24'
|
|
36
|
+
registry-url: 'https://registry.npmjs.org'
|
|
37
|
+
|
|
38
|
+
# Trusted publishing landed in npm 11.5.1.
|
|
39
|
+
- name: Use an npm that can do trusted publishing
|
|
40
|
+
run: npm install -g npm@latest
|
|
41
|
+
|
|
42
|
+
# `npm install`, not `npm ci`: these packages are developed in a
|
|
43
|
+
# workspace, so dependencies hoist to its root and each package's own
|
|
44
|
+
# lockfile is never read locally. They drift silently, and CI is the only
|
|
45
|
+
# thing that would ever read them.
|
|
46
|
+
- run: npm install --no-audit --no-fund
|
|
47
|
+
env:
|
|
48
|
+
# puppeteer downloads a browser on install; nothing in the release
|
|
49
|
+
# path renders a page.
|
|
50
|
+
PUPPETEER_SKIP_DOWNLOAD: '1'
|
|
51
|
+
|
|
52
|
+
# The tag is the release. A tag that disagrees with package.json would
|
|
53
|
+
# publish a version nobody asked for.
|
|
54
|
+
- name: Tag must match package.json
|
|
55
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
56
|
+
run: |
|
|
57
|
+
TAG="${GITHUB_REF_NAME#v}"
|
|
58
|
+
PKG="$(node -p 'require("./package.json").version')"
|
|
59
|
+
if [ "$TAG" != "$PKG" ]; then
|
|
60
|
+
echo "tag v$TAG does not match package.json $PKG"
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
echo "publishing $PKG"
|
|
64
|
+
|
|
65
|
+
# The suite runs here now. It did not before: these packages declared
|
|
66
|
+
# mikser-io only as a peerDependency (npm does not install a package's
|
|
67
|
+
# own peers) or as file:../mikser-io (a path that exists on a laptop and
|
|
68
|
+
# nowhere else), so a standalone clone could not resolve the engine it
|
|
69
|
+
# tests against. Both are now real devDependencies with version ranges,
|
|
70
|
+
# which npm still satisfies from the workspace locally.
|
|
71
|
+
- run: npm test
|
|
72
|
+
|
|
73
|
+
- run: npm publish --access public
|
package/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import _ from 'lodash'
|
|
|
19
19
|
import {
|
|
20
20
|
gateChecksum, sweepDeleted, scanSummary,
|
|
21
21
|
checksumsByCollection,
|
|
22
|
-
checksum as fileChecksum, checksumOf,
|
|
22
|
+
checksum as fileChecksum, checksumOf, registerSourceChecksum,
|
|
23
23
|
useDatabase,
|
|
24
24
|
writeOutput, reportUnchanged,
|
|
25
25
|
provideService,
|
|
@@ -283,13 +283,27 @@ export function layouts(userOptions = {}) {
|
|
|
283
283
|
// non-entity, which is why it is a rule and not a guess.
|
|
284
284
|
const isSidecarScript = (rel) => path.extname(rel.replace(/\.js$/, '')) === ''
|
|
285
285
|
|
|
286
|
+
// The folder, resolved the same way the onLoaded below resolves it.
|
|
287
|
+
//
|
|
288
|
+
// That onLoaded is where `runtime.options.layoutsFolder` gets set, and
|
|
289
|
+
// a report-only command — mikser_explain, --audit-output — runs in an
|
|
290
|
+
// onLoaded too. Which of the two runs first is plugin order, so a
|
|
291
|
+
// recompute that read the option directly worked or threw depending on
|
|
292
|
+
// it. Derived here instead, so the answer does not depend on the
|
|
293
|
+
// question's timing.
|
|
294
|
+
function layoutsFolderNow() {
|
|
295
|
+
if (runtime.options.layoutsFolder) return runtime.options.layoutsFolder
|
|
296
|
+
const name = runtime.options.layouts ?? options.layoutsFolder ?? collection
|
|
297
|
+
return path.isAbsolute(name) ? name : path.join(runtime.options.workingFolder, name)
|
|
298
|
+
}
|
|
299
|
+
|
|
286
300
|
async function sidecarInputs() {
|
|
287
|
-
const scriptPaths = (await globby('**/*.js', { cwd:
|
|
301
|
+
const scriptPaths = (await globby('**/*.js', { cwd: layoutsFolderNow() }))
|
|
288
302
|
.filter(isSidecarScript)
|
|
289
303
|
const own = new Map()
|
|
290
304
|
const shared = []
|
|
291
305
|
for (const rel of scriptPaths.sort()) {
|
|
292
|
-
const sum = await fileChecksum(path.join(
|
|
306
|
+
const sum = await fileChecksum(path.join(layoutsFolderNow(), rel))
|
|
293
307
|
own.set(rel.replace(/\.js$/, ''), sum)
|
|
294
308
|
shared.push(`${rel}:${sum}`)
|
|
295
309
|
}
|
|
@@ -305,6 +319,29 @@ export function layouts(userOptions = {}) {
|
|
|
305
319
|
return Buffer.from(`${template}:${sidecar}:${inputs.sharedDigest}`, 'utf8')
|
|
306
320
|
}
|
|
307
321
|
|
|
322
|
+
// Tell core how to recompute what it stored.
|
|
323
|
+
//
|
|
324
|
+
// The catalog holds the composed value above, not a file hash, so
|
|
325
|
+
// anything comparing it against a fresh md5 of the template compares
|
|
326
|
+
// two recipes and always finds them different. mikser_explain did
|
|
327
|
+
// exactly that and reported `differs: true` for every layout on every
|
|
328
|
+
// site — a permanent false alarm about files nobody had edited.
|
|
329
|
+
//
|
|
330
|
+
// The recipe belongs here, so the recomputation does too. One
|
|
331
|
+
// function, the same one the gate uses, so the two cannot drift apart.
|
|
332
|
+
registerSourceChecksum(collection, async (entity) => {
|
|
333
|
+
// A sidecar is in this collection but is NOT composed: it is
|
|
334
|
+
// gated on its own bytes above, because it has no template and no
|
|
335
|
+
// sidecar of its own. Answering with a composed value here would
|
|
336
|
+
// report every sidecar as diverged — the same false alarm this
|
|
337
|
+
// registration exists to remove, pointed the other way.
|
|
338
|
+
//
|
|
339
|
+
// null means "nothing composed here, use the file hash", which is
|
|
340
|
+
// exactly right for it.
|
|
341
|
+
if (entity.type === 'sidecar') return null
|
|
342
|
+
return checksumOf(await layoutInputBytes(entity.uri, entity.name, await sidecarInputs()))
|
|
343
|
+
})
|
|
344
|
+
|
|
308
345
|
// Named so onSync can re-run it when a sidecar changes. A function
|
|
309
346
|
// declaration, so it is hoisted above the onSync registration above.
|
|
310
347
|
async function rescanLayouts() {
|
|
@@ -584,6 +621,7 @@ export function layouts(userOptions = {}) {
|
|
|
584
621
|
return {
|
|
585
622
|
collection,
|
|
586
623
|
type,
|
|
624
|
+
module: import.meta.url,
|
|
587
625
|
}
|
|
588
626
|
}
|
|
589
627
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mikser-io-layouts",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.1.0",
|
|
4
4
|
"description": "SSG-flavor task-production policy for mikser-io. Multi-match layout assignment, per-layout destinations, postprocess chain attachment, layout inspection.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"homepage": "https://github.com/almero-digital-marketing/mikser-io-layouts#readme",
|
|
20
20
|
"peerDependencies": {
|
|
21
|
-
"mikser-io": "^
|
|
21
|
+
"mikser-io": "^11.1.0",
|
|
22
22
|
"zod": "^4.0.0"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"lodash": "^4.17.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"mikser-io": "
|
|
30
|
+
"mikser-io": "^11.1.0",
|
|
31
|
+
"mikser-io-render-liquid": "^11.0.1",
|
|
31
32
|
"zod": "^4.0.0"
|
|
32
33
|
}
|
|
33
34
|
}
|