@wtfalch/authz-store 0.1.0 → 0.2.1
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/dist/migrate.js +15 -4
- package/dist/owners.d.ts +6 -1
- package/dist/owners.js +7 -3
- package/package.json +3 -3
package/dist/migrate.js
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { readFile, readdir } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
2
4
|
import { sql } from 'drizzle-orm';
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The shipped SQL, next to `dist/` in the package and next to `src/` in this repository. Computed
|
|
7
|
+
* lazily inside `migrateStore` rather than as a module-level `new URL('../migrations/',
|
|
8
|
+
* import.meta.url)`: Turbopack resolves that literal statically when an app imports the package
|
|
9
|
+
* barrel, and fails with "Can't resolve '../migrations/'" because the directory holds no importable
|
|
10
|
+
* module.
|
|
11
|
+
*/
|
|
12
|
+
function migrationsDir() {
|
|
13
|
+
return join(dirname(fileURLToPath(import.meta.url)), '..', 'migrations');
|
|
14
|
+
}
|
|
5
15
|
/** Files split on this line, the marker drizzle-kit writes, so any driver can run them one statement at a time. */
|
|
6
16
|
const BREAKPOINT = '--> statement-breakpoint';
|
|
7
17
|
/** One key for every host, so two containers starting at once apply each file once between them. */
|
|
@@ -12,10 +22,11 @@ const LOCK = 7_310_422_001;
|
|
|
12
22
|
* migrations, so everything the package owns exists before a host migration references it.
|
|
13
23
|
*/
|
|
14
24
|
export async function migrateStore(db) {
|
|
15
|
-
const
|
|
25
|
+
const dir = migrationsDir();
|
|
26
|
+
const names = (await readdir(dir)).filter((n) => n.endsWith('.sql')).sort();
|
|
16
27
|
const applied = [];
|
|
17
28
|
for (const name of names) {
|
|
18
|
-
const text = await readFile(
|
|
29
|
+
const text = await readFile(join(dir, name), 'utf8');
|
|
19
30
|
const ran = await db.transaction(async (tx) => {
|
|
20
31
|
await tx.execute(sql `select pg_advisory_xact_lock(${LOCK})`);
|
|
21
32
|
// Created under the lock: two runners creating it at once collide in pg_type.
|
package/dist/owners.d.ts
CHANGED
|
@@ -17,7 +17,12 @@ export interface OwnerCoverageOptions {
|
|
|
17
17
|
readonly excludePrincipalId?: string;
|
|
18
18
|
readonly excludePrincipalClass?: string;
|
|
19
19
|
}
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* A credential cannot be the recovery owner: expiry or issuer revocation can remove its authority.
|
|
22
|
+
*
|
|
23
|
+
* Owners are counted by the fixed `owner` role key, not the `builtIn` flag: the owner role is
|
|
24
|
+
* fixed, one per org, never renamed (decided in https://github.com/wtfalch/authz/issues/67).
|
|
25
|
+
*/
|
|
21
26
|
export declare function ownerCoverage(tx: DbOrTx, binding: PolicyBinding, tenantId: string, options?: OwnerCoverageOptions): Promise<OwnerCoverage>;
|
|
22
27
|
export declare function ownerSeatCovered(coverage: OwnerCoverage): boolean;
|
|
23
28
|
export declare function principalIsReachable(): import("drizzle-orm").SQL<unknown>;
|
package/dist/owners.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { and, eq, gt, isNull, sql } from 'drizzle-orm';
|
|
2
2
|
import { policyAssignments, policyRoles } from './policy-schema.js';
|
|
3
3
|
import { credentials, invitations, memberships } from './schema.js';
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* A credential cannot be the recovery owner: expiry or issuer revocation can remove its authority.
|
|
6
|
+
*
|
|
7
|
+
* Owners are counted by the fixed `owner` role key, not the `builtIn` flag: the owner role is
|
|
8
|
+
* fixed, one per org, never renamed (decided in https://github.com/wtfalch/authz/issues/67).
|
|
9
|
+
*/
|
|
5
10
|
export async function ownerCoverage(tx, binding, tenantId, options = {}) {
|
|
6
11
|
const a = policyAssignments;
|
|
7
12
|
const r = policyRoles;
|
|
@@ -11,7 +16,6 @@ export async function ownerCoverage(tx, binding, tenantId, options = {}) {
|
|
|
11
16
|
eq(a.platformId, binding.platformId),
|
|
12
17
|
eq(a.source, 'direct'),
|
|
13
18
|
eq(a.principalClass, 'human'),
|
|
14
|
-
eq(r.builtIn, true),
|
|
15
19
|
eq(r.key, 'owner'),
|
|
16
20
|
isNull(a.expiresAt),
|
|
17
21
|
sql `${a.scope}->>'kind' = 'organisation'`,
|
|
@@ -29,7 +33,7 @@ export async function ownerCoverage(tx, binding, tenantId, options = {}) {
|
|
|
29
33
|
.select({ count: sql `count(*)::int` })
|
|
30
34
|
.from(invitations)
|
|
31
35
|
.innerJoin(r, eq(invitations.roleId, r.id))
|
|
32
|
-
.where(and(eq(invitations.tenantId, tenantId), eq(r.
|
|
36
|
+
.where(and(eq(invitations.tenantId, tenantId), eq(r.key, 'owner'), eq(invitations.status, 'pending'), gt(invitations.expiresAt, sql `now()`)));
|
|
33
37
|
return { directOwners: owners?.count ?? 0, pendingOwnerInvitations: pending?.count ?? 0 };
|
|
34
38
|
}
|
|
35
39
|
export function ownerSeatCovered(coverage) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wtfalch/authz-store",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Persistence and lifecycle for @wtfalch/authz: the storage a host would otherwise write itself.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"./package.json": "./package.json"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
|
19
|
-
"@wtfalch/authz": "^0.
|
|
20
|
-
"drizzle-orm": "
|
|
19
|
+
"@wtfalch/authz": "^0.15.0",
|
|
20
|
+
"drizzle-orm": ">=0.39.0 <1.0.0"
|
|
21
21
|
},
|
|
22
22
|
"engines": {
|
|
23
23
|
"node": ">=22.0.0"
|