@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 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
- /** The shipped SQL, next to `dist/` in the package and next to `src/` in this repository. */
4
- const MIGRATIONS = new URL('../migrations/', import.meta.url);
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 names = (await readdir(MIGRATIONS)).filter((n) => n.endsWith('.sql')).sort();
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(new URL(name, MIGRATIONS), 'utf8');
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
- /** A credential cannot be the recovery owner: expiry or issuer revocation can remove its authority. */
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
- /** A credential cannot be the recovery owner: expiry or issuer revocation can remove its authority. */
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.builtIn, true), eq(r.key, 'owner'), eq(invitations.status, 'pending'), gt(invitations.expiresAt, sql `now()`)));
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.0",
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.12.0",
20
- "drizzle-orm": "^0.39.0"
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"