@10x-media/impersonation 0.1.0-beta.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.
Files changed (163) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +49 -0
  4. package/dist/access/filterTargets.js +51 -0
  5. package/dist/access/filterTargets.js.map +1 -0
  6. package/dist/auth/cookies.js +49 -0
  7. package/dist/auth/cookies.js.map +1 -0
  8. package/dist/auth/expiryCookies.js +59 -0
  9. package/dist/auth/expiryCookies.js.map +1 -0
  10. package/dist/auth/issue.js +126 -0
  11. package/dist/auth/issue.js.map +1 -0
  12. package/dist/auth/mode.js +69 -0
  13. package/dist/auth/mode.js.map +1 -0
  14. package/dist/auth/origin.js +55 -0
  15. package/dist/auth/origin.js.map +1 -0
  16. package/dist/auth/revoke.js +24 -0
  17. package/dist/auth/revoke.js.map +1 -0
  18. package/dist/auth/tenantCookie.js +74 -0
  19. package/dist/auth/tenantCookie.js.map +1 -0
  20. package/dist/endpoints/codes.d.ts +6 -0
  21. package/dist/endpoints/current.js +66 -0
  22. package/dist/endpoints/current.js.map +1 -0
  23. package/dist/endpoints/exit.js +242 -0
  24. package/dist/endpoints/exit.js.map +1 -0
  25. package/dist/endpoints/shared.js +76 -0
  26. package/dist/endpoints/shared.js.map +1 -0
  27. package/dist/endpoints/start.js +332 -0
  28. package/dist/endpoints/start.js.map +1 -0
  29. package/dist/endpoints/terminate.js +73 -0
  30. package/dist/endpoints/terminate.js.map +1 -0
  31. package/dist/exports/client.d.ts +9 -0
  32. package/dist/exports/client.js +10 -0
  33. package/dist/exports/i18n.d.ts +3 -0
  34. package/dist/exports/i18n.js +3 -0
  35. package/dist/exports/rsc.d.ts +4 -0
  36. package/dist/exports/rsc.js +4 -0
  37. package/dist/exports/types.d.ts +3 -0
  38. package/dist/exports/types.js +1 -0
  39. package/dist/getImpersonation.d.ts +49 -0
  40. package/dist/getImpersonation.js +78 -0
  41. package/dist/getImpersonation.js.map +1 -0
  42. package/dist/ids.js +27 -0
  43. package/dist/ids.js.map +1 -0
  44. package/dist/index.d.ts +20 -0
  45. package/dist/index.js +55 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/plugin/assertTargets.js +23 -0
  48. package/dist/plugin/assertTargets.js.map +1 -0
  49. package/dist/plugin/constants.d.ts +6 -0
  50. package/dist/plugin/constants.js +20 -0
  51. package/dist/plugin/constants.js.map +1 -0
  52. package/dist/plugin/decorateAuth.js +99 -0
  53. package/dist/plugin/decorateAuth.js.map +1 -0
  54. package/dist/plugin/lookup.js +23 -0
  55. package/dist/plugin/lookup.js.map +1 -0
  56. package/dist/plugin/normalizeOptions.js +83 -0
  57. package/dist/plugin/normalizeOptions.js.map +1 -0
  58. package/dist/plugin/registerAdmin.js +49 -0
  59. package/dist/plugin/registerAdmin.js.map +1 -0
  60. package/dist/plugin/registerCollection.js +183 -0
  61. package/dist/plugin/registerCollection.js.map +1 -0
  62. package/dist/plugin/registerEndpoints.js +19 -0
  63. package/dist/plugin/registerEndpoints.js.map +1 -0
  64. package/dist/plugin/registerHooks.js +59 -0
  65. package/dist/plugin/registerHooks.js.map +1 -0
  66. package/dist/plugin/registerRetention.js +57 -0
  67. package/dist/plugin/registerRetention.js.map +1 -0
  68. package/dist/plugin/registerTranslations.js +19 -0
  69. package/dist/plugin/registerTranslations.js.map +1 -0
  70. package/dist/plugin/registry.js +11 -0
  71. package/dist/plugin/registry.js.map +1 -0
  72. package/dist/plugin/startable.js +21 -0
  73. package/dist/plugin/startable.js.map +1 -0
  74. package/dist/session/close.js +65 -0
  75. package/dist/session/close.js.map +1 -0
  76. package/dist/session/closeStale.d.ts +11 -0
  77. package/dist/session/closeStale.js +65 -0
  78. package/dist/session/closeStale.js.map +1 -0
  79. package/dist/session/locks.js +32 -0
  80. package/dist/session/locks.js.map +1 -0
  81. package/dist/session/resolve.js +91 -0
  82. package/dist/session/resolve.js.map +1 -0
  83. package/dist/translations/ar.js +52 -0
  84. package/dist/translations/ar.js.map +1 -0
  85. package/dist/translations/de.js +52 -0
  86. package/dist/translations/de.js.map +1 -0
  87. package/dist/translations/en.js +52 -0
  88. package/dist/translations/en.js.map +1 -0
  89. package/dist/translations/es.js +52 -0
  90. package/dist/translations/es.js.map +1 -0
  91. package/dist/translations/fr.js +52 -0
  92. package/dist/translations/fr.js.map +1 -0
  93. package/dist/translations/id.js +52 -0
  94. package/dist/translations/id.js.map +1 -0
  95. package/dist/translations/index.d.ts +24 -0
  96. package/dist/translations/index.js +49 -0
  97. package/dist/translations/index.js.map +1 -0
  98. package/dist/translations/keys.d.ts +56 -0
  99. package/dist/translations/keys.js +56 -0
  100. package/dist/translations/keys.js.map +1 -0
  101. package/dist/translations/ko.js +52 -0
  102. package/dist/translations/ko.js.map +1 -0
  103. package/dist/translations/lookup.js +17 -0
  104. package/dist/translations/lookup.js.map +1 -0
  105. package/dist/translations/pt.js +52 -0
  106. package/dist/translations/pt.js.map +1 -0
  107. package/dist/translations/ru.js +52 -0
  108. package/dist/translations/ru.js.map +1 -0
  109. package/dist/translations/server.js +13 -0
  110. package/dist/translations/server.js.map +1 -0
  111. package/dist/translations/uk.js +52 -0
  112. package/dist/translations/uk.js.map +1 -0
  113. package/dist/translations/useTranslation.js +12 -0
  114. package/dist/translations/useTranslation.js.map +1 -0
  115. package/dist/translations/zh.js +52 -0
  116. package/dist/translations/zh.js.map +1 -0
  117. package/dist/types.d.ts +214 -0
  118. package/dist/types.js +11 -0
  119. package/dist/types.js.map +1 -0
  120. package/dist/ui/EndSessionMenuItem.d.ts +5 -0
  121. package/dist/ui/EndSessionMenuItem.js +45 -0
  122. package/dist/ui/EndSessionMenuItem.js.map +1 -0
  123. package/dist/ui/ImpersonateIcon.js +20 -0
  124. package/dist/ui/ImpersonateIcon.js.map +1 -0
  125. package/dist/ui/ImpersonationAction.d.ts +10 -0
  126. package/dist/ui/ImpersonationAction.js +48 -0
  127. package/dist/ui/ImpersonationAction.js.map +1 -0
  128. package/dist/ui/ImpersonationBar.d.ts +36 -0
  129. package/dist/ui/ImpersonationBar.js +357 -0
  130. package/dist/ui/ImpersonationBar.js.map +1 -0
  131. package/dist/ui/ImpersonationConfig.js +25 -0
  132. package/dist/ui/ImpersonationConfig.js.map +1 -0
  133. package/dist/ui/ImpersonationDocumentButton.d.ts +5 -0
  134. package/dist/ui/ImpersonationDocumentButton.js +85 -0
  135. package/dist/ui/ImpersonationDocumentButton.js.map +1 -0
  136. package/dist/ui/ImpersonationFrontendBanner.d.ts +41 -0
  137. package/dist/ui/ImpersonationFrontendBanner.js +58 -0
  138. package/dist/ui/ImpersonationFrontendBanner.js.map +1 -0
  139. package/dist/ui/ImpersonationFrontendExit.d.ts +17 -0
  140. package/dist/ui/ImpersonationFrontendExit.js +45 -0
  141. package/dist/ui/ImpersonationFrontendExit.js.map +1 -0
  142. package/dist/ui/ImpersonationProvider.d.ts +16 -0
  143. package/dist/ui/ImpersonationProvider.js +127 -0
  144. package/dist/ui/ImpersonationProvider.js.map +1 -0
  145. package/dist/ui/ImpersonationSwitcher.d.ts +21 -0
  146. package/dist/ui/ImpersonationSwitcher.js +251 -0
  147. package/dist/ui/ImpersonationSwitcher.js.map +1 -0
  148. package/dist/ui/ImpersonationUserCard.d.ts +31 -0
  149. package/dist/ui/ImpersonationUserCard.js +51 -0
  150. package/dist/ui/ImpersonationUserCard.js.map +1 -0
  151. package/dist/ui/StartConfirmModal.d.ts +28 -0
  152. package/dist/ui/StartConfirmModal.js +65 -0
  153. package/dist/ui/StartConfirmModal.js.map +1 -0
  154. package/dist/ui/api.js +66 -0
  155. package/dist/ui/api.js.map +1 -0
  156. package/dist/ui/barPlacement.js +107 -0
  157. package/dist/ui/barPlacement.js.map +1 -0
  158. package/dist/ui/frontendBanner.css +22 -0
  159. package/dist/ui/impersonation.css +244 -0
  160. package/dist/ui/useImpersonation.d.ts +43 -0
  161. package/dist/ui/useImpersonation.js +36 -0
  162. package/dist/ui/useImpersonation.js.map +1 -0
  163. package/package.json +126 -0
