@h-ai/iam 1.0.0-beta.22 → 1.0.0-beta.24

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/README.en.md CHANGED
@@ -1090,7 +1090,7 @@ When these deadlines are disabled, access and refresh retain their independent l
1090
1090
 
1091
1091
  ### Schema and credential notifications
1092
1092
 
1093
- After RelDB initialization, `migrateIam({ dryRun: true })` previews persistence preparation without writes. iam.init prepares persistence and credential/reset fields while retaining users, passwords and permissions. Back up and stop conflicting writes before structural changes. Sessions must match the current credential generation; mismatches require login, never lowering the stored generation. Default Reach notifications use sensitive/expiresAt/idempotencyKey without plaintext persistence or delayed replay. Custom callbacks must enforce the same expiry and credential protection.
1093
+ Initialize RelDB before `iam.init()`. IAM creates and validates the required tables and fails initialization if their structure is incompatible. Sessions must match the current credential generation. A mismatch requires signing in again. Default Reach notifications use `sensitive`, `expiresAt` and `idempotencyKey`, without persisting credentials or scheduling delayed delivery. Custom callbacks must enforce the same expiry and credential protection.
1094
1094
 
1095
1095
  When audit is initialized and capture.enabled is on, IAM records important account, authentication, password, authorization, API Key and session events, including failed/denied outcomes and safe reason codes. Initialize audit before IAM and close in reverse order. Passwords, one-time proofs and tokens are never copied into events. Only successful login establishes an actor; trusted service/CLI callers supply actor/correlation through audit.withContext. Events inside an external authorization transaction commit or roll back with that transaction; record failed attempts after rollback at the caller boundary. Audit failures emit diagnostics without converting an applied business result into an unsafe retry.
1096
1096
 
package/README.ja.md CHANGED
@@ -1082,7 +1082,7 @@ RBAC 権限は `sensitiveOperations: string[]` を持ち、可空 JSON 列 `sens
1082
1082
 
1083
1083
  ### スキーマと認証情報の通知
1084
1084
 
1085
- RelDB 初期化後の `migrateIam({ dryRun: true })` は読み取り専用です。iam.init は永続構造と認証・リセット項目を準備し、利用者・パスワード・権限を保持します。構造変更前に競合書込を停止しバックアップしてください。セッションは現在の資格世代と一致する必要があり、不一致なら再ログインします。認可復元のため世代を戻してはいけません。既定 Reach 通知は sensitive/expiresAt/idempotencyKey で平文保存や遅延再送を防ぎます。独自コールバックも同じ期限と保護を守ってください。
1085
+ RelDB の初期化後に `iam.init()` を呼び出します。IAM は必要なテーブルを作成・検証し、構造が一致しない場合は初期化に失敗します。セッションの資格世代が現在の世代と一致しない場合は再ログインが必要です。既定の Reach 通知は `sensitive`、`expiresAt`、`idempotencyKey` を使用し、資格情報本文を保存したり遅延配信したりしません。独自コールバックも同じ期限と資格情報保護を守ってください。
1086
1086
 
1087
1087
  audit が初期化済みで capture.enabled が有効なら、IAM はアカウント・認証・パスワード・権限・API Key・セッションの重要イベントと失敗/拒否の安全な理由コードを記録します。audit を IAM より先に初期化し、逆順に終了してください。パスワード・単回証明・トークンは記録しません。ログイン成功後に主体を確定し、信頼できるサービス/CLI は audit.withContext で操作者と関連文脈を設定します。外部権限トランザクション内のイベントは一緒にコミット/ロールバックされ、失敗試行はロールバック後に呼出境界で記録します。監査失敗は診断を出し、反映済み業務を危険な再試行に変えません。
1088
1088
 
package/README.md CHANGED
@@ -1095,7 +1095,7 @@ RBAC 权限支持 `sensitiveOperations: string[]`(持久字段 `sensitive_oper
1095
1095
 
1096
1096
  ### 持久结构与凭据通知
1097
1097
 
