@astram/identity 0.12.0 → 0.13.0

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.
@@ -16,6 +16,14 @@ import type { FrameworkSchemas } from '@astram/core';
16
16
  import { type RecordAuthorizationInputs } from '@astram/guard';
17
17
  import type { ObjectTypeInput } from '@astram/engine';
18
18
  import type { IdentitySchemaNames } from '../../schema.js';
19
+ /**
20
+ * A pool-size variable: unset or blank gives `undefined`; otherwise plain digits, a positive safe
21
+ * integer, or it throws naming the variable (never the value). The single-layout pool budget in
22
+ * `@astram/guard` (`loadPoolBudget`) applies the same rule, so the budget counts the pools that open.
23
+ */
24
+ export declare function strictPoolSize(raw: string | undefined, name: string): number | undefined;
25
+ /** The authz pool cap: `APP_AUTHZ_POOL_MAX` (strict), else 4. */
26
+ export declare function authzPoolLimit(env?: NodeJS.ProcessEnv): number;
19
27
  /**
20
28
  * A lean `mariadb` pool for the authz grant-reads (built from `APP_DB_*` env via guard's
21
29
  * `loadDbConfig`). Kept small — these are pre-gate coarse-grant reads, not the main CRUD pool.
@@ -1 +1 @@
1
- {"version":3,"file":"record-authorization.d.ts","sourceRoot":"","sources":["../../../src/features/authz/record-authorization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAgB,EAAE,KAAK,IAAI,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAIL,KAAK,yBAAyB,EAC/B,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAaxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,IAAI,EACV,YAAY,GAAE,SAAS,eAAe,EAAO;AAC7C,0FAA0F;AAC1F,OAAO,CAAC,EAAE,mBAAmB,GAC5B,yBAAyB,CAS3B"}
1
+ {"version":3,"file":"record-authorization.d.ts","sourceRoot":"","sources":["../../../src/features/authz/record-authorization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAgB,EAAE,KAAK,IAAI,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAIL,KAAK,yBAAyB,EAC/B,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMxF;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAE3E;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAaxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,IAAI,EACV,YAAY,GAAE,SAAS,eAAe,EAAO;AAC7C,0FAA0F;AAC1F,OAAO,CAAC,EAAE,mBAAmB,GAC5B,yBAAyB,CAS3B"}
@@ -3,6 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.strictPoolSize = strictPoolSize;
7
+ exports.authzPoolLimit = authzPoolLimit;
6
8
  exports.createIdentityAuthzPool = createIdentityAuthzPool;
7
9
  exports.buildRecordAuthorizationInputs = buildRecordAuthorizationInputs;
8
10
  /**
@@ -23,6 +25,24 @@ const guard_1 = require("@astram/guard");
23
25
  const objects_js_1 = require("../../objects.js");
24
26
  const db_permission_facts_adapter_js_1 = require("./db-permission-facts.adapter.js");
25
27
  const session_facts_reader_js_1 = require("./session-facts.reader.js");
28
+ /**
29
+ * A pool-size variable: unset or blank gives `undefined`; otherwise plain digits, a positive safe
30
+ * integer, or it throws naming the variable (never the value). The single-layout pool budget in
31
+ * `@astram/guard` (`loadPoolBudget`) applies the same rule, so the budget counts the pools that open.
32
+ */
33
+ function strictPoolSize(raw, name) {
34
+ if (raw === undefined || raw.trim() === '')
35
+ return undefined;
36
+ const t = raw.trim();
37
+ const n = /^[0-9]+$/.test(t) ? Number(t) : Number.NaN;
38
+ if (!Number.isSafeInteger(n) || n < 1)
39
+ throw new Error(`${name} must be a positive integer`);
40
+ return n;
41
+ }
42
+ /** The authz pool cap: `APP_AUTHZ_POOL_MAX` (strict), else 4. */
43
+ function authzPoolLimit(env = process.env) {
44
+ return strictPoolSize(env.APP_AUTHZ_POOL_MAX, 'APP_AUTHZ_POOL_MAX') ?? 4;
45
+ }
26
46
  /**
27
47
  * A lean `mariadb` pool for the authz grant-reads (built from `APP_DB_*` env via guard's
28
48
  * `loadDbConfig`). Kept small — these are pre-gate coarse-grant reads, not the main CRUD pool.
@@ -39,7 +59,7 @@ function createIdentityAuthzPool(schemas) {
39
59
  user: db.user,
40
60
  password: db.password,
41
61
  database: db.database,
42
- connectionLimit: Number(process.env.APP_AUTHZ_POOL_MAX ?? 4),
62
+ connectionLimit: authzPoolLimit(process.env),
43
63
  // Phase 16: APP_DB_TLS / APP_DB_TLS_CA (production accounts are REQUIRE SSL).
44
64
  ...(ssl ? { ssl } : {}),
45
65
  });
@@ -1,6 +1,6 @@
1
1
  import { type DynamicModule } from '@nestjs/common';
2
2
  import { type FrameworkSchemas } from '@astram/core';
3
- import { type ObjectTypeInput } from '@astram/engine';
3
+ import { type EngineDbConfig, type ObjectTypeInput } from '@astram/engine';
4
4
  /**
5
5
  * The boot check behind {@link IDENTITY_DECISION_AUTHORITY_CHECK}: with this module wired, the
6
6
  * request path must decide with the authority guard built from this module's inputs. A missing
@@ -30,6 +30,12 @@ export declare function assertFrameworkDatabaseAgrees(identityDatabase: string,
30
30
  readonly database?: string;
31
31
  };
32
32
  } | null | undefined): true;
33
+ /**
34
+ * Map guard's DbConfig → the engine's EngineDbConfig (adds the pool cap the engine needs). The
35
+ * database and default user follow `schemas` (the names `forRoot` resolved or was given); an
36
+ * explicit `APP_DB_USER` / `APP_DB_NAME` still wins (QA P2-5).
37
+ */
38
+ export declare function engineDbFromEnv(schemas: FrameworkSchemas, env?: NodeJS.ProcessEnv): EngineDbConfig;
33
39
  /**
34
40
  * IdentityFeatureModule — the framework-owned identity FEATURE surface (company/user/role CRUD;
35
41
  * more in later phases) as thin controllers over the engine's RecordsService. The CONSUMER imports
@@ -1 +1 @@
1
- {"version":3,"file":"identity-feature.module.d.ts","sourceRoot":"","sources":["../../src/features/identity-feature.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpE,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,cAAc,CAAC;AACtB,OAAO,EAeL,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AA0GxB;;;;;;GAMG;AACH,wBAAgB,0CAA0C,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAUnF;AAKD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,GACzC,IAAI,CAuBN;AAKD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,gBAAgB,EAAE,MAAM,EACxB,WAAW,EAAE;IAAE,QAAQ,CAAC,EAAE,CAAC,EAAE;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GAC/E,IAAI,CAQN;AAwBD;;;;;;;;;;GAUG;AACH,qBACa,qBAAqB;IAChC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,OAAO,CAAC,EACb,OAAO,EACP,YAAiB,EACjB,OAAO,EAAE,YAAY,GACtB,GAAE;QACD,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC5B,YAAY,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;QAC1C,OAAO,CAAC,EAAE,gBAAgB,CAAC;KACvB,GAAG,aAAa;CA2jBvB"}
1
+ {"version":3,"file":"identity-feature.module.d.ts","sourceRoot":"","sources":["../../src/features/identity-feature.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpE,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,cAAc,CAAC;AACtB,OAAO,EAYL,KAAK,cAAc,EAGnB,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AA2GxB;;;;;;GAMG;AACH,wBAAgB,0CAA0C,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAUnF;AAKD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,GACzC,IAAI,CAwBN;AAKD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,gBAAgB,EAAE,MAAM,EACxB,WAAW,EAAE;IAAE,QAAQ,CAAC,EAAE,CAAC,EAAE;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GAC/E,IAAI,CAQN;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,gBAAgB,EACzB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,cAAc,CAqBhB;AAED;;;;;;;;;;GAUG;AACH,qBACa,qBAAqB;IAChC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,OAAO,CAAC,EACb,OAAO,EACP,YAAiB,EACjB,OAAO,EAAE,YAAY,GACtB,GAAE;QACD,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC5B,YAAY,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;QAC1C,OAAO,CAAC,EAAE,gBAAgB,CAAC;KACvB,GAAG,aAAa;CA2jBvB"}
@@ -11,6 +11,7 @@ exports.IdentityFeatureModule = void 0;
11
11
  exports.assertRequestPathUsesIdentityAuthorization = assertRequestPathUsesIdentityAuthorization;
12
12
  exports.assertFrameworkSchemasAgree = assertFrameworkSchemasAgree;
13
13
  exports.assertFrameworkDatabaseAgrees = assertFrameworkDatabaseAgrees;
14
+ exports.engineDbFromEnv = engineDbFromEnv;
14
15
  const common_1 = require("@nestjs/common");
15
16
  const core_1 = require("@nestjs/core");
16
17
  const core_2 = require("@astram/core");
@@ -107,7 +108,7 @@ const IDENTITY_FRAMEWORK_SCHEMAS_CHECK = Symbol('IDENTITY_FRAMEWORK_SCHEMAS_CHEC
107
108
  * Throws (fail closed) with the namespaces and names only.
108
109
  */
