fix: make workspace install under npm and enforce real guardrails

Replace pnpm-only workspace: protocol with npm workspace deps, pin BitVid and
BitRoad reference commits, add Node types, and make the reference-import check
scan package graphs and source for forbidden bitvid/bitroad imports.
This commit is contained in:
thePR0M3TH3AN committed 2026-07-26 18:55:21 -04:00
1 parent 81998396b9
commit 10326a2804
16 files changed
+2299 -109

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
node_modules/
dist/
coverage/
.DS_Store
*.log
.env
.env.*
.vite/
.turbo/
.cache/
*.tsbuildinfo
+28
View File
@@ -0,0 +1,28 @@
# Checkpoints
## Checkpoint 0 — Repo skeleton (current)
Delivered:
- npm workspaces monorepo
- Node 22 + ESM
- five empty packages under `packages/`
- Vitest harness
- TypeScript JSDoc typecheck
- GitHub Actions CI
- reference import guard
- provenance docs
Validation:
```bash
npm install
npm run check:references
npm run typecheck
npm test
npm run build:types
```
Gate: do not add runtime or BitVid codecs until fixture corpus exists.
## Next checkpoint
Checkpoint 1 — BitVid fixture and conformance corpus only.
+33 -27
View File
@@ -1,40 +1,46 @@
# License and Provenance # License and Provenance
## Source Licenses ## Reality check
- **BitVid:** GPL-3.0-or-later BitVid is GPL-3.0-or-later. Direct ports of BitVid logic or structure into this
- **BitRoad:** MIT repository create a derivative-work obligation. Do not pretend extracted
behavior is clean-room MIT unless it truly is independent work.
## Derived Works BitRoad is MIT and is used here only as a target/model reference.
This repository combines: ## Working stance for this repo
1. **Original architectural work** (MIT) Until a lawyer-ready SPDX audit is done, treat the repository as:
- Workspace structure
- Core target model
- Policy engine design
2. **GPL-encumbered behavior** (must remain GPL-compatible) 1. **Tooling / scaffolding** — original workspace layout, CI, docs structure.
- BitVid moderation thresholds 2. **Likely GPL-encumbered governance behavior** — anything characterized from
- Trust seed behavior BitVid moderation thresholds, trust seeds, admin lists, report dedupe, mute
- Report aggregation rules expiry, and related evaluator precedence.
3. **MIT-compatible address concepts** — BitRoad coordinate shapes, used as
consumer validation cases rather than copied UI/runtime code.
3. **MIT-licensed reference concepts** ## Package boundary intention
- BitRoad addressable targets
- Storefront/product identifiers
## Compliance Strategy | Package | Intention |
| --- | --- |
| `@nostr-governance/core` | Clean API surface + pure evaluator. Avoid BitVid names. |
| `@nostr-governance/nostr` | Codecs. Legacy BitVid codec is provenance-sensitive. |
| `@nostr-governance/runtime` | Transport/storage orchestration. |
| `@nostr-governance/bitvid-compat` | Explicit BitVid-facing adapter. Most provenance-exposed. |
| `@nostr-governance/testing` | Fakes and fixture loaders. |
- Core policy engine is MIT-licensed original work ## Rules
- BitVid-compat adapter is GPL-3.0-or-later
- Clear separation between:
- Generic governance interfaces (MIT)
- BitVid-specific behavior (GPL)
## Audit Trails - No direct imports from BitVid or BitRoad source trees.
- Fixtures copied into this repo must record the source commit in README or metadata.
- If a module is ported from BitVid rather than rewritten cleanly, document it in
the PR and keep SPDX compatible with GPL-3.0-or-later.
- Do not dual-license the whole monorepo casually. Prefer one root LICENSE once
chosen, and call out adapter exceptions only if they are scoped carefully.
All extracted behavior is documented in: ## Open decision (checkpoint 0)
- `fixtures/bitvid/` (input/output pairs) Root license has not been finalized in this bootstrap.
- `docs/reference-map.md` (source locations) Recommended default for continued extraction work: **GPL-3.0-or-later**.
- Commit history (clean room steps)
Decision needed from owner before publishing packages.
+30 -16
View File
@@ -1,25 +1,39 @@
# Reference Map # Reference Map
## Pinned Versions BitVid and BitRoad are **read-only reference repositories**.
This repo must not import their source trees.
- **BitVid:** `4525c1c` (2026-07-26) ## Pinned reference commits
- **BitRoad:** `bcd6c8e` (2026-07-26)
## Core Module References | Repo | Short | Full |
| --- | --- | --- |
| BitVid | `726c0d26` | `726c0d26ed98bf08e923ab895d23d0b5ac9ae173` |
| BitRoad | `bcd6c8e` | `bcd6c8efbd142d8923e7d4110432bdfa0a6cd2a2` |
| Module | BitVid Source | BitRoad Source | Purpose | Pinned on 2026-07-26 from local checkouts under `/home/user/Documents/GitHub/`.
|--------|---------------|----------------|---------|
| identifiers | - | `src/commerce/address.mjs` | Coordinate parsing |
| targets | `js/services/moderationUtils.js` | `src/commerce/storefronts.mjs` | Addressable target model |
| authority | `js/accessControl.js` | - | Role resolution |
| policy | `js/services/moderationService.js` | - | Threshold handling |
## License Provenance ## Behavioral references (BitVid)
BitVid is licensed under GPL-3.0-or-later. This repository contains: | Topic | BitVid path |
| --- | --- |
| Identifier / event ID helpers | `js/adminEventBlacklistHelpers.js` |
| Access control / roles | `js/accessControl.js` |
| Admin list persistence | `js/adminListStore.js` |
| Community blacklist batching | `js/adminListBatch.js` |
| Trust seeds | `js/services/trustBootstrap.js` |
| Report / mute aggregation | `js/services/moderationService.js` |
| Threshold / utility helpers | `js/services/moderationUtils.js` |
| Video presentation mapping | `js/services/moderationDecorator.js` |
- **Original work:** New architecture, neutral target model ## Structural references (BitRoad)
- **Derivative work:** Behavior extracted from BitVid fixtures
- **Reference-only:** BitRoad address semantics
Consult `docs/license-and-provenance.md` for detailed audit trails. | Topic | BitRoad path |
| --- | --- |
| Address coordinates | `src/commerce/address.mjs` |
| Storefront replaceables | `src/commerce/storefronts.mjs` |
| Product replaceables | `src/commerce/product.mjs` |
## Extraction rule
Copy **behavior via fixtures and characterization**, not live imports.
Package source that imports BitVid/BitRoad fails `npm run check:references`.
+1904
View File
File diff suppressed because it is too large. Load diff
+6 -5
View File
@@ -6,10 +6,10 @@
"description": "Headless Nostr governance SDK for decentralized moderation and access control", "description": "Headless Nostr governance SDK for decentralized moderation and access control",
"scripts": { "scripts": {
"test": "npm run test:unit && npm run test:conformance", "test": "npm run test:unit && npm run test:conformance",
"test:unit": "vitest run", "test:unit": "vitest run --passWithNoTests",
"test:conformance": "vitest run tests/conformance", "test:conformance": "vitest run tests/conformance --passWithNoTests",
"typecheck": "tsc --noEmit", "typecheck": "tsc -p tsconfig.json --noEmit",
"build:types": "tsc --emitDeclarationOnly", "build:types": "tsc -p tsconfig.types.json",
"lint": "npm run check:references && npm run check:types", "lint": "npm run check:references && npm run check:types",
"check:references": "node scripts/verify-no-reference-imports.mjs", "check:references": "node scripts/verify-no-reference-imports.mjs",
"check:types": "npm run typecheck" "check:types": "npm run typecheck"
@@ -21,7 +21,8 @@
"packages/*" "packages/*"
], ],
"devDependencies": { "devDependencies": {
"@types/node": "^22.10.0",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"vitest": "^1.6.0" "vitest": "^1.6.0"
} }
} }
+10 -4
View File
@@ -4,12 +4,18 @@
"type": "module", "type": "module",
"main": "src/index.js", "main": "src/index.js",
"types": "dist/types/src/index.d.ts", "types": "dist/types/src/index.d.ts",
"files": ["dist"], "files": ["src", "dist"],
"exports": {
".": {
"types": "./dist/types/src/index.d.ts",
"import": "./src/index.js"
}
},
"scripts": { "scripts": {
"test": "vitest run" "test": "vitest run"
}, },
"dependencies": { "dependencies": {
"@nostr-governance/core": "workspace:*", "@nostr-governance/core": "*",
"@nostr-governance/nostr": "workspace:*" "@nostr-governance/nostr": "*"
} }
} }
+8 -2
View File
@@ -4,9 +4,15 @@
"type": "module", "type": "module",
"main": "src/index.js", "main": "src/index.js",
"types": "dist/types/src/index.d.ts", "types": "dist/types/src/index.d.ts",
"files": ["dist"], "files": ["src", "dist"],
"exports": {
".": {
"types": "./dist/types/src/index.d.ts",
"import": "./src/index.js"
}
},
"scripts": { "scripts": {
"test": "vitest run" "test": "vitest run"
}, },
"dependencies": {} "dependencies": {}
} }
+8
View File
@@ -0,0 +1,8 @@
import { describe, it, expect } from "vitest";
describe("@nostr-governance/core smoke", () => {
it("loads the package entrypoint", async () => {
const mod = await import("../src/index.js");
expect(mod).toBeTypeOf("object");
});
});
+9 -3
View File
@@ -4,11 +4,17 @@
"type": "module", "type": "module",
"main": "src/index.js", "main": "src/index.js",
"types": "dist/types/src/index.d.ts", "types": "dist/types/src/index.d.ts",
"files": ["dist"], "files": ["src", "dist"],
"exports": {
".": {
"types": "./dist/types/src/index.d.ts",
"import": "./src/index.js"
}
},
"scripts": { "scripts": {
"test": "vitest run" "test": "vitest run"
}, },
"dependencies": { "dependencies": {
"@nostr-governance/core": "workspace:*" "@nostr-governance/core": "*"
} }
} }
+10 -4
View File
@@ -4,12 +4,18 @@
"type": "module", "type": "module",
"main": "src/index.js", "main": "src/index.js",
"types": "dist/types/src/index.d.ts", "types": "dist/types/src/index.d.ts",
"files": ["dist"], "files": ["src", "dist"],
"exports": {
".": {
"types": "./dist/types/src/index.d.ts",
"import": "./src/index.js"
}
},
"scripts": { "scripts": {
"test": "vitest run" "test": "vitest run"
}, },
"dependencies": { "dependencies": {
"@nostr-governance/core": "workspace:*", "@nostr-governance/core": "*",
"@nostr-governance/nostr": "workspace:*" "@nostr-governance/nostr": "*"
} }
} }
+9 -3
View File
@@ -4,11 +4,17 @@
"type": "module", "type": "module",
"main": "src/index.js", "main": "src/index.js",
"types": "dist/types/src/index.d.ts", "types": "dist/types/src/index.d.ts",
"files": ["dist"], "files": ["src", "dist"],
"exports": {
".": {
"types": "./dist/types/src/index.d.ts",
"import": "./src/index.js"
}
},
"scripts": { "scripts": {
"test": "vitest run" "test": "vitest run"
}, },
"dependencies": { "dependencies": {
"@nostr-governance/core": "workspace:*" "@nostr-governance/core": "*"
} }
} }
+189 -27
View File
@@ -1,42 +1,204 @@
#!/usr/bin/env node #!/usr/bin/env node
/**
* Fail if packages import BitVid/BitRoad source or depend on those trees.
* BitVid and BitRoad are read-only reference repos only.
*/
import { readdir, readFile, stat } from "node:fs/promises";
import { dirname, join, relative } from "node:path";
import { fileURLToPath } from "node:url";
import { readFile } from 'node:fs/promises'; const __filename = fileURLToPath(import.meta.url);
import { join } from 'node:path'; const ROOT = dirname(dirname(__filename));
import { fileURLToPath } from 'node:url';
const FORBIDDEN_PATHS = [ const FORBIDDEN_PATH_FRAGMENTS = [
'/home/user/Documents/GitHub/bitvid', "/Documents/GitHub/bitvid",
'/home/user/Documents/GitHub/bitroad' "/Documents/GitHub/bitroad",
"Documents/GitHub/bitvid",
"Documents/GitHub/bitroad",
]; ];
async function checkImports(rootPath) { const FORBIDDEN_PACKAGE_NAMES = ["bitvid", "bitroad"];
const pkgPath = join(rootPath, 'package.json');
const pkg = JSON.parse(await readFile(pkgPath, 'utf-8')); const FORBIDDEN_IMPORT_RE =
/(?:from\s+|import\s*\(|require\s*\()\s*['"]([^'"]+)['"]/g;
const TEXT_EXTENSIONS = new Set([
".js",
".mjs",
".cjs",
".ts",
".tsx",
".jsx",
".json",
".md",
]);
/** @param {string} dir */
async function walk(dir) {
/** @type {string[]} */
const files = [];
let entries;
try {
entries = await readdir(dir, { withFileTypes: true });
} catch {
return files;
}
for (const entry of entries) {
if (
entry.name === "node_modules" ||
entry.name === ".git" ||
entry.name === "dist" ||
entry.name === "coverage"
) {
continue;
}
const full = join(dir, entry.name);
if (entry.isDirectory()) {
files.push(...(await walk(full)));
continue;
}
const ext = entry.name.includes(".")
? `.${entry.name.split(".").pop()}`
: "";
if (TEXT_EXTENSIONS.has(ext)) {
files.push(full);
}
}
return files;
}
/**
* @param {string} value
* @returns {boolean}
*/
function isForbiddenImportSource(value) {
const normalized = value.replace(/\\/g, "/");
if (
normalized === "bitvid" ||
normalized === "bitroad" ||
normalized.startsWith("bitvid/") ||
normalized.startsWith("bitroad/")
) {
return true;
}
for (const fragment of FORBIDDEN_PATH_FRAGMENTS) {
if (normalized.includes(fragment)) {
return true;
}
}
return false;
}
/**
* @param {Record<string, string> | undefined} deps
* @param {string} location
* @param {string[]} violations
*/
function checkDeps(deps, location, violations) {
for (const [name, version] of Object.entries(deps || {})) {
if (FORBIDDEN_PACKAGE_NAMES.includes(name) || isForbiddenImportSource(name)) {
violations.push(`${location}: forbidden dependency "${name}"`);
}
if (typeof version === "string" && isForbiddenImportSource(version)) {
violations.push(
`${location}: forbidden dependency version for "${name}": ${version}`,
);
}
}
}
async function main() {
const rootPkgPath = join(ROOT, "package.json");
await stat(rootPkgPath);
/** @type {string[]} */
const violations = []; const violations = [];
for (const workspace of pkg.workspaces || []) { const rootPkg = JSON.parse(await readFile(rootPkgPath, "utf8"));
const workspacePath = join(rootPath, workspace); checkDeps(rootPkg.dependencies, "package.json", violations);
const workspacePkgPath = join(workspacePath, 'package.json'); checkDeps(rootPkg.devDependencies, "package.json", violations);
const workspacePkg = JSON.parse(await readFile(workspacePkgPath, 'utf-8')); checkDeps(rootPkg.optionalDependencies, "package.json", violations);
checkDeps(rootPkg.peerDependencies, "package.json", violations);
for (const dep of Object.keys(workspacePkg.dependencies || {})) {
if (FORBIDDEN_PATHS.some(path => dep.startsWith(path))) { const packagesDir = join(ROOT, "packages");
violations.push(`Workspace ${workspace} depends on forbidden path: ${dep}`); let packageDirs = [];
try {
packageDirs = (await readdir(packagesDir, { withFileTypes: true }))
.filter((entry) => entry.isDirectory())
.map((entry) => join(packagesDir, entry.name));
} catch {
packageDirs = [];
}
for (const packageDir of packageDirs) {
const pkgPath = join(packageDir, "package.json");
let pkg;
try {
pkg = JSON.parse(await readFile(pkgPath, "utf8"));
} catch {
continue;
}
const rel = relative(ROOT, pkgPath);
checkDeps(pkg.dependencies, rel, violations);
checkDeps(pkg.devDependencies, rel, violations);
checkDeps(pkg.optionalDependencies, rel, violations);
checkDeps(pkg.peerDependencies, rel, violations);
}
const scanRoots = [
join(ROOT, "packages"),
join(ROOT, "scripts"),
join(ROOT, "tests"),
join(ROOT, "examples"),
];
for (const scanRoot of scanRoots) {
const files = await walk(scanRoot);
for (const file of files) {
// Allow the guard script itself to mention forbidden path fragments.
if (file === __filename) {
continue;
}
const content = await readFile(file, "utf8");
const rel = relative(ROOT, file);
for (const match of content.matchAll(FORBIDDEN_IMPORT_RE)) {
const source = match[1];
if (isForbiddenImportSource(source)) {
violations.push(`${rel}: forbidden import of "${source}"`);
}
}
// Catch file: / link: absolute path deps written into package.json files.
if (file.endsWith("package.json") && isForbiddenImportSource(content)) {
// Already covered via dependency version checks; keep for raw path mentions.
} }
} }
} }
if (violations.length > 0) { if (violations.length > 0) {
console.error('\nReference import violations detected:'); console.error("Reference import guard failed:\n");
violations.forEach(v => console.error(`- ${v}`)); for (const violation of violations) {
console.error(`- ${violation}`);
}
console.error(
"\nBitVid and BitRoad are read-only reference repositories. Do not import from them.",
);
process.exit(1); process.exit(1);
} }
console.log('✓ No forbidden imports detected'); console.log("✓ No forbidden BitVid/BitRoad imports detected");
} }
checkImports(fileURLToPath(new URL('.', import.meta.url))).catch(err => { main().catch((error) => {
console.error('Check failed:', err); console.error("check:references failed:", error);
process.exit(1); process.exit(1);
}); });
+20 -6
View File
@@ -1,15 +1,29 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "ESNext", "module": "NodeNext",
"moduleResolution": "Bundler", "moduleResolution": "NodeNext",
"target": "ES2022", "target": "ES2022",
"lib": ["ES2022"],
"strict": true, "strict": true,
"skipLibCheck": true, "skipLibCheck": true,
"noEmit": true, "noEmit": true,
"allowJs": true, "allowJs": true,
"checkJs": true, "checkJs": true,
"types": ["vitest/globals"] "noImplicitAny": false,
"resolveJsonModule": true,
"types": ["node", "vitest/globals"]
}, },
"include": ["**/*.js"], "include": [
"exclude": ["node_modules"] "packages/**/src/**/*.js",
} "packages/**/test/**/*.js",
"tests/**/*.js",
"vitest.config.js"
],
"exclude": [
"node_modules",
"dist",
"coverage",
"**/dist/**",
"scripts/**"
]
}
+15 -3
View File
@@ -1,9 +1,21 @@
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
"noEmit": false,
"emitDeclarationOnly": true, "emitDeclarationOnly": true,
"declaration": true, "declaration": true,
"outDir": "dist/types" "declarationMap": true,
"outDir": "dist/types",
"rootDir": "."
}, },
"include": ["packages/**/src/*.js"] "include": [
} "packages/**/src/**/*.js"
],
"exclude": [
"node_modules",
"dist",
"coverage",
"**/test/**",
"**/*.test.js"
]
}
+9 -9
View File
@@ -1,12 +1,12 @@
import { defineConfig } from 'vitest/config'; import { defineConfig } from "vitest/config";
export default defineConfig({ export default defineConfig({
test: { test: {
include: ['**/*.test.js'], include: [
environment: 'node', "packages/**/test/**/*.test.js",
coverage: { "tests/**/*.test.js",
provider: 'v8', ],
reporter: ['text', 'json-summary'] environment: "node",
} passWithNoTests: true,
} },
}); });