1098
- `migrateIam({ dryRun: true })` 在 RelDB 初始化后只读预检;iam.init 准备模块持久结构和凭据/重置字段,保留用户、密码与业务权限。结构变更前备份并停止冲突写入;会话必须匹配当前安全代际,不匹配时重新登录,不能降低数据库安全代际来恢复授权。默认 Reach 通知使用 sensitive/expiresAt/idempotencyKey,不落明文、不延迟重投;自定义回调同样须遵守有效期与凭据保护。
1098
+ 先初始化 RelDB,再调用 `iam.init()`。IAM 会创建并校验所需表,结构不符时返回初始化失败。会话必须匹配当前凭据代次,不匹配时需重新登录。默认 Reach 通知使用 `sensitive`、`expiresAt` 和 `idempotencyKey`,不保存凭据正文或延迟重投。自定义回调也须遵守有效期与凭据保护要求。
1099
1099
 
1100
1100
  审计模块已初始化且 capture.enabled 开启时,IAM 自动记录关键账号、鉴别、密码、授权、API Key 和会话事件,包含失败/拒绝与安全原因码。先初始化 audit 再初始化 IAM,关闭时反序。不会记录密码、一次性票据或令牌;成功登录才确认主体,可信服务/CLI 调用应以 audit.withContext 提供操作者和关联信息。外部授权事务的事件随该事务提交或回滚,回滚失败尝试由调用入口在事务结束后记录。审计写失败输出诊断,不把已生效业务改成可盲目重试的失败。
1101
1101
 
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { IamFunctions } from './browser.js';
2
2
  export { AccountConfigSchema, AgreementConfig, AgreementConfigSchema, AgreementDisplay, ApiKey, ApiKeyConfig, ApiKeyConfigSchema, ApiKeyCredentials, ApiKeyOperations, ApiKeySortDirection, ApiKeySortField, AuthRequestContext, AuthResult, AuthStrategy, AuthStrategyType, AuthStrategyTypeSchema, AuthUiConfig, AuthUiConfigSchema, AuthnOperations, AuthzOperations, CaptchaConfigSchema, CaptchaOperation, ConsumeTicketOptions, ConsumedTicket, CreateApiKeyOptions, CreateApiKeyResult, CreateSessionOptions, Credentials, HaiIamError, IamCaptchaChallenge, IamConfig, IamConfigInput, IamConfigSchema, IamConfigSettingsInput, IamNotificationContext, IamPublicConfig, IssueTicketOptions, IssuedTicket, LdapClientFactory, LdapConfig, LdapConfigSchema, LdapCredentials, ListApiKeysOptions, ListUsersOptions, LoginAccessConfigSchema, LoginConfig, LoginConfigSchema, OtpConfig, OtpConfigSchema, OtpCredentials, PasswordConfig, PasswordConfigSchema, PasswordCredentials, PasswordResetConfig, PasswordResetConfigSchema, Permission, PermissionQueryOptions, PermissionType, RbacConfig, RbacConfigSchema, RegisterConfig, RegisterConfigSchema, RegisterOptions, RegisterResult, Role, SecurityConfig, SecurityConfigSchema, Session, SessionConfig, SessionConfigSchema, SessionData, SessionFieldUpdates, SessionOperations, StoredUser, TicketGrant, TicketOperations, TokenPair, UpdateCurrentUserInput, User, UserOperations, UserSortDirection, UserSortField } from './browser.js';
3
- import * as _h_ai_core from '@h-ai/core';
4
- import * as _h_ai_reldb from '@h-ai/reldb';
5
3
  import 'zod';
4
+ import '@h-ai/core';
6
5
  import '@h-ai/reach';
7
6
  import 'altcha/lib';
7
+ import '@h-ai/reldb';
8
8
 
9
9
  /**
10
10
  * @h-ai/iam — IAM 服务主入口
@@ -30,16 +30,4 @@ import 'altcha/lib';
30
30
  */
31
31
  declare const iam: IamFunctions;
32
32
 
33
- /**
34
- * 预检或迁移 IAM 表。保留用户与密码;旧停用账号转休眠,删除 enabled,旧版 SDK 不可与新表混用。
35
- * @example
36
- * ```ts
37
- * import { migrateIam } from '@h-ai/iam'
38
- * const plan = await migrateIam({ dryRun: true }) // RelDB 已初始化;只读。
39
- * ```
40
- */
41
- declare function migrateIam(options?: {
42
- dryRun?: boolean;
43
- }): Promise<_h_ai_core.HaiResult<_h_ai_reldb.SchemaMigrationPlan>>;
44
-
45
- export { IamFunctions, iam, migrateIam };
33
+ export { IamFunctions, iam };
package/dist/index.js CHANGED
@@ -1390,7 +1390,9 @@ async function createDbUserRepository() {
1390
1390
  if (userRepoInstance && userRepoSqlOps === reldb.sql)
1391
1391
  return userRepoInstance;
1392
1392
  const repo = new DbUserRepository();
1393
- await repo.count();
1393
+ const ready = await repo.ready();
1394
+ if (!ready.success)
1395
+ throw ready.error;
1394
1396
  repo.create = guardIamMutation(repo.create.bind(repo), 1);
1395
1397
  repo.updateById = guardIamMutation(repo.updateById.bind(repo), 2);
1396
1398
  repo.deleteById = guardIamMutation(repo.deleteById.bind(repo), 1);
@@ -1408,6 +1410,9 @@ var DbUserRepository = class extends BaseReldbCrudRepository {
1408
1410
  fields: USER_FIELDS
1409
1411
  });
