feat: npm package @crudy/pgmorbac ships the extension SQL
The package carries the install and upgrade scripts, built from src/ on prepack (sql/ is not committed), with extensionSql(), upgradeScripts(), version and sqlDir.
This commit is contained in:
@@ -20,3 +20,6 @@ Thumbs.db
|
||||
node_modules/
|
||||
dist/
|
||||
package-lock.json
|
||||
|
||||
# npm package build output (scripts/build-package-sql.mjs)
|
||||
/sql/
|
||||
|
||||
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## [1.0.0] - 2026-07-25
|
||||
|
||||
### Added
|
||||
- npm package `@crudy/pgmorbac`: the install and upgrade scripts with `extensionSql()`, `upgradeScripts()`, `version` and `sqlDir`
|
||||
- First stable release of the Multi-OrBAC PostgreSQL extension
|
||||
- Complete Multi-OrBAC implementation based on CNRS research paper
|
||||
- Core features:
|
||||
|
||||
@@ -77,6 +77,24 @@ sudo cp pgmorbac--1.0.0.sql $(pg_config --sharedir)/extension/
|
||||
psql -d mydb -c "CREATE EXTENSION pgmorbac;"
|
||||
```
|
||||
|
||||
### From Node.js (npm)
|
||||
|
||||
`@crudy/pgmorbac` ships the same install and upgrade scripts for projects that
|
||||
apply SQL through a migration runner instead of `CREATE EXTENSION`:
|
||||
|
||||
```bash
|
||||
npm install @crudy/pgmorbac
|
||||
```
|
||||
|
||||
```js
|
||||
import { extensionSql, upgradeScripts, version, sqlDir } from '@crudy/pgmorbac';
|
||||
|
||||
await client.query(extensionSql()); // pgmorbac--<version>.sql
|
||||
for (const u of upgradeScripts()) { // pgmorbac--<from>--<to>.sql, in order
|
||||
await client.query(u.sql);
|
||||
}
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```sql
|
||||
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
/** Absolute path to pgmorbac.control. */
|
||||
export declare const controlFile: string;
|
||||
/** Absolute path to the directory holding the install and upgrade scripts. */
|
||||
export declare const sqlDir: string;
|
||||
/** The extension version (default_version in pgmorbac.control). */
|
||||
export declare const version: string;
|
||||
/** The install script pgmorbac--<version>.sql, as CREATE EXTENSION would run it. */
|
||||
export declare function extensionSql(): string;
|
||||
export interface UpgradeScript {
|
||||
from: string;
|
||||
to: string;
|
||||
filename: string;
|
||||
sql: string;
|
||||
}
|
||||
/** Upgrade scripts pgmorbac--<from>--<to>.sql, in version order. */
|
||||
export declare function upgradeScripts(): UpgradeScript[];
|
||||
@@ -0,0 +1,32 @@
|
||||
import { readFileSync, readdirSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
|
||||
const root = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
export const controlFile = join(root, 'pgmorbac.control');
|
||||
export const sqlDir = join(root, 'sql');
|
||||
|
||||
const control = readFileSync(controlFile, 'utf8').match(/default_version\s*=\s*'([^']+)'/);
|
||||
if (!control) throw new Error('[pgmorbac] pgmorbac.control has no default_version');
|
||||
export const version = control[1];
|
||||
|
||||
/** The install script pgmorbac--<version>.sql, as CREATE EXTENSION would run it. */
|
||||
export function extensionSql() {
|
||||
return readFileSync(join(sqlDir, `pgmorbac--${version}.sql`), 'utf8');
|
||||
}
|
||||
|
||||
const semver = (v) => v.split('.').map(Number);
|
||||
const byFrom = (a, b) => {
|
||||
const [x, y] = [semver(a.from), semver(b.from)];
|
||||
return x[0] - y[0] || x[1] - y[1] || x[2] - y[2];
|
||||
};
|
||||
|
||||
/** Upgrade scripts pgmorbac--<from>--<to>.sql, in version order. */
|
||||
export function upgradeScripts() {
|
||||
return readdirSync(sqlDir)
|
||||
.map((filename) => ({ filename, m: /^pgmorbac--(\d+\.\d+\.\d+)--(\d+\.\d+\.\d+)\.sql$/.exec(filename) }))
|
||||
.filter(({ m }) => m)
|
||||
.map(({ filename, m }) => ({ from: m[1], to: m[2], filename, sql: readFileSync(join(sqlDir, filename), 'utf8') }))
|
||||
.sort(byFrom);
|
||||
}
|
||||
+48
-3
@@ -1,13 +1,58 @@
|
||||
{
|
||||
"name": "pgmorbac-release-tools",
|
||||
"name": "@crudy/pgmorbac",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Release tooling for the pgmorbac PostgreSQL extension (build + sign + publish the PGXN distribution).",
|
||||
"description": "Multi-OrBAC for PostgreSQL: the pgmorbac extension SQL, packaged for Node.js projects and migration runners",
|
||||
"keywords": [
|
||||
"pgmorbac",
|
||||
"morbac",
|
||||
"orbac",
|
||||
"rbac",
|
||||
"authorization",
|
||||
"access-control",
|
||||
"postgresql",
|
||||
"postgresql-extension",
|
||||
"row-level-security",
|
||||
"multi-tenant"
|
||||
],
|
||||
"author": "Marc Villain",
|
||||
"license": "MIT",
|
||||
"homepage": "https://pgmorbac.crudy.fr",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/crudylabs/pgmorbac.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/crudylabs/pgmorbac/issues"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
}
|
||||
},
|
||||
"main": "./index.js",
|
||||
"types": "./index.d.ts",
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"sql",
|
||||
"pgmorbac.control",
|
||||
"README.md",
|
||||
"CHANGELOG.md",
|
||||
"LICENSE"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"scripts": {
|
||||
"prepack": "node scripts/build-package-sql.mjs",
|
||||
"dist": "node scripts/build-dist.mjs",
|
||||
"release": "node scripts/build-dist.mjs && node scripts/gitea-release.mjs"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jose": "^5"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env node
|
||||
// Builds sql/ for the npm package: the install script from src/ (tools/build.sh)
|
||||
// plus any upgrade scripts. Runs on prepack; sql/ is never committed.
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const control = readFileSync(join(root, 'pgmorbac.control'), 'utf8').match(/default_version\s*=\s*'([^']+)'/);
|
||||
if (!control) throw new Error('pgmorbac.control has no default_version');
|
||||
const version = control[1];
|
||||
const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
|
||||
if (pkg.version !== version) throw new Error(`package.json ${pkg.version} != pgmorbac.control ${version}`);
|
||||
|
||||
const sqlDir = join(root, 'sql');
|
||||
rmSync(sqlDir, { recursive: true, force: true });
|
||||
mkdirSync(sqlDir);
|
||||
execFileSync(join(root, 'tools', 'build.sh'), ['src', join(sqlDir, `pgmorbac--${version}.sql`)], { cwd: root, stdio: 'inherit' });
|
||||
const upgrades = join(root, 'src', 'upgrades');
|
||||
if (existsSync(upgrades)) {
|
||||
for (const f of readdirSync(upgrades).filter((n) => n.endsWith('.sql'))) copyFileSync(join(upgrades, f), join(sqlDir, f));
|
||||
}
|
||||
Reference in New Issue
Block a user