@camstack/core 0.1.28 → 0.1.30

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.
@@ -10,7 +10,14 @@ export declare class ScopedTokenManager {
10
10
  record: ScopedToken;
11
11
  }>;
12
12
  validate(rawToken: string): Promise<ScopedToken | null>;
13
- matchesScope(token: ScopedToken, addonId?: string, routePath?: string, capability?: string): boolean;
13
+ /**
14
+ * Coarse scope match — checks only `addonId` / `capability` (no
15
+ * `route-prefix` after the caps-only migration). Used by addon-route
16
+ * HTTP handlers that need a quick allow/deny before the per-method
17
+ * `access` check kicks in via `METHOD_ACCESS_MAP` in
18
+ * `protectedProcedure`.
19
+ */
20
+ matchesScope(token: ScopedToken, addonId?: string, capability?: string): boolean;
14
21
  revoke(tokenId: string): Promise<void>;
15
22
  listForUser(userId: string): Promise<ScopedToken[]>;
16
23
  updateLastUsed(tokenId: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"scoped-token-manager.d.ts","sourceRoot":"","sources":["../../src/auth/scoped-token-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAUnF;;GAEG;AACH,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,mBAAmB;IAEjD,MAAM,CACV,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,EAAE,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,CAAC;IAsB5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAY7D,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO;IAW9F,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAKnD,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpD;;;;;;;;;;;;;;OAcG;IACG,cAAc,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;CAYzE"}
1
+ {"version":3,"file":"scoped-token-manager.d.ts","sourceRoot":"","sources":["../../src/auth/scoped-token-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAUnF;;GAEG;AACH,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,mBAAmB;IAEjD,MAAM,CACV,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,EAAE,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,CAAC;IAsB5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAY7D;;;;;;OAMG;IACH,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO;IAU1E,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAKnD,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpD;;;;;;;;;;;;;;OAcG;IACG,cAAc,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;CAYzE"}
@@ -1,5 +1,5 @@
1
1
  import { AuthManager } from './auth-manager.js';
2
- import { UserRecord, UserRole, SettingsStoreClient } from '@camstack/types';
2
+ import { UserRecord, UserRole, TokenScope, SettingsStoreClient } from '@camstack/types';
3
3
  export type { UserRecord };
4
4
  interface CreateUserInput {
5
5
  username: string;
@@ -7,8 +7,9 @@ interface CreateUserInput {
7
7
  role: UserRole;
8
8
  allowedProviders?: string[] | '*';
9
9
  allowedDevices?: Record<string, string[] | '*'>;
10
+ scopes?: TokenScope[];
10
11
  }
11
- type UpdatableUserFields = Partial<Pick<UserRecord, 'role' | 'allowedProviders' | 'allowedDevices'>>;
12
+ type UpdatableUserFields = Partial<Pick<UserRecord, 'role' | 'allowedProviders' | 'allowedDevices' | 'scopes'>>;
12
13
  export interface UserStorageAccess {
13
14
  getStore(): SettingsStoreClient;
14
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"user-manager.d.ts","sourceRoot":"","sources":["../../src/auth/user-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAGhF,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B,UAAU,eAAe;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,QAAQ,CAAA;IACd,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,GAAG,CAAA;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,CAAA;CAChD;AAED,KAAK,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,GAAG,gBAAgB,CAAC,CAAC,CAAA;AAIpG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,IAAI,mBAAmB,CAAA;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAAA;CACxB;AAMD,qBAAa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAFN,aAAa,EAAE,iBAAiB,EAChC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,gBAAgB;IAG3C,OAAO,KAAK,KAAK,GAEhB;IAEK,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;IAqBnD,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAM5D,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAMhD,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAOnF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,EAAE,CAAC;IAStD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5D,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjC,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7D,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;CAkBzC"}
1
+ {"version":3,"file":"user-manager.d.ts","sourceRoot":"","sources":["../../src/auth/user-manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAG5F,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B,UAAU,eAAe;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,QAAQ,CAAA;IACd,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,GAAG,CAAA;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,CAAA;IAC/C,MAAM,CAAC,EAAE,UAAU,EAAE,CAAA;CACtB;AAED,KAAK,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,QAAQ,CAAC,CAAC,CAAA;AAI/G,MAAM,WAAW,iBAAiB;IAChC,QAAQ,IAAI,mBAAmB,CAAA;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAAA;CACxB;AAMD,qBAAa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAFN,aAAa,EAAE,iBAAiB,EAChC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,gBAAgB;IAG3C,OAAO,KAAK,KAAK,GAEhB;IAEK,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC;IAsBnD,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAM5D,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAMhD,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAOnF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,EAAE,CAAC;IAStD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5D,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjC,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7D,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;CAqBzC"}
@@ -12,6 +12,12 @@ export declare class LocalAuthAddon extends BaseAddon<LocalAuthConfig> {
12
12
  constructor();
13
13
  protected onInitialize(): Promise<ProviderRegistration[]>;
14
14
  protected onShutdown(): Promise<void>;
15
+ /**
16
+ * Caps-only auth migration — rewrites legacy `super_admin` rows to
17
+ * `admin` and backfills the missing `scopes` field with `[]`. Idempotent;
18
+ * a re-run sees no rows needing changes.
19
+ */
20
+ private migrateLegacyUserRecords;
15
21
  }
16
22
  export default LocalAuthAddon;
17
23
  //# sourceMappingURL=local-auth.addon.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-auth.addon.d.ts","sourceRoot":"","sources":["../../../src/builtins/local-auth/local-auth.addon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAA2B,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AACpF,OAAO,EAAE,SAAS,EAAoD,MAAM,iBAAiB,CAAA;AA4B7F,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,qBAAa,cAAe,SAAQ,SAAS,CAAC,eAAe,CAAC;IAC5D,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,kBAAkB,CAAkC;;cAI5C,YAAY,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAwM/C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAM5C;AAED,eAAe,cAAc,CAAA"}
1
+ {"version":3,"file":"local-auth.addon.d.ts","sourceRoot":"","sources":["../../../src/builtins/local-auth/local-auth.addon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAA2B,oBAAoB,EAAuB,MAAM,iBAAiB,CAAA;AACzG,OAAO,EAAE,SAAS,EAAoD,MAAM,iBAAiB,CAAA;AA4B7F,UAAU,eAAe;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,qBAAa,cAAe,SAAQ,SAAS,CAAC,eAAe,CAAC;IAC5D,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,kBAAkB,CAAkC;;cAI5C,YAAY,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;cAmO/C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3C;;;;OAIG;YACW,wBAAwB;CAwBvC;AAED,eAAe,cAAc,CAAA"}
@@ -6258,6 +6258,7 @@ var UserManager = class {
6258
6258
  role: input.role,
6259
6259
  allowedProviders: input.allowedProviders ?? "*",
6260
6260
  allowedDevices: input.allowedDevices ?? {},
6261
+ scopes: input.scopes ?? [],
6261
6262
  createdAt: now,
6262
6263
  updatedAt: now
6263
6264
  };
@@ -6342,7 +6343,7 @@ var UserManager = class {
6342
6343
  await this.create({
6343
6344
  username: adminUsername,
6344
6345
  password: adminPassword,
6345
- role: "super_admin",
6346
+ role: "admin",
6346
6347
  allowedProviders: "*",
6347
6348
  allowedDevices: {}
6348
6349
  });
@@ -6481,14 +6482,18 @@ var ScopedTokenManager = class {
6481
6482
  this.updateLastUsed(record.id).catch(() => {});
6482
6483
  return record;
6483
6484
  }
6484
- matchesScope(token, addonId, routePath, capability) {
6485
+ /**
6486
+ * Coarse scope match — checks only `addonId` / `capability` (no
6487
+ * `route-prefix` after the caps-only migration). Used by addon-route
6488
+ * HTTP handlers that need a quick allow/deny before the per-method
6489
+ * `access` check kicks in via `METHOD_ACCESS_MAP` in
6490
+ * `protectedProcedure`.
6491
+ */
6492
+ matchesScope(token, addonId, capability) {
6485
6493
  for (const scope of token.scopes) switch (scope.type) {
6486
6494
  case "addon":
6487
6495
  if (addonId && scope.target === addonId) return true;
6488
6496
  break;
6489
- case "route-prefix":
6490
- if (routePath && routePath.startsWith(scope.target)) return true;
6491
- break;
6492
6497
  case "capability":
6493
6498
  if (capability && scope.target === capability) return true;
6494
6499
  break;
@@ -6772,6 +6777,11 @@ var LocalAuthAddon = class extends _camstack_types.BaseAddon {
6772
6777
  this.apiKeyManager = new ApiKeyManager(storageAccess, this.authManager);
6773
6778
  this.scopedTokenManager = new ScopedTokenManager(store);
6774
6779
  try {
6780
+ try {
6781
+ await this.migrateLegacyUserRecords(store);
6782
+ } catch (err) {
6783
+ this.ctx.logger.warn("caps-only migration pass failed; legacy super_admin rows may still exist", { meta: { error: err instanceof Error ? err.message : String(err) } });
6784
+ }
6775
6785
  await this.userManager.ensureAdminExists();
6776
6786
  const liveUsers = await this.userManager.listAll();
6777
6787
  const liveIds = new Set(liveUsers.map((u) => u.id));
@@ -6832,6 +6842,11 @@ var LocalAuthAddon = class extends _camstack_types.BaseAddon {
6832
6842
  await this.userManager.resetPassword(input.id, input.newPassword);
6833
6843
  return { success: true };
6834
6844
  },
6845
+ setUserScopes: async (input) => {
6846
+ if (!this.userManager) throw new Error("User management not available");
6847
+ await this.userManager.update(input.userId, { scopes: input.scopes });
6848
+ return { success: true };
6849
+ },
6835
6850
  validateCredentials: async (input) => {
6836
6851
  if (!this.userManager) return null;
6837
6852
  return await this.userManager.validateCredentials(input.username, input.password) ?? null;
@@ -6898,6 +6913,32 @@ var LocalAuthAddon = class extends _camstack_types.BaseAddon {
6898
6913
  this.apiKeyManager = null;
6899
6914
  this.scopedTokenManager = null;
6900
6915
  }
6916
+ /**
6917
+ * Caps-only auth migration — rewrites legacy `super_admin` rows to
6918
+ * `admin` and backfills the missing `scopes` field with `[]`. Idempotent;
6919
+ * a re-run sees no rows needing changes.
6920
+ */
6921
+ async migrateLegacyUserRecords(store) {
6922
+ const results = await store.query.query({ collection: "users" });
6923
+ let migrated = 0;
6924
+ for (const row of results) {
6925
+ const data = row.data;
6926
+ const needsRoleRewrite = (typeof data["role"] === "string" ? data["role"] : null) === "super_admin";
6927
+ const needsScopesBackfill = !("scopes" in data);
6928
+ if (!needsRoleRewrite && !needsScopesBackfill) continue;
6929
+ const next = { ...data };
6930
+ if (needsRoleRewrite) next["role"] = "admin";
6931
+ if (needsScopesBackfill) next["scopes"] = [];
6932
+ next["updatedAt"] = Date.now();
6933
+ await store.update.mutate({
6934
+ collection: "users",
6935
+ id: row.id,
6936
+ data: next
6937
+ });
6938
+ migrated++;
6939
+ }
6940
+ if (migrated > 0) this.ctx.logger.info("caps-only auth migration: rewrote legacy user records", { meta: { count: migrated } });
6941
+ }
6901
6942
  };
6902
6943
  //#endregion
6903
6944
  exports.ApiKeyManager = ApiKeyManager;