1410
1412
  }
1413
+ ready() {
1414
+ return this.ensureSchema();
1415
+ }
1411
1416
  /** 数据库时钟在执行最终 SQL 时核验有效期,暂停进程不能复用旧的 Date.now()。 */
1412
1417
  databaseNow() {
1413
1418
  if (reldb.config?.type === "postgresql")
@@ -3073,7 +3078,9 @@ async function createDbPermissionRepository() {
3073
3078
  if (permRepoInstance && permRepoSqlOps === reldb.sql)
3074
3079
  return permRepoInstance;
3075
3080
  const repo = new DbPermissionRepository();
3076
- await repo.count();
3081
+ const ready = await repo.ready();
3082
+ if (!ready.success)
3083
+ throw ready.error;
3077
3084
  permRepoInstance = repo;
3078
3085
  permRepoSqlOps = reldb.sql;
3079
3086
  return repo;
@@ -3113,6 +3120,9 @@ var DbPermissionRepository = class extends BaseReldbCrudRepository {
3113
3120
  fields: PERMISSION_FIELDS
3114
3121
  });
3115
3122
  }
3123
+ ready() {
3124
+ return this.ensureSchema();
3125
+ }
3116
3126
  /** 根据权限代码查找权限 */
3117
3127
  async findByCode(code, tx) {
3118
3128
  return this.findOneBy("code = ?", [code], tx);
@@ -4738,123 +4748,6 @@ function observeApiKeys(operations) {
4738
4748
  revokeApiKey: (id) => observe(() => operations.revokeApiKey(id), { action: "apikey.revoke", resource: "iam.apikeys", resourceId: id })
4739
4749
  };
4740
4750
  }
