@camstack/core 0.1.29 → 0.1.31

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.
@@ -6253,6 +6253,7 @@ var UserManager = class {
6253
6253
  role: input.role,
6254
6254
  allowedProviders: input.allowedProviders ?? "*",
6255
6255
  allowedDevices: input.allowedDevices ?? {},
6256
+ scopes: input.scopes ?? [],
6256
6257
  createdAt: now,
6257
6258
  updatedAt: now
6258
6259
  };
@@ -6337,7 +6338,7 @@ var UserManager = class {
6337
6338
  await this.create({
6338
6339
  username: adminUsername,
6339
6340
  password: adminPassword,
6340
- role: "super_admin",
6341
+ role: "admin",
6341
6342
  allowedProviders: "*",
6342
6343
  allowedDevices: {}
6343
6344
  });
@@ -6476,14 +6477,18 @@ var ScopedTokenManager = class {
6476
6477
  this.updateLastUsed(record.id).catch(() => {});
6477
6478
  return record;
6478
6479
  }
6479
- matchesScope(token, addonId, routePath, capability) {
6480
+ /**
6481
+ * Coarse scope match — checks only `addonId` / `capability` (no
6482
+ * `route-prefix` after the caps-only migration). Used by addon-route
6483
+ * HTTP handlers that need a quick allow/deny before the per-method
6484
+ * `access` check kicks in via `METHOD_ACCESS_MAP` in
6485
+ * `protectedProcedure`.
6486
+ */
6487
+ matchesScope(token, addonId, capability) {
6480
6488
  for (const scope of token.scopes) switch (scope.type) {
6481
6489
  case "addon":
6482
6490
  if (addonId && scope.target === addonId) return true;
6483
6491
  break;
6484
- case "route-prefix":
6485
- if (routePath && routePath.startsWith(scope.target)) return true;
6486
- break;
6487
6492
  case "capability":
6488
6493
  if (capability && scope.target === capability) return true;
6489
6494
  break;
@@ -6767,6 +6772,11 @@ var LocalAuthAddon = class extends BaseAddon {
6767
6772
  this.apiKeyManager = new ApiKeyManager(storageAccess, this.authManager);
6768
6773
  this.scopedTokenManager = new ScopedTokenManager(store);
6769
6774
  try {
6775
+ try {
6776
+ await this.migrateLegacyUserRecords(store);
6777
+ } catch (err) {
6778
+ 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) } });
6779
+ }
6770
6780
  await this.userManager.ensureAdminExists();
6771
6781
  const liveUsers = await this.userManager.listAll();
6772
6782
  const liveIds = new Set(liveUsers.map((u) => u.id));
@@ -6827,6 +6837,11 @@ var LocalAuthAddon = class extends BaseAddon {
6827
6837
  await this.userManager.resetPassword(input.id, input.newPassword);
6828
6838
  return { success: true };
6829
6839
  },
6840
+ setUserScopes: async (input) => {
6841
+ if (!this.userManager) throw new Error("User management not available");
6842
+ await this.userManager.update(input.userId, { scopes: input.scopes });
6843
+ return { success: true };
6844
+ },
6830
6845
  validateCredentials: async (input) => {
6831
6846
  if (!this.userManager) return null;
6832
6847
  return await this.userManager.validateCredentials(input.username, input.password) ?? null;
@@ -6893,6 +6908,32 @@ var LocalAuthAddon = class extends BaseAddon {
6893
6908
  this.apiKeyManager = null;
6894
6909
  this.scopedTokenManager = null;
6895
6910
  }
6911
+ /**
6912
+ * Caps-only auth migration — rewrites legacy `super_admin` rows to
6913
+ * `admin` and backfills the missing `scopes` field with `[]`. Idempotent;
6914
+ * a re-run sees no rows needing changes.
6915
+ */
6916
+ async migrateLegacyUserRecords(store) {
6917
+ const results = await store.query.query({ collection: "users" });
6918
+ let migrated = 0;
6919
+ for (const row of results) {
6920
+ const data = row.data;
6921
+ const needsRoleRewrite = (typeof data["role"] === "string" ? data["role"] : null) === "super_admin";
6922
+ const needsScopesBackfill = !("scopes" in data);
6923
+ if (!needsRoleRewrite && !needsScopesBackfill) continue;
6924
+ const next = { ...data };
6925
+ if (needsRoleRewrite) next["role"] = "admin";
6926
+ if (needsScopesBackfill) next["scopes"] = [];
6927
+ next["updatedAt"] = Date.now();
6928
+ await store.update.mutate({
6929
+ collection: "users",
6930
+ id: row.id,
6931
+ data: next
6932
+ });
6933
+ migrated++;
6934
+ }
6935
+ if (migrated > 0) this.ctx.logger.info("caps-only auth migration: rewrote legacy user records", { meta: { count: migrated } });
6936
+ }
6896
6937
  };
6897
6938
  //#endregion
6898
6939
  export { LocalAuthAddon, LocalAuthAddon as default, AuthManager as i, ApiKeyManager as n, UserManager as r, ScopedTokenManager as t };