109
110
  function assertFrameworkSchemasAgree(identity, guard) {
110
- const names = (s) => `namespace=${s.namespace} app=${s.app} identity=${s.identity} authz=${s.authz} audit=${s.audit}`;
111
+ const names = (s) => `namespace=${s.namespace} app=${s.app} identity=${s.identity} authz=${s.authz} audit=${s.audit} layout=${s.layout ?? 'four'}`;
111
112
  if (guard === undefined || guard === null) {
112
113
  if (identity.isDefault)
113
114
  return true;
@@ -117,7 +118,8 @@ function assertFrameworkSchemasAgree(identity, guard) {
117
118
  const same = identity.app === guard.app &&
118
119
  identity.identity === guard.identity &&
119
120
  identity.authz === guard.authz &&
120
- identity.audit === guard.audit;
121
+ identity.audit === guard.audit &&
122
+ (identity.layout ?? 'four') === (guard.layout ?? 'four');
121
123
  if (!same) {
122
124
  throw new Error(`IdentityFeatureModule: framework database names disagree — identity ${names(identity)}; ` +
123
125
  `guard ${names(guard)}. Pass the same names (or none) to ShieldModule and ` +
@@ -147,8 +149,13 @@ function assertFrameworkDatabaseAgrees(identityDatabase, guardConfig) {
147
149
  * database and default user follow `schemas` (the names `forRoot` resolved or was given); an
148
150
  * explicit `APP_DB_USER` / `APP_DB_NAME` still wins (QA P2-5).
149
151
  */
150
- function engineDbFromEnv(schemas) {
151
- const db = (0, guard_1.loadDbConfig)(process.env, schemas);
152
+ function engineDbFromEnv(schemas, env = process.env) {
153
+ const db = (0, guard_1.loadDbConfig)(env, schemas);
154
+ // POOL_MAX_ENGINE, else APP_DB_MAX_CONNECTIONS, else 10; a set but invalid value throws naming
155
+ // the variable. Guard's single-layout pool budget parses these the same way.
156
+ const connectionLimit = (0, record_authorization_js_1.strictPoolSize)(env.POOL_MAX_ENGINE, 'POOL_MAX_ENGINE') ??
157
+ (0, record_authorization_js_1.strictPoolSize)(env.APP_DB_MAX_CONNECTIONS, 'APP_DB_MAX_CONNECTIONS') ??
158
+ 10;
152
159
  const ssl = (0, guard_1.mariadbSslOption)(db.tls);
153
160
  return {
154
161
  host: db.host,
@@ -158,7 +165,7 @@ function engineDbFromEnv(schemas) {
158
165
  database: db.database,
159
166
  // The engine's runtime CRUD pool cap. A conservative default; the app can raise it later via
160
167
  // an explicit EngineModule.forRoot if it needs more. (ADR-0018 budget lives app-side.)
161
- connectionLimit: Number(process.env.APP_DB_MAX_CONNECTIONS ?? 10),
168
+ connectionLimit,
162
169
  // Phase 16: APP_DB_TLS / APP_DB_TLS_CA (production accounts are REQUIRE SSL).
163
170
  ...(ssl ? { ssl } : {}),
164
171
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astram/identity",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "license": "MIT",
5
5
  "description": "Astram framework — the framework-owned identity + tenancy model. Hosts the identity @ObjectType classes (user, company, membership, posting), framework-authored identity migrations, and the identity resolver. Top of the dependency graph: depends on @astram/engine (for @ObjectType/@Field decorators) + @astram/guard / @astram/core (for the auth ports).",
6
6
  "type": "commonjs",
@@ -36,9 +36,9 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "mariadb": "^3.5.4",
39
- "@astram/core": "1.7.0",
40
- "@astram/engine": "0.8.0",
41
- "@astram/guard": "0.15.0"
39
+ "@astram/core": "1.8.0",
40
+ "@astram/guard": "0.16.0",
41
+ "@astram/engine": "0.9.0"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@nestjs/common": "^11",