4741
- var columns = {
4742
- credential_version: "VARCHAR(255) NOT NULL DEFAULT ''",
4743
- reset_version: "VARCHAR(255) NOT NULL DEFAULT ''",
4744
- reset_hash: "TEXT",
4745
- reset_expires_at: "BIGINT",
4746
- reset_attempts: "INTEGER NOT NULL DEFAULT 0"
4747
- };
4748
- var accountColumns = {
4749
- account_type: "VARCHAR(16) NOT NULL DEFAULT 'permanent'",
4750
- account_status: "VARCHAR(16) NOT NULL DEFAULT 'active'",
4751
- account_expires_at: "TIMESTAMP",
4752
- last_login_at: "TIMESTAMP"
4753
- };
4754
- var steps = [
4755
- {
4756
- version: 1,
4757
- name: "credential-and-reset-versions",
4758
- async needed(sql) {
4759
- const found = await reldb.schemaColumns("hai_iam_users", sql);
4760
- return found.success ? ok(found.data.length > 0 && Object.keys(columns).some((name) => !found.data.includes(name))) : found;
4761
- },
4762
- async apply(sql) {
4763
- const found = await reldb.schemaColumns("hai_iam_users", sql);
4764
- if (!found.success)
4765
- return found;
4766
- for (const [name, definition] of Object.entries(columns)) {
4767
- if (found.data.includes(name))
4768
- continue;
4769
- const added = await sql.execute(`ALTER TABLE hai_iam_users ADD COLUMN ${name} ${definition}`);
4770
- if (!added.success)
4771
- return added;
4772
- }
4773
- return ok(void 0);
4774
- }
4775
- },
4776
- {
4777
- version: 2,
4778
- name: "account-lifecycle",
4779
- async needed(sql) {
4780
- const found = await reldb.schemaColumns("hai_iam_users", sql);
4781
- return found.success ? ok(found.data.length > 0 && Object.keys(accountColumns).some((name) => !found.data.includes(name))) : found;
4782
- },
4783
- async apply(sql) {
4784
- const found = await reldb.schemaColumns("hai_iam_users", sql);
4785
- if (!found.success)
4786
- return found;
4787
- for (const [name, definition] of Object.entries(accountColumns)) {
4788
- if (found.data.includes(name))
4789
- continue;
4790
- const added = await sql.execute(`ALTER TABLE hai_iam_users ADD COLUMN ${name} ${definition}`);
4791
- if (!added.success)
4792
- return added;
4793
- }
4794
- return ok(void 0);
4795
- }
4796
- },
4797
- {
4798
- version: 3,
4799
- name: "initial-password-state",
4800
- async needed(sql) {
4801
- const found = await reldb.schemaColumns("hai_iam_users", sql);
4802
- return found.success ? ok(found.data.length > 0 && !found.data.includes("must_change_password")) : found;
4803
- },
4804
- async apply(sql) {
4805
- const added = await sql.execute("ALTER TABLE hai_iam_users ADD COLUMN must_change_password BOOLEAN NOT NULL DEFAULT FALSE");
4806
- return added.success ? ok(void 0) : added;
4807
- }
4808
- },
4809
- {
4810
- version: 4,
4811
- name: "login-failure-window",
4812
- async needed(sql) {
4813
- const found = await reldb.schemaColumns("hai_iam_users", sql);
4814
- return found.success ? ok(found.data.length > 0 && !found.data.includes("first_login_failed_at")) : found;
4815
- },
4816
- async apply(sql) {
4817
- const added = await sql.execute("ALTER TABLE hai_iam_users ADD COLUMN first_login_failed_at TIMESTAMP");
4818
- return added.success ? ok(void 0) : added;
4819
- }
4820
- },
4821
- {
4822
- version: 5,
4823
- name: "permission-sensitive-operations",
4824
- async needed(sql) {
4825
- const found = await reldb.schemaColumns("hai_iam_permissions", sql);
4826
- return found.success ? ok(found.data.length > 0 && !found.data.includes("sensitive_operations")) : found;
4827
- },
4828
- async apply(sql) {
4829
- const added = await sql.execute("ALTER TABLE hai_iam_permissions ADD COLUMN sensitive_operations JSON");
4830
- return added.success ? ok(void 0) : added;
4831
- }
4832
- },
4833
- {
4834
- version: 6,
4835
- name: "account-lifecycle-only",
4836
- async needed(sql) {
4837
- const found = await reldb.schemaColumns("hai_iam_users", sql);
4838
- return found.success ? ok(found.data.includes("enabled")) : found;
4839
- },
4840
- async apply(sql) {
4841
- const converted = await sql.execute("UPDATE hai_iam_users SET account_status = ?, credential_version = ?, reset_version = ?, reset_hash = NULL, reset_expires_at = NULL WHERE (enabled = ? OR enabled IS NULL) AND account_status = ?", [
4842
- "dormant",
4843
- globalThis.crypto.randomUUID(),
4844
- globalThis.crypto.randomUUID(),
4845
- reldb.config?.type === "postgresql" ? false : 0,
4846
- "active"
4847
- ]);
4848
- if (!converted.success)
4849
- return converted;
4850
- const removed = await sql.execute("ALTER TABLE hai_iam_users DROP COLUMN enabled");
4851
- return removed.success ? ok(void 0) : removed;
4852
- }
4853
- }
4854
- ];
4855
- function migrateIam(options = {}) {
4856
- return reldb.migrateSchema("iam", steps, options);
4857
- }
4858
4751
 
4859
4752
  // src/iam-notifications.ts
4860
4753
  async function resolveIamNotifications(input) {
@@ -6658,9 +6551,6 @@ var iam = {
6658
6551
  sms: Boolean(onOtpSendSms),
6659
6552
  passwordReset: Boolean(onPasswordResetRequest)
6660
6553
  });
6661
- const migration = await migrateIam();
6662
- if (!migration.success)
6663
- return migration;
6664
6554
  const credentialUsers = await createDbUserRepository();
6665
6555
  const sessionResult = await createSessionOperations({
6666
6556
  config: parsed,
@@ -6848,6 +6738,6 @@ var iam = {
6848
6738
  }
6849
6739
  };
6850
6740
 
6851
- export { iam, migrateIam };
6741
+ export { iam };
6852
6742
  //# sourceMappingURL=index.js.map
6853
6743
  //# sourceMappingURL=index.js.map