diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 7278246..5d52763 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -29,6 +29,7 @@ jobs: cache: npm - run: npm ci + - run: npm run build:publisher - run: npm run build - name: Assemble site diff --git a/package-lock.json b/package-lock.json index a628e3e..91736c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "@devslab/numkey", - "version": "0.4.2", + "version": "0.6.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devslab/numkey", - "version": "0.4.2", + "version": "0.6.1", "license": "MIT", "devDependencies": { + "@devslab/site-kit": "0.8.0", "@types/react": "^19.0.0", "jsdom": "^26.1.0", "solid-js": "^1.9.14", @@ -19,12 +20,16 @@ }, "peerDependencies": { "react": ">=18", + "solid-js": "^1.6.0", "vue": "^3.3.0" }, "peerDependenciesMeta": { "react": { "optional": true }, + "solid-js": { + "optional": true + }, "vue": { "optional": true } @@ -209,6 +214,65 @@ "node": ">=18" } }, + "node_modules/@devslab/dds-css": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@devslab/dds-css/-/dds-css-0.8.0.tgz", + "integrity": "sha512-PxibTv92uMzU3rKtOesFUOSR5x3RWp3JHoO9LBidlqwFOjg37+Wd/Y7prLA8mw7USJ1FnF/R5Q4xHDJHk3iCAQ==", + "dev": true, + "license": "SEE LICENSE IN LICENSE" + }, + "node_modules/@devslab/dds-icons": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@devslab/dds-icons/-/dds-icons-0.8.0.tgz", + "integrity": "sha512-kspidNuH1A1E9euuVYlsw5D+vLsPZf01+lGShyB186ru7UEsLkz3epdNH9ry+OPx4lloGYzigyyqq1jwBK8Ofg==", + "dev": true, + "license": "SEE LICENSE IN LICENSE" + }, + "node_modules/@devslab/dds-solid": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@devslab/dds-solid/-/dds-solid-0.8.0.tgz", + "integrity": "sha512-Q05I3QeiaIJga1ixgw+usw3U9Oc4V8tps8mv/Jylu1B0uip4IiAILIM2sePaeJe/ciGfRTxJRsAtprqfyk9I/w==", + "dev": true, + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@devslab/dds-css": "0.8.0", + "@devslab/dds-icons": "0.8.0", + "@devslab/dds-tokens": "0.8.0" + }, + "peerDependencies": { + "solid-js": "1.9.15" + } + }, + "node_modules/@devslab/dds-tokens": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@devslab/dds-tokens/-/dds-tokens-0.8.0.tgz", + "integrity": "sha512-lI/K50/jbKFWjlnTIBce23xry7JbJ1Io461VwUjpLvTAxTrZ5vee9ybosSMSTIs/BDWQidt6V80ghZxsGjX5yg==", + "dev": true, + "license": "SEE LICENSE IN LICENSE" + }, + "node_modules/@devslab/site-kit": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@devslab/site-kit/-/site-kit-0.8.0.tgz", + "integrity": "sha512-m2J6/GH7zid3db+BhoN/2GGUg4tlOsDamXBLFjJg+r8JqDgUv5QyocM5tPgqhW6G/jwKIxS0cZo8RcJJAvU7gQ==", + "dev": true, + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@devslab/dds-solid": "0.8.0" + }, + "peerDependencies": { + "@tanstack/solid-router": "1.170.30", + "@tanstack/solid-start": "1.168.47", + "solid-js": "1.9.15" + }, + "peerDependenciesMeta": { + "@tanstack/solid-router": { + "optional": true + }, + "@tanstack/solid-start": { + "optional": true + } + } + }, "node_modules/@emnapi/core": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", @@ -2796,9 +2860,9 @@ "license": "ISC" }, "node_modules/solid-js": { - "version": "1.9.14", - "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.14.tgz", - "integrity": "sha512-sAEXC0Kk0S1EDg+8ysEWJDbYhA3RRoEjwuySUGlKIemeo0I5YZfOyumNjNs9Sv3y2nmhD+0rW66ag2HsMuQiGQ==", + "version": "1.9.15", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.9.15.tgz", + "integrity": "sha512-EeiY2xfpZJqPLjXspVEKjAII4yv8NyG//NxZ3IpOFHdUNnnTyL0uJOeS9LWGvA7cFCz5y94cjFwYlmw5Luncsg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 3a2774c..4bb191d 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,10 @@ "typecheck": "tsc --noEmit", "test": "vitest run", "test:watch": "vitest", - "verify": "npm run check:brand && npm run typecheck && npm run test && npm run build", - "prepublishOnly": "npm run verify" + "verify": "npm run check:publisher && npm run check:brand && npm run typecheck && npm run test && npm run build", + "prepublishOnly": "npm run verify", + "build:publisher": "node scripts/build-publisher.mjs", + "check:publisher": "node scripts/build-publisher.mjs --check" }, "peerDependencies": { "react": ">=18", @@ -68,6 +70,7 @@ } }, "devDependencies": { + "@devslab/site-kit": "0.8.0", "@types/react": "^19.0.0", "jsdom": "^26.1.0", "solid-js": "^1.9.14", diff --git a/scripts/build-publisher.mjs b/scripts/build-publisher.mjs new file mode 100644 index 0000000..535b55a --- /dev/null +++ b/scripts/build-publisher.mjs @@ -0,0 +1,28 @@ +import { readFile, writeFile } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; +import { renderPublisherHtml } from '@devslab/site-kit'; +import { DEVSLAB_PUBLISHER } from '@devslab/site-kit/devslab'; + +// The checked-in HTML remains crawlable without JavaScript or a package registry. +const pages = ["site/index.html"]; +const root = new URL('../', import.meta.url); +const start = ''; +const end = ''; +const template = start + renderPublisherHtml(DEVSLAB_PUBLISHER) + end; +for (const page of pages) { + const target = new URL(page, root); + const source = await readFile(target, 'utf8'); + const rendered = template.replace(/\r?\n/g, source.includes('\r\n') ? '\r\n' : '\n'); + const from = source.indexOf(start); + const through = source.indexOf(end); + if (from < 0 || through < from || source.indexOf(start, from + start.length) !== -1) { + throw new Error('Expected one publisher marker pair in ' + page); + } + const result = source.slice(0, from) + rendered + source.slice(through + end.length); + if (process.argv.includes('--check')) { + if (result !== source) throw new Error('Stale publisher in ' + page + '; run build:publisher'); + } else if (result !== source) { + await writeFile(target, result); + } + console.log('Publisher verified: ' + fileURLToPath(target)); +} diff --git a/scripts/check-brand-assets.mjs b/scripts/check-brand-assets.mjs index ee493a1..8bb829e 100644 --- a/scripts/check-brand-assets.mjs +++ b/scripts/check-brand-assets.mjs @@ -64,7 +64,7 @@ assert.ok(darkGlow > lightGlow, 'dark atmosphere override must follow the light assert.match(site.slice(darkGlow), /rgb\(6 182 212 \/ \.10\)/, 'dark atmosphere must cap cyan opacity at .10') const pkg = JSON.parse(await read('package.json')) -assert.equal(pkg.scripts.verify, 'npm run check:brand && npm run typecheck && npm run test && npm run build', 'routine verification must include the brand check') +assert.equal(pkg.scripts.verify, 'npm run check:publisher && npm run check:brand && npm run typecheck && npm run test && npm run build', 'routine verification must include publisher and brand checks') assert.equal(pkg.scripts.prepublishOnly, 'npm run verify', 'publishing must use routine verification') for (const workflow of ['.github/workflows/ci.yml', '.github/workflows/publish.yml']) { assert.match(await read(workflow), /npm run verify/, `${workflow} must use the routine verification gate`) diff --git a/site/index.html b/site/index.html index 71a5827..3de20e0 100644 --- a/site/index.html +++ b/site/index.html @@ -201,7 +201,8 @@

No build step / JSP·PHP·정적 페이지 — 스크립트