@@ -0,0 +1,52 @@
1
+ import { keys } from "./keys.js";
2
+ //#region src/translations/pt.ts
3
+ const pt = {
4
+ [keys.actingAs]: "A atuar como {{name}}",
5
+ [keys.collectionPlural]: "Sessões de impersonação",
6
+ [keys.collectionSingular]: "Sessão de impersonação",
7
+ [keys.confirm]: "Personificar",
8
+ [keys.confirmTitle]: "Personificar este utilizador?",
9
+ [keys.collapseBar]: "Recolher a barra de impersonação",
10
+ [keys.expandBar]: "Expandir a barra de impersonação",
11
+ [keys.endSession]: "Terminar sessão",
12
+ [keys.endSessionBody]: "Isto termina a impersonação. O alvo volta a ser ele próprio.",
13
+ [keys.errorAlreadyImpersonating]: "Já existe uma impersonação ativa",
14
+ [keys.errorFailed]: "A impersonação falhou",
15
+ [keys.errorForbidden]: "Não permitido",
16
+ [keys.errorImpersonatorGone]: "A sua conta já não está disponível",
17
+ [keys.errorImpersonatorSessionExpired]: "A sessão original expirou. Inicie sessão novamente.",
18
+ [keys.errorInvalidBody]: "Pedido inválido",
19
+ [keys.errorNotImpersonating]: "Sem impersonação ativa",
20
+ [keys.errorOrigin]: "Rejeitado pela verificação de origem",
21
+ [keys.errorReasonRequired]: "É necessário um motivo",
22
+ [keys.errorSelfTarget]: "Não pode impersonar-se a si próprio",
23
+ [keys.errorTargetNotFound]: "Utilizador não encontrado",
24
+ [keys.errorTargetTrashed]: "O utilizador está no lixo",
25
+ [keys.errorTargetUnverified]: "O utilizador não está verificado",
26
+ [keys.errorUnsupportedAuth]: "Este método de autenticação não pode impersonar",
27
+ [keys.errorUnsupportedCollection]: "Esta coleção não pode ser impersonada",
28
+ [keys.fieldEndedAt]: "Terminada",
29
+ [keys.fieldEndedBy]: "Terminada por",
30
+ [keys.fieldImpersonator]: "Impersonador",
31
+ [keys.fieldMode]: "Modo",
32
+ [keys.fieldReason]: "Motivo",
33
+ [keys.fieldStartedAt]: "Início",
34
+ [keys.fieldTarget]: "Alvo",
35
+ [keys.noResults]: "Sem resultados",
36
+ [keys.openDocument]: "Abrir documento",
37
+ [keys.openDrawer]: "Abrir no drawer",
38
+ [keys.openWebsite]: "Abrir site",
39
+ [keys.pluginName]: "Impersonação",
40
+ [keys.reasonLabel]: "Motivo",
41
+ [keys.reasonPlaceholder]: "Motivo opcional",
42
+ [keys.returnTo]: "Voltar a {{name}}",
43
+ [keys.searchByName]: "Pesquisar por nome",
44
+ [keys.sessionActiveOnSite]: "A sessão de {{name}} está ativa no site",
45
+ [keys.sessionEndsAt]: "A sessão termina às {{time}}",
46
+ [keys.sessionEndsIn]: "A sessão termina em {{countdown}}",
47
+ [keys.switchToUser]: "Personificar"
48
+ };
49
+ //#endregion
50
+ export { pt };
51
+
52
+ //# sourceMappingURL=pt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pt.js","names":[],"sources":["../../src/translations/pt.ts"],"sourcesContent":["import { keys, type TranslationKey } from './keys'\n\nexport const pt: Record<TranslationKey, string> = {\n\t[keys.actingAs]: 'A atuar como {{name}}',\n\t[keys.collectionPlural]: 'Sessões de impersonação',\n\t[keys.collectionSingular]: 'Sessão de impersonação',\n\t[keys.confirm]: 'Personificar',\n\t[keys.confirmTitle]: 'Personificar este utilizador?',\n\t[keys.collapseBar]: 'Recolher a barra de impersonação',\n\t[keys.expandBar]: 'Expandir a barra de impersonação',\n\t[keys.endSession]: 'Terminar sessão',\n\t[keys.endSessionBody]: 'Isto termina a impersonação. O alvo volta a ser ele próprio.',\n\t[keys.errorAlreadyImpersonating]: 'Já existe uma impersonação ativa',\n\t[keys.errorFailed]: 'A impersonação falhou',\n\t[keys.errorForbidden]: 'Não permitido',\n\t[keys.errorImpersonatorGone]: 'A sua conta já não está disponível',\n\t[keys.errorImpersonatorSessionExpired]: 'A sessão original expirou. Inicie sessão novamente.',\n\t[keys.errorInvalidBody]: 'Pedido inválido',\n\t[keys.errorNotImpersonating]: 'Sem impersonação ativa',\n\t[keys.errorOrigin]: 'Rejeitado pela verificação de origem',\n\t[keys.errorReasonRequired]: 'É necessário um motivo',\n\t[keys.errorSelfTarget]: 'Não pode impersonar-se a si próprio',\n\t[keys.errorTargetNotFound]: 'Utilizador não encontrado',\n\t[keys.errorTargetTrashed]: 'O utilizador está no lixo',\n\t[keys.errorTargetUnverified]: 'O utilizador não está verificado',\n\t[keys.errorUnsupportedAuth]: 'Este método de autenticação não pode impersonar',\n\t[keys.errorUnsupportedCollection]: 'Esta coleção não pode ser impersonada',\n\t[keys.fieldEndedAt]: 'Terminada',\n\t[keys.fieldEndedBy]: 'Terminada por',\n\t[keys.fieldImpersonator]: 'Impersonador',\n\t[keys.fieldMode]: 'Modo',\n\t[keys.fieldReason]: 'Motivo',\n\t[keys.fieldStartedAt]: 'Início',\n\t[keys.fieldTarget]: 'Alvo',\n\t[keys.noResults]: 'Sem resultados',\n\t[keys.openDocument]: 'Abrir documento',\n\t[keys.openDrawer]: 'Abrir no drawer',\n\t[keys.openWebsite]: 'Abrir site',\n\t[keys.pluginName]: 'Impersonação',\n\t[keys.reasonLabel]: 'Motivo',\n\t[keys.reasonPlaceholder]: 'Motivo opcional',\n\t[keys.returnTo]: 'Voltar a {{name}}',\n\t[keys.searchByName]: 'Pesquisar por nome',\n\t[keys.sessionActiveOnSite]: 'A sessão de {{name}} está ativa no site',\n\t[keys.sessionEndsAt]: 'A sessão termina às {{time}}',\n\t[keys.sessionEndsIn]: 'A sessão termina em {{countdown}}',\n\t[keys.switchToUser]: 'Personificar',\n}\n"],"mappings":";;AAEA,MAAa,KAAqC;EAChD,KAAK,WAAW;EAChB,KAAK,mBAAmB;EACxB,KAAK,qBAAqB;EAC1B,KAAK,UAAU;EACf,KAAK,eAAe;EACpB,KAAK,cAAc;EACnB,KAAK,YAAY;EACjB,KAAK,aAAa;EAClB,KAAK,iBAAiB;EACtB,KAAK,4BAA4B;EACjC,KAAK,cAAc;EACnB,KAAK,iBAAiB;EACtB,KAAK,wBAAwB;EAC7B,KAAK,kCAAkC;EACvC,KAAK,mBAAmB;EACxB,KAAK,wBAAwB;EAC7B,KAAK,cAAc;EACnB,KAAK,sBAAsB;EAC3B,KAAK,kBAAkB;EACvB,KAAK,sBAAsB;EAC3B,KAAK,qBAAqB;EAC1B,KAAK,wBAAwB;EAC7B,KAAK,uBAAuB;EAC5B,KAAK,6BAA6B;EAClC,KAAK,eAAe;EACpB,KAAK,eAAe;EACpB,KAAK,oBAAoB;EACzB,KAAK,YAAY;EACjB,KAAK,cAAc;EACnB,KAAK,iBAAiB;EACtB,KAAK,cAAc;EACnB,KAAK,YAAY;EACjB,KAAK,eAAe;EACpB,KAAK,aAAa;EAClB,KAAK,cAAc;EACnB,KAAK,aAAa;EAClB,KAAK,cAAc;EACnB,KAAK,oBAAoB;EACzB,KAAK,WAAW;EAChB,KAAK,eAAe;EACpB,KAAK,sBAAsB;EAC3B,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;EACrB,KAAK,eAAe;AACtB"}
@@ -0,0 +1,52 @@
1
+ import { keys } from "./keys.js";
2
+ //#region src/translations/ru.ts
3
+ const ru = {
4
+ [keys.actingAs]: "Действует как {{name}}",
5
+ [keys.collectionPlural]: "Сеансы имперсонации",
6
+ [keys.collectionSingular]: "Сеанс имперсонации",
7
+ [keys.confirm]: "Имперсонировать",
8
+ [keys.confirmTitle]: "Имперсонировать этого пользователя?",
9
+ [keys.collapseBar]: "Свернуть панель имперсонации",
10
+ [keys.expandBar]: "Развернуть панель имперсонации",
11
+ [keys.endSession]: "Завершить сеанс",
12
+ [keys.endSessionBody]: "Имперсонация будет завершена. Цель снова войдёт как она сама.",
13
+ [keys.errorAlreadyImpersonating]: "Имперсонация уже идёт",
14
+ [keys.errorFailed]: "Имперсонация не удалась",
15
+ [keys.errorForbidden]: "Не разрешено",
16
+ [keys.errorImpersonatorGone]: "Ваша учётная запись больше недоступна",
17
+ [keys.errorImpersonatorSessionExpired]: "Исходный сеанс истёк. Войдите снова.",
18
+ [keys.errorInvalidBody]: "Неверный запрос",
19
+ [keys.errorNotImpersonating]: "Имперсонация не активна",
20
+ [keys.errorOrigin]: "Отклонено проверкой origin",
21
+ [keys.errorReasonRequired]: "Нужна причина",
22
+ [keys.errorSelfTarget]: "Нельзя имперсонировать себя",
23
+ [keys.errorTargetNotFound]: "Пользователь не найден",
24
+ [keys.errorTargetTrashed]: "Пользователь в корзине",
25
+ [keys.errorTargetUnverified]: "Пользователь не подтверждён",
26
+ [keys.errorUnsupportedAuth]: "Этот способ входа не может имперсонировать",
27
+ [keys.errorUnsupportedCollection]: "Эту коллекцию нельзя имперсонировать",
28
+ [keys.fieldEndedAt]: "Завершён",
29
+ [keys.fieldEndedBy]: "Завершён кем",
30
+ [keys.fieldImpersonator]: "Имперсонатор",
31
+ [keys.fieldMode]: "Режим",
32
+ [keys.fieldReason]: "Причина",
33
+ [keys.fieldStartedAt]: "Начат",
34
+ [keys.fieldTarget]: "Цель",
35
+ [keys.noResults]: "Нет совпадений",
36
+ [keys.openDocument]: "Открыть документ",
37
+ [keys.openDrawer]: "Открыть в панели",
38
+ [keys.openWebsite]: "Открыть сайт",
39
+ [keys.pluginName]: "Имперсонация",
40
+ [keys.reasonLabel]: "Причина",
41
+ [keys.reasonPlaceholder]: "Необязательная причина",
42
+ [keys.returnTo]: "Вернуться к {{name}}",
43
+ [keys.searchByName]: "Поиск по имени",
44
+ [keys.sessionActiveOnSite]: "Сессия {{name}} активна на сайте",
45
+ [keys.sessionEndsAt]: "Сеанс закончится в {{time}}",
46
+ [keys.sessionEndsIn]: "Сессия закончится через {{countdown}}",
47
+ [keys.switchToUser]: "Имперсонировать"
48
+ };
49
+ //#endregion
50
+ export { ru };
51
+
52
+ //# sourceMappingURL=ru.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ru.js","names":[],"sources":["../../src/translations/ru.ts"],"sourcesContent":["import { keys, type TranslationKey } from './keys'\n\nexport const ru: Record<TranslationKey, string> = {\n\t[keys.actingAs]: 'Действует как {{name}}',\n\t[keys.collectionPlural]: 'Сеансы имперсонации',\n\t[keys.collectionSingular]: 'Сеанс имперсонации',\n\t[keys.confirm]: 'Имперсонировать',\n\t[keys.confirmTitle]: 'Имперсонировать этого пользователя?',\n\t[keys.collapseBar]: 'Свернуть панель имперсонации',\n\t[keys.expandBar]: 'Развернуть панель имперсонации',\n\t[keys.endSession]: 'Завершить сеанс',\n\t[keys.endSessionBody]: 'Имперсонация будет завершена. Цель снова войдёт как она сама.',\n\t[keys.errorAlreadyImpersonating]: 'Имперсонация уже идёт',\n\t[keys.errorFailed]: 'Имперсонация не удалась',\n\t[keys.errorForbidden]: 'Не разрешено',\n\t[keys.errorImpersonatorGone]: 'Ваша учётная запись больше недоступна',\n\t[keys.errorImpersonatorSessionExpired]: 'Исходный сеанс истёк. Войдите снова.',\n\t[keys.errorInvalidBody]: 'Неверный запрос',\n\t[keys.errorNotImpersonating]: 'Имперсонация не активна',\n\t[keys.errorOrigin]: 'Отклонено проверкой origin',\n\t[keys.errorReasonRequired]: 'Нужна причина',\n\t[keys.errorSelfTarget]: 'Нельзя имперсонировать себя',\n\t[keys.errorTargetNotFound]: 'Пользователь не найден',\n\t[keys.errorTargetTrashed]: 'Пользователь в корзине',\n\t[keys.errorTargetUnverified]: 'Пользователь не подтверждён',\n\t[keys.errorUnsupportedAuth]: 'Этот способ входа не может имперсонировать',\n\t[keys.errorUnsupportedCollection]: 'Эту коллекцию нельзя имперсонировать',\n\t[keys.fieldEndedAt]: 'Завершён',\n\t[keys.fieldEndedBy]: 'Завершён кем',\n\t[keys.fieldImpersonator]: 'Имперсонатор',\n\t[keys.fieldMode]: 'Режим',\n\t[keys.fieldReason]: 'Причина',\n\t[keys.fieldStartedAt]: 'Начат',\n\t[keys.fieldTarget]: 'Цель',\n\t[keys.noResults]: 'Нет совпадений',\n\t[keys.openDocument]: 'Открыть документ',\n\t[keys.openDrawer]: 'Открыть в панели',\n\t[keys.openWebsite]: 'Открыть сайт',\n\t[keys.pluginName]: 'Имперсонация',\n\t[keys.reasonLabel]: 'Причина',\n\t[keys.reasonPlaceholder]: 'Необязательная причина',\n\t[keys.returnTo]: 'Вернуться к {{name}}',\n\t[keys.searchByName]: 'Поиск по имени',\n\t[keys.sessionActiveOnSite]: 'Сессия {{name}} активна на сайте',\n\t[keys.sessionEndsAt]: 'Сеанс закончится в {{time}}',\n\t[keys.sessionEndsIn]: 'Сессия закончится через {{countdown}}',\n\t[keys.switchToUser]: 'Имперсонировать',\n}\n"],"mappings":";;AAEA,MAAa,KAAqC;EAChD,KAAK,WAAW;EAChB,KAAK,mBAAmB;EACxB,KAAK,qBAAqB;EAC1B,KAAK,UAAU;EACf,KAAK,eAAe;EACpB,KAAK,cAAc;EACnB,KAAK,YAAY;EACjB,KAAK,aAAa;EAClB,KAAK,iBAAiB;EACtB,KAAK,4BAA4B;EACjC,KAAK,cAAc;EACnB,KAAK,iBAAiB;EACtB,KAAK,wBAAwB;EAC7B,KAAK,kCAAkC;EACvC,KAAK,mBAAmB;EACxB,KAAK,wBAAwB;EAC7B,KAAK,cAAc;EACnB,KAAK,sBAAsB;EAC3B,KAAK,kBAAkB;EACvB,KAAK,sBAAsB;EAC3B,KAAK,qBAAqB;EAC1B,KAAK,wBAAwB;EAC7B,KAAK,uBAAuB;EAC5B,KAAK,6BAA6B;EAClC,KAAK,eAAe;EACpB,KAAK,eAAe;EACpB,KAAK,oBAAoB;EACzB,KAAK,YAAY;EACjB,KAAK,cAAc;EACnB,KAAK,iBAAiB;EACtB,KAAK,cAAc;EACnB,KAAK,YAAY;EACjB,KAAK,eAAe;EACpB,KAAK,aAAa;EAClB,KAAK,cAAc;EACnB,KAAK,aAAa;EAClB,KAAK,cAAc;EACnB,KAAK,oBAAoB;EACzB,KAAK,WAAW;EAChB,KAAK,eAAe;EACpB,KAAK,sBAAsB;EAC3B,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;EACrB,KAAK,eAAe;AACtB"}
@@ -0,0 +1,13 @@
1
+ //#region src/translations/server.ts
2
+ /**
3
+ * Adapt a Payload request `t` (typed to core keys only) so it also accepts this
4
+ * plugin's keys. They are registered at config time and resolve at runtime; the
5
+ * cast only widens the compile-time key domain.
6
+ */
7
+ const asTranslate = (t) => t;
8
+ /** A field `label`/`description` backed by a typed key, resolved per request. */
9
+ const labelForKey = (key) => ({ t }) => asTranslate(t)(key);
10
+ //#endregion
11
+ export { labelForKey };
12
+
13
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","names":[],"sources":["../../src/translations/server.ts"],"sourcesContent":["import type { LabelFunction } from 'payload'\n\nimport type { TranslationKey } from './keys'\n\n/** A `t`-like function narrowed to this plugin's typed keys. */\ntype Translate = (key: TranslationKey) => string\n\n/**\n * Adapt a Payload request `t` (typed to core keys only) so it also accepts this\n * plugin's keys. They are registered at config time and resolve at runtime; the\n * cast only widens the compile-time key domain.\n */\nexport const asTranslate = (t: unknown): Translate => t as Translate\n\n/** A field `label`/`description` backed by a typed key, resolved per request. */\nexport const labelForKey =\n\t(key: TranslationKey): LabelFunction =>\n\t({ t }) =>\n\t\tasTranslate(t)(key)\n"],"mappings":";;;;;;AAYA,MAAa,eAAe,MAA0B;;AAGtD,MAAa,eACX,SACA,EAAE,QACF,YAAY,CAAC,EAAE,GAAG"}
@@ -0,0 +1,52 @@
1
+ import { keys } from "./keys.js";
2
+ //#region src/translations/uk.ts
3
+ const uk = {
4
+ [keys.actingAs]: "Діє як {{name}}",
5
+ [keys.collectionPlural]: "Сеанси імперсонації",
6
+ [keys.collectionSingular]: "Сеанс імперсонації",
7
+ [keys.confirm]: "Імперсонувати",
8
+ [keys.confirmTitle]: "Імперсонувати цього користувача?",
9
+ [keys.collapseBar]: "Згорнути панель імперсонації",
10
+ [keys.expandBar]: "Розгорнути панель імперсонації",
11
+ [keys.endSession]: "Завершити сеанс",
12
+ [keys.endSessionBody]: "Імперсонацію буде завершено. Ціль знову ввійде як вона сама.",
13
+ [keys.errorAlreadyImpersonating]: "Імперсонація вже триває",
14
+ [keys.errorFailed]: "Імперсонація не вдалася",
15
+ [keys.errorForbidden]: "Не дозволено",
16
+ [keys.errorImpersonatorGone]: "Ваш обліковий запис більше недоступний",
17
+ [keys.errorImpersonatorSessionExpired]: "Початковий сеанс закінчився. Увійдіть знову.",
18
+ [keys.errorInvalidBody]: "Невірний запит",
19
+ [keys.errorNotImpersonating]: "Імперсонація не активна",
20
+ [keys.errorOrigin]: "Відхилено перевіркою origin",
21
+ [keys.errorReasonRequired]: "Потрібна причина",
22
+ [keys.errorSelfTarget]: "Не можна імперсонувати себе",
23
+ [keys.errorTargetNotFound]: "Користувача не знайдено",
24
+ [keys.errorTargetTrashed]: "Користувач у кошику",
25
+ [keys.errorTargetUnverified]: "Користувача не підтверджено",
26
+ [keys.errorUnsupportedAuth]: "Цей спосіб входу не може імперсонувати",
27
+ [keys.errorUnsupportedCollection]: "Цю колекцію не можна імперсонувати",
28
+ [keys.fieldEndedAt]: "Завершено",
29
+ [keys.fieldEndedBy]: "Завершено ким",
30
+ [keys.fieldImpersonator]: "Імперсонатор",
31
+ [keys.fieldMode]: "Режим",
32
+ [keys.fieldReason]: "Причина",
33
+ [keys.fieldStartedAt]: "Почато",
34
+ [keys.fieldTarget]: "Ціль",
35
+ [keys.noResults]: "Немає збігів",
36
+ [keys.openDocument]: "Відкрити документ",
37
+ [keys.openDrawer]: "Відкрити в панелі",
38
+ [keys.openWebsite]: "Відкрити сайт",
39
+ [keys.pluginName]: "Імперсонація",
40
+ [keys.reasonLabel]: "Причина",
41
+ [keys.reasonPlaceholder]: "Необов'язкова причина",
42
+ [keys.returnTo]: "Повернутися до {{name}}",
43
+ [keys.searchByName]: "Пошук за іменем",
44
+ [keys.sessionActiveOnSite]: "Сесія {{name}} активна на сайті",
45
+ [keys.sessionEndsAt]: "Сеанс закінчиться о {{time}}",
46
+ [keys.sessionEndsIn]: "Сесія завершиться через {{countdown}}",
47
+ [keys.switchToUser]: "Імперсонувати"
48
+ };
49
+ //#endregion
50
+ export { uk };
51
+
52
+ //# sourceMappingURL=uk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uk.js","names":[],"sources":["../../src/translations/uk.ts"],"sourcesContent":["import { keys, type TranslationKey } from './keys'\n\nexport const uk: Record<TranslationKey, string> = {\n\t[keys.actingAs]: 'Діє як {{name}}',\n\t[keys.collectionPlural]: 'Сеанси імперсонації',\n\t[keys.collectionSingular]: 'Сеанс імперсонації',\n\t[keys.confirm]: 'Імперсонувати',\n\t[keys.confirmTitle]: 'Імперсонувати цього користувача?',\n\t[keys.collapseBar]: 'Згорнути панель імперсонації',\n\t[keys.expandBar]: 'Розгорнути панель імперсонації',\n\t[keys.endSession]: 'Завершити сеанс',\n\t[keys.endSessionBody]: 'Імперсонацію буде завершено. Ціль знову ввійде як вона сама.',\n\t[keys.errorAlreadyImpersonating]: 'Імперсонація вже триває',\n\t[keys.errorFailed]: 'Імперсонація не вдалася',\n\t[keys.errorForbidden]: 'Не дозволено',\n\t[keys.errorImpersonatorGone]: 'Ваш обліковий запис більше недоступний',\n\t[keys.errorImpersonatorSessionExpired]: 'Початковий сеанс закінчився. Увійдіть знову.',\n\t[keys.errorInvalidBody]: 'Невірний запит',\n\t[keys.errorNotImpersonating]: 'Імперсонація не активна',\n\t[keys.errorOrigin]: 'Відхилено перевіркою origin',\n\t[keys.errorReasonRequired]: 'Потрібна причина',\n\t[keys.errorSelfTarget]: 'Не можна імперсонувати себе',\n\t[keys.errorTargetNotFound]: 'Користувача не знайдено',\n\t[keys.errorTargetTrashed]: 'Користувач у кошику',\n\t[keys.errorTargetUnverified]: 'Користувача не підтверджено',\n\t[keys.errorUnsupportedAuth]: 'Цей спосіб входу не може імперсонувати',\n\t[keys.errorUnsupportedCollection]: 'Цю колекцію не можна імперсонувати',\n\t[keys.fieldEndedAt]: 'Завершено',\n\t[keys.fieldEndedBy]: 'Завершено ким',\n\t[keys.fieldImpersonator]: 'Імперсонатор',\n\t[keys.fieldMode]: 'Режим',\n\t[keys.fieldReason]: 'Причина',\n\t[keys.fieldStartedAt]: 'Почато',\n\t[keys.fieldTarget]: 'Ціль',\n\t[keys.noResults]: 'Немає збігів',\n\t[keys.openDocument]: 'Відкрити документ',\n\t[keys.openDrawer]: 'Відкрити в панелі',\n\t[keys.openWebsite]: 'Відкрити сайт',\n\t[keys.pluginName]: 'Імперсонація',\n\t[keys.reasonLabel]: 'Причина',\n\t[keys.reasonPlaceholder]: \"Необов'язкова причина\",\n\t[keys.returnTo]: 'Повернутися до {{name}}',\n\t[keys.searchByName]: 'Пошук за іменем',\n\t[keys.sessionActiveOnSite]: 'Сесія {{name}} активна на сайті',\n\t[keys.sessionEndsAt]: 'Сеанс закінчиться о {{time}}',\n\t[keys.sessionEndsIn]: 'Сесія завершиться через {{countdown}}',\n\t[keys.switchToUser]: 'Імперсонувати',\n}\n"],"mappings":";;AAEA,MAAa,KAAqC;EAChD,KAAK,WAAW;EAChB,KAAK,mBAAmB;EACxB,KAAK,qBAAqB;EAC1B,KAAK,UAAU;EACf,KAAK,eAAe;EACpB,KAAK,cAAc;EACnB,KAAK,YAAY;EACjB,KAAK,aAAa;EAClB,KAAK,iBAAiB;EACtB,KAAK,4BAA4B;EACjC,KAAK,cAAc;EACnB,KAAK,iBAAiB;EACtB,KAAK,wBAAwB;EAC7B,KAAK,kCAAkC;EACvC,KAAK,mBAAmB;EACxB,KAAK,wBAAwB;EAC7B,KAAK,cAAc;EACnB,KAAK,sBAAsB;EAC3B,KAAK,kBAAkB;EACvB,KAAK,sBAAsB;EAC3B,KAAK,qBAAqB;EAC1B,KAAK,wBAAwB;EAC7B,KAAK,uBAAuB;EAC5B,KAAK,6BAA6B;EAClC,KAAK,eAAe;EACpB,KAAK,eAAe;EACpB,KAAK,oBAAoB;EACzB,KAAK,YAAY;EACjB,KAAK,cAAc;EACnB,KAAK,iBAAiB;EACtB,KAAK,cAAc;EACnB,KAAK,YAAY;EACjB,KAAK,eAAe;EACpB,KAAK,aAAa;EAClB,KAAK,cAAc;EACnB,KAAK,aAAa;EAClB,KAAK,cAAc;EACnB,KAAK,oBAAoB;EACzB,KAAK,WAAW;EAChB,KAAK,eAAe;EACpB,KAAK,sBAAsB;EAC3B,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;EACrB,KAAK,eAAe;AACtB"}
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { useTranslation } from "@payloadcms/ui";
3
+ //#region src/translations/useTranslation.ts
4
+ /**
5
+ * `useTranslation` bound to this plugin's keys, so `t(keys.X)` typechecks without
6
+ * a per-call `@ts-expect-error`. Returns Payload's `{ t, i18n }` unchanged.
7
+ */
8
+ const useTranslation$1 = () => useTranslation();
9
+ //#endregion
10
+ export { useTranslation$1 as useTranslation };
11
+
12
+ //# sourceMappingURL=useTranslation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTranslation.js","names":["useTranslation","usePayloadTranslation"],"sources":["../../src/translations/useTranslation.ts"],"sourcesContent":["'use client'\n\nimport { useTranslation as usePayloadTranslation } from '@payloadcms/ui'\n\nimport type { TranslationKey } from './keys'\n\n/**\n * `useTranslation` bound to this plugin's keys, so `t(keys.X)` typechecks without\n * a per-call `@ts-expect-error`. Returns Payload's `{ t, i18n }` unchanged.\n */\nexport const useTranslation = () => usePayloadTranslation<Record<string, never>, TranslationKey>()\n"],"mappings":";;;;;;;AAUA,MAAaA,yBAAuBC,eAA6D"}
@@ -0,0 +1,52 @@
1
+ import { keys } from "./keys.js";
2
+ //#region src/translations/zh.ts
3
+ const zh = {
4
+ [keys.actingAs]: "正在以 {{name}} 的身份操作",
5
+ [keys.collectionPlural]: "模拟登录会话",
6
+ [keys.collectionSingular]: "模拟登录会话",
7
+ [keys.confirm]: "模拟登录",
8
+ [keys.confirmTitle]: "模拟此用户?",
9
+ [keys.collapseBar]: "收起模拟登录条",
10
+ [keys.expandBar]: "展开模拟登录条",
11
+ [keys.endSession]: "结束会话",
12
+ [keys.endSessionBody]: "这将结束模拟登录。目标将重新以自己的身份登录。",
13
+ [keys.errorAlreadyImpersonating]: "已在模拟登录中",
14
+ [keys.errorFailed]: "模拟登录失败",
15
+ [keys.errorForbidden]: "不允许",
16
+ [keys.errorImpersonatorGone]: "您的账户已不可用",
17
+ [keys.errorImpersonatorSessionExpired]: "原始会话已过期,请重新登录。",
18
+ [keys.errorInvalidBody]: "无效请求",
19
+ [keys.errorNotImpersonating]: "当前没有模拟登录",
20
+ [keys.errorOrigin]: "未通过来源检查",
21
+ [keys.errorReasonRequired]: "必须填写原因",
22
+ [keys.errorSelfTarget]: "不能模拟登录自己",
23
+ [keys.errorTargetNotFound]: "找不到用户",
24
+ [keys.errorTargetTrashed]: "用户在回收站中",
25
+ [keys.errorTargetUnverified]: "用户未验证",
26
+ [keys.errorUnsupportedAuth]: "此认证方式不能模拟登录",
27
+ [keys.errorUnsupportedCollection]: "此集合不能被模拟登录",
28
+ [keys.fieldEndedAt]: "结束时间",
29
+ [keys.fieldEndedBy]: "结束方式",
30
+ [keys.fieldImpersonator]: "操作者",
31
+ [keys.fieldMode]: "模式",
32
+ [keys.fieldReason]: "原因",
33
+ [keys.fieldStartedAt]: "开始时间",
34
+ [keys.fieldTarget]: "目标",
35
+ [keys.noResults]: "没有匹配的用户",
36
+ [keys.openDocument]: "打开文档",
37
+ [keys.openDrawer]: "在抽屉中打开",
38
+ [keys.openWebsite]: "打开网站",
39
+ [keys.pluginName]: "模拟登录",
40
+ [keys.reasonLabel]: "原因",
41
+ [keys.reasonPlaceholder]: "可选原因",
42
+ [keys.returnTo]: "返回 {{name}}",
43
+ [keys.searchByName]: "按名称搜索",
44
+ [keys.sessionActiveOnSite]: "{{name}} 的会话在网站上处于活动状态",
45
+ [keys.sessionEndsAt]: "会话将于 {{time}} 结束",
46
+ [keys.sessionEndsIn]: "会话将在 {{countdown}} 后结束",
47
+ [keys.switchToUser]: "模拟登录"
48
+ };
49
+ //#endregion
50
+ export { zh };
51
+
52
+ //# sourceMappingURL=zh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zh.js","names":[],"sources":["../../src/translations/zh.ts"],"sourcesContent":["import { keys, type TranslationKey } from './keys'\n\nexport const zh: Record<TranslationKey, string> = {\n\t[keys.actingAs]: '正在以 {{name}} 的身份操作',\n\t[keys.collectionPlural]: '模拟登录会话',\n\t[keys.collectionSingular]: '模拟登录会话',\n\t[keys.confirm]: '模拟登录',\n\t[keys.confirmTitle]: '模拟此用户?',\n\t[keys.collapseBar]: '收起模拟登录条',\n\t[keys.expandBar]: '展开模拟登录条',\n\t[keys.endSession]: '结束会话',\n\t[keys.endSessionBody]: '这将结束模拟登录。目标将重新以自己的身份登录。',\n\t[keys.errorAlreadyImpersonating]: '已在模拟登录中',\n\t[keys.errorFailed]: '模拟登录失败',\n\t[keys.errorForbidden]: '不允许',\n\t[keys.errorImpersonatorGone]: '您的账户已不可用',\n\t[keys.errorImpersonatorSessionExpired]: '原始会话已过期,请重新登录。',\n\t[keys.errorInvalidBody]: '无效请求',\n\t[keys.errorNotImpersonating]: '当前没有模拟登录',\n\t[keys.errorOrigin]: '未通过来源检查',\n\t[keys.errorReasonRequired]: '必须填写原因',\n\t[keys.errorSelfTarget]: '不能模拟登录自己',\n\t[keys.errorTargetNotFound]: '找不到用户',\n\t[keys.errorTargetTrashed]: '用户在回收站中',\n\t[keys.errorTargetUnverified]: '用户未验证',\n\t[keys.errorUnsupportedAuth]: '此认证方式不能模拟登录',\n\t[keys.errorUnsupportedCollection]: '此集合不能被模拟登录',\n\t[keys.fieldEndedAt]: '结束时间',\n\t[keys.fieldEndedBy]: '结束方式',\n\t[keys.fieldImpersonator]: '操作者',\n\t[keys.fieldMode]: '模式',\n\t[keys.fieldReason]: '原因',\n\t[keys.fieldStartedAt]: '开始时间',\n\t[keys.fieldTarget]: '目标',\n\t[keys.noResults]: '没有匹配的用户',\n\t[keys.openDocument]: '打开文档',\n\t[keys.openDrawer]: '在抽屉中打开',\n\t[keys.openWebsite]: '打开网站',\n\t[keys.pluginName]: '模拟登录',\n\t[keys.reasonLabel]: '原因',\n\t[keys.reasonPlaceholder]: '可选原因',\n\t[keys.returnTo]: '返回 {{name}}',\n\t[keys.searchByName]: '按名称搜索',\n\t[keys.sessionActiveOnSite]: '{{name}} 的会话在网站上处于活动状态',\n\t[keys.sessionEndsAt]: '会话将于 {{time}} 结束',\n\t[keys.sessionEndsIn]: '会话将在 {{countdown}} 后结束',\n\t[keys.switchToUser]: '模拟登录',\n}\n"],"mappings":";;AAEA,MAAa,KAAqC;EAChD,KAAK,WAAW;EAChB,KAAK,mBAAmB;EACxB,KAAK,qBAAqB;EAC1B,KAAK,UAAU;EACf,KAAK,eAAe;EACpB,KAAK,cAAc;EACnB,KAAK,YAAY;EACjB,KAAK,aAAa;EAClB,KAAK,iBAAiB;EACtB,KAAK,4BAA4B;EACjC,KAAK,cAAc;EACnB,KAAK,iBAAiB;EACtB,KAAK,wBAAwB;EAC7B,KAAK,kCAAkC;EACvC,KAAK,mBAAmB;EACxB,KAAK,wBAAwB;EAC7B,KAAK,cAAc;EACnB,KAAK,sBAAsB;EAC3B,KAAK,kBAAkB;EACvB,KAAK,sBAAsB;EAC3B,KAAK,qBAAqB;EAC1B,KAAK,wBAAwB;EAC7B,KAAK,uBAAuB;EAC5B,KAAK,6BAA6B;EAClC,KAAK,eAAe;EACpB,KAAK,eAAe;EACpB,KAAK,oBAAoB;EACzB,KAAK,YAAY;EACjB,KAAK,cAAc;EACnB,KAAK,iBAAiB;EACtB,KAAK,cAAc;EACnB,KAAK,YAAY;EACjB,KAAK,eAAe;EACpB,KAAK,aAAa;EAClB,KAAK,cAAc;EACnB,KAAK,aAAa;EAClB,KAAK,cAAc;EACnB,KAAK,oBAAoB;EACzB,KAAK,WAAW;EAChB,KAAK,eAAe;EACpB,KAAK,sBAAsB;EAC3B,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;EACrB,KAAK,eAAe;AACtB"}
@@ -0,0 +1,214 @@
1
+ import { FailureCode } from "./endpoints/codes.js";
2
+ import { TranslationsOption } from "./translations/index.js";
3
+ import { Access, CollectionConfig, CollectionSlug, Payload, PayloadComponent, PayloadRequest, TypedUser, Where } from "payload";
4
+
5
+ //#region src/types.d.ts
6
+ type ImpersonationMode = 'parallel' | 'swap';
7
+ type EndedBy = 'exit' | 'expired' | 'failed' | 'impersonatorGone' | 'logout' | 'targetGone' | 'terminated';
8
+ type ImpersonationActor = {
9
+ absoluteExpiresAt?: null | string;
10
+ id: number | string;
11
+ impersonator: {
12
+ collection: string;
13
+ id: number | string;
14
+ };
15
+ impersonatorEmail?: null | string;
16
+ impersonatorLocale?: null | string;
17
+ impersonatorTitle?: null | string;
18
+ mode: ImpersonationMode;
19
+ reason?: null | string;
20
+ startedAt: string;
21
+ target: {
22
+ collection: string;
23
+ id: number | string;
24
+ };
25
+ targetEmail?: null | string;
26
+ targetTitle?: null | string;
27
+ };
28
+ type ImpersonateAccessArgs = {
29
+ req: PayloadRequest;
30
+ target: Record<string, unknown>;
31
+ targetCollection: CollectionSlug;
32
+ };
33
+ /**
34
+ * Host gate for starting a session. Only the literal `true` allows. `false`,
35
+ * `undefined`, and a Payload `Where` object all deny. A `Where` is never treated
36
+ * as allow-all.
37
+ */
38
+ type ImpersonateAccess = (args: ImpersonateAccessArgs) => boolean | Promise<boolean>;
39
+ type BooleanAccess = (args: {
40
+ req: PayloadRequest;
41
+ }) => boolean | Promise<boolean>;
42
+ /**
43
+ * Which users the switcher (and document action) should offer. This is UX only.
44
+ * `access.impersonate` remains the start check. The result is sent to the client,
45
+ * so a caller can still POST `/start` for someone outside the filter; start
46
+ * re-runs this function and rejects a miss.
47
+ *
48
+ * - `true`: list the whole collection
49
+ * - `false`: hide the collection
50
+ * - `Where`: AND this query onto the list fetch
51
+ */
52
+ type FilterTargets = (args: {
53
+ req: PayloadRequest;
54
+ targetCollection: CollectionSlug;
55
+ }) => boolean | Promise<boolean | Where> | Where;
56
+ type IssuedSession = {
57
+ cookie: string;
58
+ cookieName: string;
59
+ exp: number;
60
+ mode: ImpersonationMode;
61
+ sid: string;
62
+ token: string;
63
+ user: TypedUser;
64
+ };
65
+ type SessionIssueArgs = {
66
+ collection: CollectionSlug;
67
+ payload: Payload;
68
+ req: PayloadRequest;
69
+ userId: number | string;
70
+ };
71
+ type SessionRevokeArgs = {
72
+ collection: CollectionSlug;
73
+ payload: Payload;
74
+ req?: PayloadRequest;
75
+ sid: string;
76
+ userId: number | string;
77
+ };
78
+ type SessionSeams = {
79
+ /** Defaults to `user._sid`. */binding?: (user: TypedUser) => string | undefined;
80
+ issue?: (args: SessionIssueArgs) => Promise<IssuedSession>;
81
+ revoke?: (args: SessionRevokeArgs) => Promise<void>;
82
+ };
83
+ type UiOptions = {
84
+ /**
85
+ * Admin bar while a session is open. Target side: "Acting as" / "Return to".
86
+ * Parallel impersonator side: "session is active on the website" / "End session".
87
+ * @default true
88
+ */
89
+ bar?: boolean;
90
+ /**
91
+ * Replacement for the default switcher row. Receives the same props as
92
+ * `ImpersonationUserCard` (`collectionSlug`, `doc`, and the pick/drawer/document
93
+ * actions). A string path is registered on `admin.dependencies` so the import
94
+ * map can load it. Omit to keep the default card.
95
+ */
96
+ card?: PayloadComponent;
97
+ /**
98
+ * Show email under `useAsTitle` on default switcher cards. Hidden when the
99
+ * title is already the email.
100
+ * @default true
101
+ */
102
+ cardEmail?: boolean;
103
+ /**
104
+ * Impersonate button on the target document. Rendered in
105
+ * `BeforeDocumentControls` so it stays visible when the edit-menu dots are
106
+ * hidden (no create/delete access).
107
+ * @default true
108
+ */
109
+ documentAction?: boolean;
110
+ /**
111
+ * How the bar, the collapsed chip, and the frontend banner name users:
112
+ * `'title'` is the collection's `useAsTitle` (falls back to the email),
113
+ * `'email'` is the email.
114
+ * @default 'title'
115
+ */
116
+ userLabel?: UserLabel;
117
+ /**
118
+ * Header control that opens the user switcher drawer.
119
+ * @default true
120
+ */
121
+ headerAction?: boolean;
122
+ /**
123
+ * "End session" beside Save on an `impersonation-sessions` document
124
+ * (`beforeDocumentControls`). Hidden when the row already has `endedAt`.
125
+ * Create, update, and delete stay denied.
126
+ * @default true
127
+ */
128
+ recordAction?: boolean;
129
+ /**
130
+ * Put `impersonation-sessions` in the admin nav. `access.readRecords` still
131
+ * decides who can read a row. Omit to keep the collection hidden.
132
+ * @default false
133
+ */
134
+ sessionsCollection?: boolean;
135
+ };
136
+ type RetentionOptions = {
137
+ /** Closed rows older than this many days are deleted. Open rows are never deleted. */deleteAfterDays: number; /** @default `0 3 * * *` */
138
+ cron?: string; /** @default `impersonation-retention` */
139
+ queue?: string;
140
+ };
141
+ type EnabledOptions = {
142
+ access: {
143
+ /**
144
+ * Gate for POST `/start`. Only the literal `true` allows. A `Where` object
145
+ * is deny, never allow-all.
146
+ */
147
+ impersonate: ImpersonateAccess; /** Who can read `impersonation-sessions`. Omit to deny. Does not un-hide the collection. */
148
+ readRecords?: Access; /** Who can POST `/end` on someone else's session. Default deny. */
149
+ terminate?: BooleanAccess;
150
+ /**
151
+ * Who the switcher lists. Omit to show everyone the viewer can read.
152
+ * See {@link FilterTargets}.
153
+ */
154
+ filterTargets?: FilterTargets;
155
+ };
156
+ apiPath?: string;
157
+ collectionSlug?: string;
158
+ /**
159
+ * Last pass over the built `impersonation-sessions` collection. Whatever
160
+ * this returns is registered as-is, including access. Do not rename fields
161
+ * the plugin reads (`impersonator`, `target`, `targetSid`, `impersonatorSid`,
162
+ * `startedAt`, `endedAt`, `endedBy`, `mode`, `absoluteExpiresAt`) and do not
163
+ * change the slug here. Use `collectionSlug` for that.
164
+ */
165
+ collection?: {
166
+ overrides?: (collection: CollectionConfig) => CollectionConfig;
167
+ };
168
+ cookies?: {
169
+ clearOnSwitch?: string[];
170
+ };
171
+ decorateRequests?: boolean;
172
+ hintCookieName?: string;
173
+ maxDuration?: number;
174
+ /**
175
+ * Opt-in cleanup of closed rows, plus `closeStaleImpersonations` on the same
176
+ * cron. Off until you set this. The host must run the queue (`jobs.autoRun`
177
+ * or a bin). Open rows are never deleted.
178
+ */
179
+ retention?: false | RetentionOptions;
180
+ onEnd?: (args: {
181
+ endedBy: EndedBy;
182
+ payload: Payload;
183
+ record: Record<string, unknown>;
184
+ req?: PayloadRequest;
185
+ }) => Promise<void> | void;
186
+ onStart?: (args: {
187
+ payload: Payload;
188
+ record: Record<string, unknown>;
189
+ req: PayloadRequest;
190
+ }) => Promise<void> | void;
191
+ reason?: 'off' | 'optional' | 'required';
192
+ security?: {
193
+ trustedOrigins?: string[];
194
+ };
195
+ session?: SessionSeams;
196
+ targets?: CollectionSlug[];
197
+ translations?: TranslationsOption;
198
+ ui?: false | UiOptions;
199
+ };
200
+ type ImpersonationPluginOptions = ({
201
+ disabled: true;
202
+ } & Partial<EnabledOptions>) | ({
203
+ disabled?: false;
204
+ } & EnabledOptions);
205
+ type UserLabel = 'email' | 'title';
206
+ /** Runtime fields Payload paints on `req.user` but generated collection types omit. */
207
+ type ImpersonatedUser = TypedUser & {
208
+ _impersonation?: ImpersonationActor;
209
+ _sid?: string;
210
+ _strategy?: string;
211
+ };
212
+ //#endregion
213
+ export { EndedBy, FilterTargets, ImpersonateAccessArgs, ImpersonatedUser, ImpersonationActor, ImpersonationMode, ImpersonationPluginOptions, RetentionOptions, UiOptions, UserLabel };
214
+ //# sourceMappingURL=types.d.ts.map
package/dist/types.js ADDED
@@ -0,0 +1,11 @@
1
+ //#region src/types.ts
2
+ const asAuthUser = (user) => user;
3
+ /** Sid the current request is bound to. Host `session.binding` wins over `_sid`. */
4
+ const boundSid = (user, binding) => {
5
+ if (!user) return;
6
+ return binding?.(user) ?? asAuthUser(user)._sid;
7
+ };
8
+ //#endregion
9
+ export { asAuthUser, boundSid };
10
+
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import type {\n\tAccess,\n\tCollectionConfig,\n\tCollectionSlug,\n\tPayload,\n\tPayloadComponent,\n\tPayloadRequest,\n\tTypedUser,\n\tWhere,\n} from 'payload'\n\nimport type { TranslationsOption } from './translations'\n\nexport type ImpersonationMode = 'parallel' | 'swap'\n\nexport type EndedBy =\n\t| 'exit'\n\t| 'expired'\n\t| 'failed'\n\t| 'impersonatorGone'\n\t| 'logout'\n\t| 'targetGone'\n\t| 'terminated'\n\nexport type { FailureCode } from './endpoints/codes'\n\nexport type ImpersonationActor = {\n\tabsoluteExpiresAt?: null | string\n\tid: number | string\n\timpersonator: { collection: string; id: number | string }\n\timpersonatorEmail?: null | string\n\timpersonatorLocale?: null | string\n\timpersonatorTitle?: null | string\n\tmode: ImpersonationMode\n\treason?: null | string\n\tstartedAt: string\n\ttarget: { collection: string; id: number | string }\n\ttargetEmail?: null | string\n\ttargetTitle?: null | string\n}\n\nexport type ImpersonateAccessArgs = {\n\treq: PayloadRequest\n\ttarget: Record<string, unknown>\n\ttargetCollection: CollectionSlug\n}\n\n/**\n * Host gate for starting a session. Only the literal `true` allows. `false`,\n * `undefined`, and a Payload `Where` object all deny. A `Where` is never treated\n * as allow-all.\n */\nexport type ImpersonateAccess = (args: ImpersonateAccessArgs) => boolean | Promise<boolean>\n\nexport type BooleanAccess = (args: { req: PayloadRequest }) => boolean | Promise<boolean>\n\n/**\n * Which users the switcher (and document action) should offer. This is UX only.\n * `access.impersonate` remains the start check. The result is sent to the client,\n * so a caller can still POST `/start` for someone outside the filter; start\n * re-runs this function and rejects a miss.\n *\n * - `true`: list the whole collection\n * - `false`: hide the collection\n * - `Where`: AND this query onto the list fetch\n */\nexport type FilterTargets = (args: {\n\treq: PayloadRequest\n\ttargetCollection: CollectionSlug\n}) => boolean | Promise<boolean | Where> | Where\n\nexport type IssuedSession = {\n\tcookie: string\n\tcookieName: string\n\texp: number\n\tmode: ImpersonationMode\n\tsid: string\n\ttoken: string\n\tuser: TypedUser\n}\n\nexport type SessionIssueArgs = {\n\tcollection: CollectionSlug\n\tpayload: Payload\n\treq: PayloadRequest\n\tuserId: number | string\n}\n\nexport type SessionRevokeArgs = {\n\tcollection: CollectionSlug\n\tpayload: Payload\n\treq?: PayloadRequest\n\tsid: string\n\tuserId: number | string\n}\n\nexport type SessionSeams = {\n\t/** Defaults to `user._sid`. */\n\tbinding?: (user: TypedUser) => string | undefined\n\tissue?: (args: SessionIssueArgs) => Promise<IssuedSession>\n\trevoke?: (args: SessionRevokeArgs) => Promise<void>\n}\n\nexport type UiOptions = {\n\t/**\n\t * Admin bar while a session is open. Target side: \"Acting as\" / \"Return to\".\n\t * Parallel impersonator side: \"session is active on the website\" / \"End session\".\n\t * @default true\n\t */\n\tbar?: boolean\n\t/**\n\t * Replacement for the default switcher row. Receives the same props as\n\t * `ImpersonationUserCard` (`collectionSlug`, `doc`, and the pick/drawer/document\n\t * actions). A string path is registered on `admin.dependencies` so the import\n\t * map can load it. Omit to keep the default card.\n\t */\n\tcard?: PayloadComponent\n\t/**\n\t * Show email under `useAsTitle` on default switcher cards. Hidden when the\n\t * title is already the email.\n\t * @default true\n\t */\n\tcardEmail?: boolean\n\t/**\n\t * Impersonate button on the target document. Rendered in\n\t * `BeforeDocumentControls` so it stays visible when the edit-menu dots are\n\t * hidden (no create/delete access).\n\t * @default true\n\t */\n\tdocumentAction?: boolean\n\t/**\n\t * How the bar, the collapsed chip, and the frontend banner name users:\n\t * `'title'` is the collection's `useAsTitle` (falls back to the email),\n\t * `'email'` is the email.\n\t * @default 'title'\n\t */\n\tuserLabel?: UserLabel\n\t/**\n\t * Header control that opens the user switcher drawer.\n\t * @default true\n\t */\n\theaderAction?: boolean\n\t/**\n\t * \"End session\" beside Save on an `impersonation-sessions` document\n\t * (`beforeDocumentControls`). Hidden when the row already has `endedAt`.\n\t * Create, update, and delete stay denied.\n\t * @default true\n\t */\n\trecordAction?: boolean\n\t/**\n\t * Put `impersonation-sessions` in the admin nav. `access.readRecords` still\n\t * decides who can read a row. Omit to keep the collection hidden.\n\t * @default false\n\t */\n\tsessionsCollection?: boolean\n}\n\nexport type RetentionOptions = {\n\t/** Closed rows older than this many days are deleted. Open rows are never deleted. */\n\tdeleteAfterDays: number\n\t/** @default `0 3 * * *` */\n\tcron?: string\n\t/** @default `impersonation-retention` */\n\tqueue?: string\n}\n\nexport type EnabledOptions = {\n\taccess: {\n\t\t/**\n\t\t * Gate for POST `/start`. Only the literal `true` allows. A `Where` object\n\t\t * is deny, never allow-all.\n\t\t */\n\t\timpersonate: ImpersonateAccess\n\t\t/** Who can read `impersonation-sessions`. Omit to deny. Does not un-hide the collection. */\n\t\treadRecords?: Access\n\t\t/** Who can POST `/end` on someone else's session. Default deny. */\n\t\tterminate?: BooleanAccess\n\t\t/**\n\t\t * Who the switcher lists. Omit to show everyone the viewer can read.\n\t\t * See {@link FilterTargets}.\n\t\t */\n\t\tfilterTargets?: FilterTargets\n\t}\n\tapiPath?: string\n\tcollectionSlug?: string\n\t/**\n\t * Last pass over the built `impersonation-sessions` collection. Whatever\n\t * this returns is registered as-is, including access. Do not rename fields\n\t * the plugin reads (`impersonator`, `target`, `targetSid`, `impersonatorSid`,\n\t * `startedAt`, `endedAt`, `endedBy`, `mode`, `absoluteExpiresAt`) and do not\n\t * change the slug here. Use `collectionSlug` for that.\n\t */\n\tcollection?: {\n\t\toverrides?: (collection: CollectionConfig) => CollectionConfig\n\t}\n\tcookies?: { clearOnSwitch?: string[] }\n\tdecorateRequests?: boolean\n\thintCookieName?: string\n\tmaxDuration?: number\n\t/**\n\t * Opt-in cleanup of closed rows, plus `closeStaleImpersonations` on the same\n\t * cron. Off until you set this. The host must run the queue (`jobs.autoRun`\n\t * or a bin). Open rows are never deleted.\n\t */\n\tretention?: false | RetentionOptions\n\tonEnd?: (args: {\n\t\tendedBy: EndedBy\n\t\tpayload: Payload\n\t\trecord: Record<string, unknown>\n\t\treq?: PayloadRequest\n\t}) => Promise<void> | void\n\tonStart?: (args: {\n\t\tpayload: Payload\n\t\trecord: Record<string, unknown>\n\t\treq: PayloadRequest\n\t}) => Promise<void> | void\n\treason?: 'off' | 'optional' | 'required'\n\tsecurity?: { trustedOrigins?: string[] }\n\tsession?: SessionSeams\n\ttargets?: CollectionSlug[]\n\ttranslations?: TranslationsOption\n\tui?: false | UiOptions\n}\n\nexport type ImpersonationPluginOptions =\n\t| ({ disabled: true } & Partial<EnabledOptions>)\n\t| ({ disabled?: false } & EnabledOptions)\n\nexport type UserLabel = 'email' | 'title'\n\nexport type ResolvedUi = {\n\tbar: boolean\n\tcard?: PayloadComponent\n\tcardEmail: boolean\n\tdocumentAction: boolean\n\theaderAction: boolean\n\trecordAction: boolean\n\tsessionsCollection: boolean\n\tuserLabel: UserLabel\n}\n\nexport type ResolvedOptions = {\n\taccess: {\n\t\tfilterTargets?: FilterTargets\n\t\timpersonate: ImpersonateAccess\n\t\treadRecords: Access\n\t\tterminate: BooleanAccess\n\t}\n\tapiPath: string\n\tcollectionSlug: CollectionSlug\n\tcollectionOverrides?: (collection: CollectionConfig) => CollectionConfig\n\tcookies: { clearOnSwitch: string[] }\n\tdecorateRequests: boolean\n\thintCookieName: string\n\tmaxDuration: number | undefined\n\tonEnd?: EnabledOptions['onEnd']\n\tonStart?: EnabledOptions['onStart']\n\treason: 'off' | 'optional' | 'required'\n\tretention: RetentionOptions | undefined\n\tsecurity: { trustedOrigins: string[] }\n\tsession: SessionSeams\n\ttargets: CollectionSlug[] | undefined\n\tui: ResolvedUi\n}\n\n/** Runtime fields Payload paints on `req.user` but generated collection types omit. */\nexport type ImpersonatedUser = TypedUser & {\n\t_impersonation?: ImpersonationActor\n\t_sid?: string\n\t_strategy?: string\n}\n\nexport const asAuthUser = (user: TypedUser): ImpersonatedUser => user as ImpersonatedUser\n\n/** Sid the current request is bound to. Host `session.binding` wins over `_sid`. */\nexport const boundSid = (\n\tuser: null | TypedUser | undefined,\n\tbinding?: (user: TypedUser) => string | undefined\n): string | undefined => {\n\tif (!user) {\n\t\treturn undefined\n\t}\n\treturn binding?.(user) ?? asAuthUser(user)._sid\n}\n\nexport type ImpersonationRecord = {\n\tabsoluteExpiresAt?: null | string\n\tendedAt?: null | string\n\tendedBy?: EndedBy | null\n\tid: number | string\n\timpersonator: { relationTo: string; value: number | string } | number | string\n\timpersonatorEmail?: null | string\n\timpersonatorLocale?: null | string\n\timpersonatorSid: string\n\timpersonatorTenantCookie?: null | string\n\timpersonatorTitle?: null | string\n\tip?: null | string\n\tmode: ImpersonationMode\n\treason?: null | string\n\tstartedAt: string\n\ttarget: { relationTo: string; value: number | string } | number | string\n\ttargetEmail?: null | string\n\ttargetLocked?: boolean | null\n\ttargetSid: string\n\ttargetTitle?: null | string\n\tuserAgent?: null | string\n}\n"],"mappings":";AAgRA,MAAa,cAAc,SAAsC;;AAGjE,MAAa,YACZ,MACA,YACwB;CACxB,IAAI,CAAC,MACJ;CAED,OAAO,UAAU,IAAI,KAAK,WAAW,IAAI,EAAE;AAC5C"}
@@ -0,0 +1,5 @@
1
+ //#region src/ui/EndSessionMenuItem.d.ts
2
+ declare const EndSessionMenuItem: () => import("react/jsx-runtime").JSX.Element | null;
3
+ //#endregion
4
+ export { EndSessionMenuItem };
5
+ //# sourceMappingURL=EndSessionMenuItem.d.ts.map
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ import { keys } from "../translations/keys.js";
3
+ import { useTranslation as useTranslation$1 } from "../translations/useTranslation.js";
4
+ import { errorKey } from "./api.js";
5
+ import { useImpersonation } from "./useImpersonation.js";
6
+ import { useState } from "react";
7
+ import { Button, ConfirmationModal, toast, useDocumentInfo, useModal } from "@payloadcms/ui";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/ui/EndSessionMenuItem.tsx
10
+ const CONFIRM_SLUG = "impersonation-confirm-end";
11
+ const EndSessionMenuItem = () => {
12
+ const { collectionSlug, data, id } = useDocumentInfo();
13
+ const { t } = useTranslation$1();
14
+ const { openModal } = useModal();
15
+ const { end, sessionCollection } = useImpersonation();
16
+ const [generation, setGeneration] = useState(0);
17
+ const endedAt = data && typeof data === "object" && "endedAt" in data ? data.endedAt : void 0;
18
+ if (!id || collectionSlug !== sessionCollection || endedAt) return null;
19
+ const onConfirm = async () => {
20
+ const result = await end(id);
21
+ if (!result.ok) {
22
+ toast.error(t(errorKey(result.error ?? "failed")));
23
+ setGeneration((current) => current + 1);
24
+ throw new Error(result.error ?? "failed");
25
+ }
26
+ window.location.reload();
27
+ };
28
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Button, {
29
+ buttonStyle: "subtle",
30
+ margin: false,
31
+ onClick: () => openModal(CONFIRM_SLUG),
32
+ children: t(keys.endSession)
33
+ }), /* @__PURE__ */ jsx(ConfirmationModal, {
34
+ body: t(keys.endSessionBody),
35
+ className: "impersonation-confirm-modal",
36
+ confirmLabel: t(keys.endSession),
37
+ heading: t(keys.endSession),
38
+ modalSlug: CONFIRM_SLUG,
39
+ onConfirm
40
+ }, generation)] });
41
+ };
42
+ //#endregion
43
+ export { EndSessionMenuItem };
44
+
45
+ //# sourceMappingURL=EndSessionMenuItem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EndSessionMenuItem.js","names":["useTranslation"],"sources":["../../src/ui/EndSessionMenuItem.tsx"],"sourcesContent":["'use client'\n\nimport { Button, ConfirmationModal, toast, useDocumentInfo, useModal } from '@payloadcms/ui'\nimport { useState } from 'react'\n\nimport { keys } from '../translations/keys'\nimport { useTranslation } from '../translations/useTranslation'\nimport { errorKey } from './api'\nimport { useImpersonation } from './useImpersonation'\n\nconst CONFIRM_SLUG = 'impersonation-confirm-end'\n\nexport const EndSessionMenuItem = () => {\n\tconst { collectionSlug, data, id } = useDocumentInfo()\n\tconst { t } = useTranslation()\n\tconst { openModal } = useModal()\n\tconst { end, sessionCollection } = useImpersonation()\n\tconst [generation, setGeneration] = useState(0)\n\n\tconst endedAt =\n\t\tdata && typeof data === 'object' && 'endedAt' in data\n\t\t\t? (data as { endedAt?: null | string }).endedAt\n\t\t\t: undefined\n\tif (!id || collectionSlug !== sessionCollection || endedAt) {\n\t\treturn null\n\t}\n\n\tconst onConfirm = async () => {\n\t\tconst result = await end(id)\n\t\tif (!result.ok) {\n\t\t\ttoast.error(t(errorKey(result.error ?? 'failed')))\n\t\t\tsetGeneration((current) => current + 1)\n\t\t\tthrow new Error(result.error ?? 'failed')\n\t\t}\n\t\twindow.location.reload()\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<Button buttonStyle=\"subtle\" margin={false} onClick={() => openModal(CONFIRM_SLUG)}>\n\t\t\t\t{t(keys.endSession)}\n\t\t\t</Button>\n\t\t\t<ConfirmationModal\n\t\t\t\tbody={t(keys.endSessionBody)}\n\t\t\t\tclassName=\"impersonation-confirm-modal\"\n\t\t\t\tconfirmLabel={t(keys.endSession)}\n\t\t\t\theading={t(keys.endSession)}\n\t\t\t\tkey={generation}\n\t\t\t\tmodalSlug={CONFIRM_SLUG}\n\t\t\t\tonConfirm={onConfirm}\n\t\t\t/>\n\t\t</>\n\t)\n}\n"],"mappings":";;;;;;;;;AAUA,MAAM,eAAe;AAErB,MAAa,2BAA2B;CACvC,MAAM,EAAE,gBAAgB,MAAM,OAAO,gBAAgB;CACrD,MAAM,EAAE,MAAMA,iBAAe;CAC7B,MAAM,EAAE,cAAc,SAAS;CAC/B,MAAM,EAAE,KAAK,sBAAsB,iBAAiB;CACpD,MAAM,CAAC,YAAY,iBAAiB,SAAS,CAAC;CAE9C,MAAM,UACL,QAAQ,OAAO,SAAS,YAAY,aAAa,OAC7C,KAAqC,UACtC,KAAA;CACJ,IAAI,CAAC,MAAM,mBAAmB,qBAAqB,SAClD,OAAO;CAGR,MAAM,YAAY,YAAY;EAC7B,MAAM,SAAS,MAAM,IAAI,EAAE;EAC3B,IAAI,CAAC,OAAO,IAAI;GACf,MAAM,MAAM,EAAE,SAAS,OAAO,SAAS,QAAQ,CAAC,CAAC;GACjD,eAAe,YAAY,UAAU,CAAC;GACtC,MAAM,IAAI,MAAM,OAAO,SAAS,QAAQ;EACzC;EACA,OAAO,SAAS,OAAO;CACxB;CAEA,OACC,qBAAA,UAAA,EAAA,UAAA,CACC,oBAAC,QAAD;EAAQ,aAAY;EAAS,QAAQ;EAAO,eAAe,UAAU,YAAY;YAC/E,EAAE,KAAK,UAAU;CACX,CAAA,GACR,oBAAC,mBAAD;EACC,MAAM,EAAE,KAAK,cAAc;EAC3B,WAAU;EACV,cAAc,EAAE,KAAK,UAAU;EAC/B,SAAS,EAAE,KAAK,UAAU;EAE1B,WAAW;EACA;CACX,GAHK,UAGL,CACA,EAAA,CAAA;AAEJ"}
@@ -0,0 +1,20 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ //#region src/ui/ImpersonateIcon.tsx
3
+ const ImpersonateIcon = () => /* @__PURE__ */ jsx("svg", {
4
+ "aria-hidden": "true",
5
+ fill: "none",
6
+ height: "20",
7
+ viewBox: "0 0 20 20",
8
+ width: "20",
9
+ children: /* @__PURE__ */ jsx("path", {
10
+ d: "M7.5 6.5H5.25v7H7.5M12.5 6.5h2.25v7H12.5M7.75 10h4.5",
11
+ stroke: "currentColor",
12
+ strokeLinecap: "round",
13
+ strokeLinejoin: "round",
14
+ strokeWidth: "1.5"
15
+ })
16
+ });
17
+ //#endregion
18
+ export { ImpersonateIcon };
19
+
20
+ //# sourceMappingURL=ImpersonateIcon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImpersonateIcon.js","names":[],"sources":["../../src/ui/ImpersonateIcon.tsx"],"sourcesContent":["export const ImpersonateIcon = () => (\n\t<svg aria-hidden=\"true\" fill=\"none\" height=\"20\" viewBox=\"0 0 20 20\" width=\"20\">\n\t\t<path\n\t\t\td=\"M7.5 6.5H5.25v7H7.5M12.5 6.5h2.25v7H12.5M7.75 10h4.5\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t/>\n\t</svg>\n)\n"],"mappings":";;AAAA,MAAa,wBACZ,oBAAC,OAAD;CAAK,eAAY;CAAO,MAAK;CAAO,QAAO;CAAK,SAAQ;CAAY,OAAM;WACzE,oBAAC,QAAD;EACC,GAAE;EACF,QAAO;EACP,eAAc;EACd,gBAAe;EACf,aAAY;CACZ,CAAA;AACG,CAAA"}
@@ -0,0 +1,10 @@
1
+ import { ServerProps } from "payload";
2
+
3
+ //#region src/ui/ImpersonationAction.d.ts
4
+ declare const ImpersonationAction: ({
5
+ payload,
6
+ user
7
+ }: ServerProps) => Promise<import("react/jsx-runtime").JSX.Element | null>;
8
+ //#endregion
9
+ export { ImpersonationAction };
10
+ //# sourceMappingURL=ImpersonationAction.d.ts.map