scope.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // SCOPE_SEED defines the basic scope structure.
  2. // When you need to set different permissions for Admin and User
  3. // on specific endpoints (like /me), use SCOPE rather than modifying SCOPE_SEED.
  4. // If you want to add a new scope, you only need to add a new key to the SCOPE_SEED object.
  5. // Change translation file contents (accesstoken_scopes_desc) when scope structure is modified
  6. const SCOPE_SEED_ADMIN = {
  7. admin: {
  8. top: {},
  9. app: {},
  10. security: {},
  11. markdown: {},
  12. customize: {},
  13. import_data: {},
  14. export_data: {},
  15. data_transfer: {},
  16. external_notification: {},
  17. slack_integration: {},
  18. legacy_slack_integration: {},
  19. user_management: {},
  20. user_group_management: {},
  21. audit_log: {},
  22. plugin: {},
  23. ai_integration: {},
  24. full_text_search: {},
  25. },
  26. } as const;
  27. const SCOPE_SEED_USER = {
  28. user_settings: {
  29. info: {},
  30. external_account: {},
  31. password: {},
  32. api: {
  33. api_token: {},
  34. access_token: {},
  35. },
  36. in_app_notification: {},
  37. other: {},
  38. },
  39. features: {
  40. ai_assistant: {},
  41. page: {},
  42. share_link: {},
  43. bookmark: {},
  44. attachment: {},
  45. page_bulk_export: {},
  46. },
  47. } as const;
  48. const SCOPE_SEED = {
  49. ...SCOPE_SEED_ADMIN,
  50. ...SCOPE_SEED_USER,
  51. } as const;
  52. export const ACTION = {
  53. READ: 'read',
  54. WRITE: 'write',
  55. } as const;
  56. type ACTION_TYPE = (typeof ACTION)[keyof typeof ACTION];
  57. export const ALL_SIGN = '*';
  58. const SCOPE_SEED_WITH_ACTION = Object.values(ACTION).reduce(
  59. (acc, action) => {
  60. acc[action] = SCOPE_SEED;
  61. return acc;
  62. },
  63. {} as Record<ACTION_TYPE, typeof SCOPE_SEED>,
  64. );
  65. type FlattenObject<T> = {
  66. [K in keyof T]: T[K] extends object
  67. ? keyof T[K] extends never
  68. ? K
  69. : `${K & string}:${FlattenObject<T[K]> & string}`
  70. : K;
  71. }[keyof T];
  72. type AddAllToScope<S extends string> = S extends `${infer X}:${infer Y}`
  73. ? `${X}:${typeof ALL_SIGN}` | `${X}:${AddAllToScope<Y>}` | S
  74. : S;
  75. type ScopeOnly = FlattenObject<typeof SCOPE_SEED_WITH_ACTION>;
  76. type ScopeWithAll = AddAllToScope<ScopeOnly>;
  77. export type Scope = ScopeOnly | ScopeWithAll;
  78. // ScopeConstants type definition
  79. type ScopeConstantLeaf = Scope;
  80. type ScopeConstantNode<T> = {
  81. [K in keyof T as Uppercase<string & K>]: T[K] extends object
  82. ? keyof T[K] extends never
  83. ? ScopeConstantLeaf
  84. : ScopeConstantNode<T[K]> & { ALL: Scope }
  85. : ScopeConstantLeaf;
  86. };
  87. type ScopeConstantType = {
  88. [A in keyof typeof SCOPE_SEED_WITH_ACTION as Uppercase<
  89. string & A
  90. >]: ScopeConstantNode<typeof SCOPE_SEED> & { ALL: Scope };
  91. };
  92. const buildScopeConstants = (): ScopeConstantType => {
  93. const result = {} as Partial<ScopeConstantType>;
  94. const processObject = (
  95. // biome-ignore lint/suspicious/noExplicitAny: ignore
  96. obj: Record<string, any>,
  97. path: string[] = [],
  98. // biome-ignore lint/suspicious/noExplicitAny: ignore
  99. resultObj: Record<string, any>,
  100. ) => {
  101. for (const [key, value] of Object.entries(obj)) {
  102. const upperKey = key.toUpperCase();
  103. const currentPath = [...path, key];
  104. const scopePath = currentPath.join(':');
  105. if (value == null) {
  106. continue; // Changed from 'return' to 'continue' to match the loop behavior
  107. }
  108. if (typeof value === 'object' && Object.keys(value).length === 0) {
  109. resultObj[upperKey] = `${scopePath}` as Scope;
  110. } else if (typeof value === 'object') {
  111. resultObj[upperKey] = {
  112. ALL: `${scopePath}:${ALL_SIGN}` as Scope,
  113. };
  114. processObject(value, currentPath, resultObj[upperKey]);
  115. }
  116. }
  117. };
  118. processObject(SCOPE_SEED_WITH_ACTION, [], result);
  119. return result as ScopeConstantType;
  120. };
  121. export const SCOPE = buildScopeConstants();