@payloadcms/figma 0.0.1-alpha.3 → 0.0.1-alpha.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.
Files changed (209) hide show
  1. package/dist/api/control-plane.d.ts +22 -1
  2. package/dist/api/control-plane.d.ts.map +1 -1
  3. package/dist/api/control-plane.js +54 -15
  4. package/dist/api/control-plane.js.map +1 -1
  5. package/dist/api/figma-api.d.ts.map +1 -1
  6. package/dist/api/figma-api.js +42 -12
  7. package/dist/api/figma-api.js.map +1 -1
  8. package/dist/auth/callback-server.d.ts.map +1 -1
  9. package/dist/auth/callback-server.js +2 -1
  10. package/dist/auth/callback-server.js.map +1 -1
  11. package/dist/auth/crypto-utils.d.ts.map +1 -1
  12. package/dist/auth/crypto-utils.js +5 -5
  13. package/dist/auth/crypto-utils.js.map +1 -1
  14. package/dist/auth/oauth-flow.d.ts +1 -1
  15. package/dist/auth/oauth-flow.d.ts.map +1 -1
  16. package/dist/auth/oauth-flow.js +5 -5
  17. package/dist/auth/oauth-flow.js.map +1 -1
  18. package/dist/auth/project-token.d.ts.map +1 -1
  19. package/dist/auth/project-token.js +9 -4
  20. package/dist/auth/project-token.js.map +1 -1
  21. package/dist/auth/token-store.d.ts +10 -0
  22. package/dist/auth/token-store.d.ts.map +1 -1
  23. package/dist/auth/token-store.js +20 -0
  24. package/dist/auth/token-store.js.map +1 -1
  25. package/dist/cli.js +3 -0
  26. package/dist/cli.js.map +1 -1
  27. package/dist/commands/deploy.d.ts +4 -0
  28. package/dist/commands/deploy.d.ts.map +1 -1
  29. package/dist/commands/deploy.js +68 -126
  30. package/dist/commands/deploy.js.map +1 -1
  31. package/dist/commands/init.d.ts +1 -5
  32. package/dist/commands/init.d.ts.map +1 -1
  33. package/dist/commands/init.js +90 -85
  34. package/dist/commands/init.js.map +1 -1
  35. package/dist/commands/list-tokens.js +2 -2
  36. package/dist/commands/list-tokens.js.map +1 -1
  37. package/dist/commands/login.d.ts +8 -1
  38. package/dist/commands/login.d.ts.map +1 -1
  39. package/dist/commands/login.js +12 -6
  40. package/dist/commands/login.js.map +1 -1
  41. package/dist/commands/logout.js +2 -2
  42. package/dist/commands/logout.js.map +1 -1
  43. package/dist/config/oauth.d.ts +5 -0
  44. package/dist/config/oauth.d.ts.map +1 -1
  45. package/dist/config/oauth.js +9 -4
  46. package/dist/config/oauth.js.map +1 -1
  47. package/dist/db-content-api/README.md +108 -0
  48. package/dist/db-content-api/generated/content-api-types.d.ts +3702 -0
  49. package/dist/db-content-api/generated/content-api-types.d.ts.map +1 -0
  50. package/dist/db-content-api/generated/content-api-types.js +7 -0
  51. package/dist/db-content-api/generated/content-api-types.js.map +1 -0
  52. package/dist/db-content-api/index.d.ts +18 -0
  53. package/dist/db-content-api/index.d.ts.map +1 -0
  54. package/dist/db-content-api/index.js +551 -0
  55. package/dist/db-content-api/index.js.map +1 -0
  56. package/dist/db-content-api/temp-utilities/pagination.d.ts +13 -0
  57. package/dist/db-content-api/temp-utilities/pagination.d.ts.map +1 -0
  58. package/dist/db-content-api/temp-utilities/pagination.js +45 -0
  59. package/dist/db-content-api/temp-utilities/pagination.js.map +1 -0
  60. package/dist/db-content-api/temp-utilities/slug.d.ts +2 -0
  61. package/dist/db-content-api/temp-utilities/slug.d.ts.map +1 -0
  62. package/dist/db-content-api/temp-utilities/slug.js +3 -0
  63. package/dist/db-content-api/temp-utilities/slug.js.map +1 -0
  64. package/dist/db-content-api/temp-utilities/sorting.d.ts +7 -0
  65. package/dist/db-content-api/temp-utilities/sorting.d.ts.map +1 -0
  66. package/dist/db-content-api/temp-utilities/sorting.js +71 -0
  67. package/dist/db-content-api/temp-utilities/sorting.js.map +1 -0
  68. package/dist/db-content-api/temp-utilities/unwrapDocument.d.ts +4 -0
  69. package/dist/db-content-api/temp-utilities/unwrapDocument.d.ts.map +1 -0
  70. package/dist/db-content-api/temp-utilities/unwrapDocument.js +45 -0
  71. package/dist/db-content-api/temp-utilities/unwrapDocument.js.map +1 -0
  72. package/dist/db-content-api/utilities/auth.d.ts +30 -0
  73. package/dist/db-content-api/utilities/auth.d.ts.map +1 -0
  74. package/dist/db-content-api/utilities/auth.js +81 -0
  75. package/dist/db-content-api/utilities/auth.js.map +1 -0
  76. package/dist/db-content-api/utilities/data.d.ts +24 -0
  77. package/dist/db-content-api/utilities/data.d.ts.map +1 -0
  78. package/dist/db-content-api/utilities/data.js +118 -0
  79. package/dist/db-content-api/utilities/data.js.map +1 -0
  80. package/dist/db-content-api/utilities/joins.d.ts +55 -0
  81. package/dist/db-content-api/utilities/joins.d.ts.map +1 -0
  82. package/dist/db-content-api/utilities/joins.js +130 -0
  83. package/dist/db-content-api/utilities/joins.js.map +1 -0
  84. package/dist/db-content-api/utilities/where.d.ts +12 -0
  85. package/dist/db-content-api/utilities/where.d.ts.map +1 -0
  86. package/dist/db-content-api/utilities/where.js +63 -0
  87. package/dist/db-content-api/utilities/where.js.map +1 -0
  88. package/dist/endpoints/health.d.ts +3 -0
  89. package/dist/endpoints/health.d.ts.map +1 -0
  90. package/dist/endpoints/health.js +11 -0
  91. package/dist/endpoints/health.js.map +1 -0
  92. package/dist/exports/client.d.ts +3 -0
  93. package/dist/exports/client.d.ts.map +1 -0
  94. package/dist/exports/client.js +4 -0
  95. package/dist/exports/client.js.map +1 -0
  96. package/dist/index.d.ts +2 -1
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +3 -1
  99. package/dist/index.js.map +1 -1
  100. package/dist/oauth/components/LoginButton/index.d.ts.map +1 -1
  101. package/dist/oauth/components/LoginButton/index.js +50 -6
  102. package/dist/oauth/components/LoginButton/index.js.map +1 -1
  103. package/dist/oauth/components/LoginButton/index.scss +50 -3
  104. package/dist/oauth/components/LogoutButton/index.d.ts.map +1 -1
  105. package/dist/oauth/components/LogoutButton/index.js +0 -1
  106. package/dist/oauth/components/LogoutButton/index.js.map +1 -1
  107. package/dist/oauth/defaults.d.ts.map +1 -1
  108. package/dist/oauth/defaults.js +29 -5
  109. package/dist/oauth/defaults.js.map +1 -1
  110. package/dist/oauth/endpoints/getLoginEndpoint.d.ts.map +1 -1
  111. package/dist/oauth/endpoints/getLoginEndpoint.js +1 -1
  112. package/dist/oauth/endpoints/getLoginEndpoint.js.map +1 -1
  113. package/dist/oauth/index.d.ts.map +1 -1
  114. package/dist/oauth/index.js +42 -6
  115. package/dist/oauth/index.js.map +1 -1
  116. package/dist/oauth/strategy/index.d.ts.map +1 -1
  117. package/dist/oauth/strategy/index.js +6 -2
  118. package/dist/oauth/strategy/index.js.map +1 -1
  119. package/dist/oauth/types.d.ts +6 -6
  120. package/dist/oauth/types.d.ts.map +1 -1
  121. package/dist/oauth/types.js.map +1 -1
  122. package/dist/oauth/utilities/createCookieOptions.d.ts.map +1 -1
  123. package/dist/oauth/utilities/createCookieOptions.js.map +1 -1
  124. package/dist/oauth/utilities/isDuplicateKeyError.d.ts +7 -0
  125. package/dist/oauth/utilities/isDuplicateKeyError.d.ts.map +1 -0
  126. package/dist/oauth/utilities/isDuplicateKeyError.js +14 -0
  127. package/dist/oauth/utilities/isDuplicateKeyError.js.map +1 -0
  128. package/dist/oauth/utilities/refreshTokens.d.ts.map +1 -1
  129. package/dist/oauth/utilities/refreshTokens.js +1 -1
  130. package/dist/oauth/utilities/refreshTokens.js.map +1 -1
  131. package/dist/plugin/build-config.d.ts +21 -4
  132. package/dist/plugin/build-config.d.ts.map +1 -1
  133. package/dist/plugin/build-config.js +89 -9
  134. package/dist/plugin/build-config.js.map +1 -1
  135. package/dist/storage-content-api/api-types.d.ts +161 -0
  136. package/dist/storage-content-api/api-types.d.ts.map +1 -0
  137. package/dist/storage-content-api/api-types.js +6 -0
  138. package/dist/storage-content-api/api-types.js.map +1 -0
  139. package/dist/storage-content-api/client.d.ts +6 -0
  140. package/dist/storage-content-api/client.d.ts.map +1 -0
  141. package/dist/storage-content-api/client.js +36 -0
  142. package/dist/storage-content-api/client.js.map +1 -0
  143. package/dist/storage-content-api/generateURL.d.ts +7 -0
  144. package/dist/storage-content-api/generateURL.d.ts.map +1 -0
  145. package/dist/storage-content-api/generateURL.js +7 -0
  146. package/dist/storage-content-api/generateURL.js.map +1 -0
  147. package/dist/storage-content-api/handleDelete.d.ts +8 -0
  148. package/dist/storage-content-api/handleDelete.d.ts.map +1 -0
  149. package/dist/storage-content-api/handleDelete.js +15 -0
  150. package/dist/storage-content-api/handleDelete.js.map +1 -0
  151. package/dist/storage-content-api/handleUpload.d.ts +11 -0
  152. package/dist/storage-content-api/handleUpload.d.ts.map +1 -0
  153. package/dist/storage-content-api/handleUpload.js +126 -0
  154. package/dist/storage-content-api/handleUpload.js.map +1 -0
  155. package/dist/storage-content-api/index.d.ts +5 -0
  156. package/dist/storage-content-api/index.d.ts.map +1 -0
  157. package/dist/storage-content-api/index.js +31 -0
  158. package/dist/storage-content-api/index.js.map +1 -0
  159. package/dist/storage-content-api/staticHandler.d.ts +10 -0
  160. package/dist/storage-content-api/staticHandler.d.ts.map +1 -0
  161. package/dist/storage-content-api/staticHandler.js +35 -0
  162. package/dist/storage-content-api/staticHandler.js.map +1 -0
  163. package/dist/storage-content-api/types.d.ts +10 -0
  164. package/dist/storage-content-api/types.d.ts.map +1 -0
  165. package/dist/storage-content-api/types.js +3 -0
  166. package/dist/storage-content-api/types.js.map +1 -0
  167. package/dist/templates/README.md +19 -0
  168. package/dist/utils/env-management.d.ts +9 -8
  169. package/dist/utils/env-management.d.ts.map +1 -1
  170. package/dist/utils/env-management.js +73 -74
  171. package/dist/utils/env-management.js.map +1 -1
  172. package/dist/utils/formatter.d.ts.map +1 -1
  173. package/dist/utils/formatter.js +1 -7
  174. package/dist/utils/formatter.js.map +1 -1
  175. package/dist/utils/lambda-config.d.ts.map +1 -1
  176. package/dist/utils/lambda-config.js +1 -0
  177. package/dist/utils/lambda-config.js.map +1 -1
  178. package/dist/utils/messages.d.ts.map +1 -1
  179. package/dist/utils/messages.js +5 -7
  180. package/dist/utils/messages.js.map +1 -1
  181. package/dist/utils/payload-config-ast.d.ts +22 -3
  182. package/dist/utils/payload-config-ast.d.ts.map +1 -1
  183. package/dist/utils/payload-config-ast.js +89 -31
  184. package/dist/utils/payload-config-ast.js.map +1 -1
  185. package/dist/utils/payload-config-finder.d.ts +2 -2
  186. package/dist/utils/payload-config-finder.d.ts.map +1 -1
  187. package/dist/utils/payload-config-finder.js +48 -9
  188. package/dist/utils/payload-config-finder.js.map +1 -1
  189. package/dist/utils/payload-config-modifier.d.ts.map +1 -1
  190. package/dist/utils/payload-config-modifier.js +33 -4
  191. package/dist/utils/payload-config-modifier.js.map +1 -1
  192. package/dist/utils/payload-package-check.d.ts +5 -0
  193. package/dist/utils/payload-package-check.d.ts.map +1 -1
  194. package/dist/utils/payload-package-check.js +48 -4
  195. package/dist/utils/payload-package-check.js.map +1 -1
  196. package/dist/utils/project.d.ts.map +1 -1
  197. package/dist/utils/project.js +8 -6
  198. package/dist/utils/project.js.map +1 -1
  199. package/dist/utils/s3-upload.d.ts +0 -1
  200. package/dist/utils/s3-upload.d.ts.map +1 -1
  201. package/dist/utils/s3-upload.js +10 -3
  202. package/dist/utils/s3-upload.js.map +1 -1
  203. package/dist/utils/token-display.d.ts.map +1 -1
  204. package/dist/utils/token-display.js +11 -5
  205. package/dist/utils/token-display.js.map +1 -1
  206. package/dist/utils/typescript-validator.d.ts.map +1 -1
  207. package/dist/utils/typescript-validator.js +1 -6
  208. package/dist/utils/typescript-validator.js.map +1 -1
  209. package/package.json +24 -7
@@ -0,0 +1,130 @@
1
+ import { convertPayloadSortToContentAPI } from '../temp-utilities/sorting.js';
2
+ import { convertPayloadWhereToContentAPI } from './where.js';
3
+ /**
4
+ * Convert Payload's JoinQuery to Content API's join format.
5
+ *
6
+ * ## Content API Join Limitations
7
+ *
8
+ * The following Payload join features are NOT YET supported by Content API:
9
+ *
10
+ * 1. **hasMany relationships** - Content API's join uses `data#>'{path}'#>>'{}'` to extract
11
+ * a single ID. HasMany relationships store arrays `["id1", "id2"]` which can't match.
12
+ *
13
+ * 2. **Array field relationships** - `on: 'array.category'` expects iteration over array
14
+ * elements, but Content API treats the path as a single JSONB extraction.
15
+ *
16
+ * 3. **Polymorphic relationships** - Stored as `{ relationTo, value }` objects, but
17
+ * Content API expects a simple ID string.
18
+ *
19
+ * 4. **Localized relationship fields** - Locale-aware joins not implemented.
20
+ *
21
+ * Note: "Where querying through joins" (e.g., `where: { 'relatedPosts.title': { equals: 'x' } }`)
22
+ * is a separate Payload feature that filters documents based on joined data. This is NOT
23
+ * a join feature but a where clause feature, and would need separate Content API support.
24
+ *
25
+ * Payload's JoinQuery format (at runtime):
26
+ * {
27
+ * 'group.relatedPosts': { // joinPath - where results go in the document
28
+ * sort: '-title', // Payload sort format
29
+ * limit: 10,
30
+ * page: 2, // page-based pagination
31
+ * where: { ... }, // Payload where format
32
+ * count: true
33
+ * }
34
+ * }
35
+ *
36
+ * Content API's join format:
37
+ * [{
38
+ * collectionId: 'posts', // collection to join FROM
39
+ * on: 'group.category', // field in joined collection pointing to this doc
40
+ * path: 'group.relatedPosts', // where to put results
41
+ * count: false,
42
+ * where: { ... }, // Content API where format
43
+ * sort: [{ path, direction }], // Content API sort format
44
+ * limit: 10,
45
+ * offset: 10 // offset-based pagination
46
+ * }]
47
+ *
48
+ * The mapping requires the collection config to resolve:
49
+ * - Which collection each join field refers to
50
+ * - What the 'on' field is for each join
51
+ */ export function convertPayloadJoinsToContentAPI(payload, collectionConfig, joins) {
52
+ // joins === false means explicitly disable all joins
53
+ // joins === undefined means use defaults (no custom query params)
54
+ if (joins === false || !joins) {
55
+ return undefined;
56
+ }
57
+ const result = [];
58
+ // Iterate through all join paths in the query
59
+ for (const [joinPath, joinQueryValue] of Object.entries(joins)){
60
+ // joinQuery === false means skip this specific join
61
+ if (joinQueryValue === false) {
62
+ continue;
63
+ }
64
+ // Normalize undefined/empty to empty object
65
+ const joinQuery = joinQueryValue ?? {};
66
+ // Find the SanitizedJoin config for this joinPath
67
+ // SanitizedJoins is indexed by the collection being joined FROM
68
+ let foundJoin;
69
+ // Search through all collections in the joins config
70
+ for (const [collectionSlug, sanitizedJoins] of Object.entries(collectionConfig.joins)){
71
+ for (const sanitizedJoin of sanitizedJoins){
72
+ if (sanitizedJoin.joinPath === joinPath) {
73
+ foundJoin = {
74
+ collectionSlug,
75
+ on: sanitizedJoin.field.on
76
+ };
77
+ break;
78
+ }
79
+ }
80
+ if (foundJoin) {
81
+ break;
82
+ }
83
+ }
84
+ // Also check polymorphic joins
85
+ if (!foundJoin) {
86
+ for (const sanitizedJoin of collectionConfig.polymorphicJoins){
87
+ if (sanitizedJoin.joinPath === joinPath) {
88
+ // For polymorphic joins, collection is an array - use first one
89
+ const collections = sanitizedJoin.field.collection;
90
+ foundJoin = {
91
+ collectionSlug: Array.isArray(collections) ? collections[0] : collections,
92
+ on: sanitizedJoin.field.on
93
+ };
94
+ break;
95
+ }
96
+ }
97
+ }
98
+ if (!foundJoin) {
99
+ payload.logger.warn(`Join path '${joinPath}' not found in collection config for '${collectionConfig.slug}'`);
100
+ continue;
101
+ }
102
+ // Convert pagination: Payload uses page, Content API JoinClause uses offset
103
+ let offset;
104
+ if (joinQuery.page && joinQuery.page > 1 && joinQuery.limit) {
105
+ offset = (joinQuery.page - 1) * joinQuery.limit;
106
+ }
107
+ const contentAPIJoin = {
108
+ collectionId: foundJoin.collectionSlug,
109
+ count: joinQuery.count ?? false,
110
+ on: foundJoin.on,
111
+ path: joinPath,
112
+ ...joinQuery.limit !== undefined && {
113
+ limit: joinQuery.limit
114
+ },
115
+ ...offset !== undefined && {
116
+ offset
117
+ },
118
+ ...joinQuery.sort && {
119
+ sort: convertPayloadSortToContentAPI(joinQuery.sort)
120
+ },
121
+ ...joinQuery.where && {
122
+ where: convertPayloadWhereToContentAPI(joinQuery.where)
123
+ }
124
+ };
125
+ result.push(contentAPIJoin);
126
+ }
127
+ return result.length > 0 ? result : undefined;
128
+ }
129
+
130
+ //# sourceMappingURL=joins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/db-content-api/utilities/joins.ts"],"sourcesContent":["import type { JoinQuery, Payload, SanitizedCollectionConfig } from 'payload'\n\nimport type { components } from '../generated/content-api-types.js'\n\nimport { convertPayloadSortToContentAPI } from '../temp-utilities/sorting.js'\nimport { convertPayloadWhereToContentAPI } from './where.js'\n\n// JoinClause is an array type, so we extract the element type\ntype ContentAPIJoin = components['schemas']['JoinClause'][number]\n\n/**\n * Convert Payload's JoinQuery to Content API's join format.\n *\n * ## Content API Join Limitations\n *\n * The following Payload join features are NOT YET supported by Content API:\n *\n * 1. **hasMany relationships** - Content API's join uses `data#>'{path}'#>>'{}'` to extract\n * a single ID. HasMany relationships store arrays `[\"id1\", \"id2\"]` which can't match.\n *\n * 2. **Array field relationships** - `on: 'array.category'` expects iteration over array\n * elements, but Content API treats the path as a single JSONB extraction.\n *\n * 3. **Polymorphic relationships** - Stored as `{ relationTo, value }` objects, but\n * Content API expects a simple ID string.\n *\n * 4. **Localized relationship fields** - Locale-aware joins not implemented.\n *\n * Note: \"Where querying through joins\" (e.g., `where: { 'relatedPosts.title': { equals: 'x' } }`)\n * is a separate Payload feature that filters documents based on joined data. This is NOT\n * a join feature but a where clause feature, and would need separate Content API support.\n *\n * Payload's JoinQuery format (at runtime):\n * {\n * 'group.relatedPosts': { // joinPath - where results go in the document\n * sort: '-title', // Payload sort format\n * limit: 10,\n * page: 2, // page-based pagination\n * where: { ... }, // Payload where format\n * count: true\n * }\n * }\n *\n * Content API's join format:\n * [{\n * collectionId: 'posts', // collection to join FROM\n * on: 'group.category', // field in joined collection pointing to this doc\n * path: 'group.relatedPosts', // where to put results\n * count: false,\n * where: { ... }, // Content API where format\n * sort: [{ path, direction }], // Content API sort format\n * limit: 10,\n * offset: 10 // offset-based pagination\n * }]\n *\n * The mapping requires the collection config to resolve:\n * - Which collection each join field refers to\n * - What the 'on' field is for each join\n */\nexport function convertPayloadJoinsToContentAPI(\n payload: Payload,\n collectionConfig: SanitizedCollectionConfig,\n joins: false | JoinQuery | undefined,\n): ContentAPIJoin[] | undefined {\n // joins === false means explicitly disable all joins\n // joins === undefined means use defaults (no custom query params)\n if (joins === false || !joins) {\n return undefined\n }\n\n const result: ContentAPIJoin[] = []\n\n // Iterate through all join paths in the query\n for (const [joinPath, joinQueryValue] of Object.entries(joins)) {\n // joinQuery === false means skip this specific join\n if (joinQueryValue === false) {\n continue\n }\n\n // Normalize undefined/empty to empty object\n const joinQuery = joinQueryValue ?? {}\n\n // Find the SanitizedJoin config for this joinPath\n // SanitizedJoins is indexed by the collection being joined FROM\n let foundJoin: { collectionSlug: string; on: string } | undefined\n\n // Search through all collections in the joins config\n for (const [collectionSlug, sanitizedJoins] of Object.entries(collectionConfig.joins)) {\n for (const sanitizedJoin of sanitizedJoins) {\n if (sanitizedJoin.joinPath === joinPath) {\n foundJoin = {\n collectionSlug,\n on: sanitizedJoin.field.on,\n }\n break\n }\n }\n if (foundJoin) {\n break\n }\n }\n\n // Also check polymorphic joins\n if (!foundJoin) {\n for (const sanitizedJoin of collectionConfig.polymorphicJoins) {\n if (sanitizedJoin.joinPath === joinPath) {\n // For polymorphic joins, collection is an array - use first one\n const collections = sanitizedJoin.field.collection\n foundJoin = {\n collectionSlug: Array.isArray(collections) ? collections[0] : collections,\n on: sanitizedJoin.field.on,\n }\n break\n }\n }\n }\n\n if (!foundJoin) {\n payload.logger.warn(\n `Join path '${joinPath}' not found in collection config for '${collectionConfig.slug}'`,\n )\n continue\n }\n\n // Convert pagination: Payload uses page, Content API JoinClause uses offset\n let offset: number | undefined\n if (joinQuery.page && joinQuery.page > 1 && joinQuery.limit) {\n offset = (joinQuery.page - 1) * joinQuery.limit\n }\n\n const contentAPIJoin: ContentAPIJoin = {\n collectionId: foundJoin.collectionSlug,\n count: joinQuery.count ?? false,\n on: foundJoin.on,\n path: joinPath,\n ...(joinQuery.limit !== undefined && { limit: joinQuery.limit }),\n ...(offset !== undefined && { offset }),\n ...(joinQuery.sort && { sort: convertPayloadSortToContentAPI(joinQuery.sort) }),\n ...(joinQuery.where && { where: convertPayloadWhereToContentAPI(joinQuery.where) }),\n }\n\n result.push(contentAPIJoin)\n }\n\n return result.length > 0 ? result : undefined\n}\n"],"names":["convertPayloadSortToContentAPI","convertPayloadWhereToContentAPI","convertPayloadJoinsToContentAPI","payload","collectionConfig","joins","undefined","result","joinPath","joinQueryValue","Object","entries","joinQuery","foundJoin","collectionSlug","sanitizedJoins","sanitizedJoin","on","field","polymorphicJoins","collections","collection","Array","isArray","logger","warn","slug","offset","page","limit","contentAPIJoin","collectionId","count","path","sort","where","push","length"],"mappings":"AAIA,SAASA,8BAA8B,QAAQ,+BAA8B;AAC7E,SAASC,+BAA+B,QAAQ,aAAY;AAK5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDC,GACD,OAAO,SAASC,gCACdC,OAAgB,EAChBC,gBAA2C,EAC3CC,KAAoC;IAEpC,qDAAqD;IACrD,kEAAkE;IAClE,IAAIA,UAAU,SAAS,CAACA,OAAO;QAC7B,OAAOC;IACT;IAEA,MAAMC,SAA2B,EAAE;IAEnC,8CAA8C;IAC9C,KAAK,MAAM,CAACC,UAAUC,eAAe,IAAIC,OAAOC,OAAO,CAACN,OAAQ;QAC9D,oDAAoD;QACpD,IAAII,mBAAmB,OAAO;YAC5B;QACF;QAEA,4CAA4C;QAC5C,MAAMG,YAAYH,kBAAkB,CAAC;QAErC,kDAAkD;QAClD,gEAAgE;QAChE,IAAII;QAEJ,qDAAqD;QACrD,KAAK,MAAM,CAACC,gBAAgBC,eAAe,IAAIL,OAAOC,OAAO,CAACP,iBAAiBC,KAAK,EAAG;YACrF,KAAK,MAAMW,iBAAiBD,eAAgB;gBAC1C,IAAIC,cAAcR,QAAQ,KAAKA,UAAU;oBACvCK,YAAY;wBACVC;wBACAG,IAAID,cAAcE,KAAK,CAACD,EAAE;oBAC5B;oBACA;gBACF;YACF;YACA,IAAIJ,WAAW;gBACb;YACF;QACF;QAEA,+BAA+B;QAC/B,IAAI,CAACA,WAAW;YACd,KAAK,MAAMG,iBAAiBZ,iBAAiBe,gBAAgB,CAAE;gBAC7D,IAAIH,cAAcR,QAAQ,KAAKA,UAAU;oBACvC,gEAAgE;oBAChE,MAAMY,cAAcJ,cAAcE,KAAK,CAACG,UAAU;oBAClDR,YAAY;wBACVC,gBAAgBQ,MAAMC,OAAO,CAACH,eAAeA,WAAW,CAAC,EAAE,GAAGA;wBAC9DH,IAAID,cAAcE,KAAK,CAACD,EAAE;oBAC5B;oBACA;gBACF;YACF;QACF;QAEA,IAAI,CAACJ,WAAW;YACdV,QAAQqB,MAAM,CAACC,IAAI,CACjB,CAAC,WAAW,EAAEjB,SAAS,sCAAsC,EAAEJ,iBAAiBsB,IAAI,CAAC,CAAC,CAAC;YAEzF;QACF;QAEA,4EAA4E;QAC5E,IAAIC;QACJ,IAAIf,UAAUgB,IAAI,IAAIhB,UAAUgB,IAAI,GAAG,KAAKhB,UAAUiB,KAAK,EAAE;YAC3DF,SAAS,AAACf,CAAAA,UAAUgB,IAAI,GAAG,CAAA,IAAKhB,UAAUiB,KAAK;QACjD;QAEA,MAAMC,iBAAiC;YACrCC,cAAclB,UAAUC,cAAc;YACtCkB,OAAOpB,UAAUoB,KAAK,IAAI;YAC1Bf,IAAIJ,UAAUI,EAAE;YAChBgB,MAAMzB;YACN,GAAII,UAAUiB,KAAK,KAAKvB,aAAa;gBAAEuB,OAAOjB,UAAUiB,KAAK;YAAC,CAAC;YAC/D,GAAIF,WAAWrB,aAAa;gBAAEqB;YAAO,CAAC;YACtC,GAAIf,UAAUsB,IAAI,IAAI;gBAAEA,MAAMlC,+BAA+BY,UAAUsB,IAAI;YAAE,CAAC;YAC9E,GAAItB,UAAUuB,KAAK,IAAI;gBAAEA,OAAOlC,gCAAgCW,UAAUuB,KAAK;YAAE,CAAC;QACpF;QAEA5B,OAAO6B,IAAI,CAACN;IACd;IAEA,OAAOvB,OAAO8B,MAAM,GAAG,IAAI9B,SAASD;AACtC"}
@@ -0,0 +1,12 @@
1
+ import type { Where } from 'payload';
2
+ import type { components } from '../generated/content-api-types.js';
3
+ type WhereClause = components['schemas']['WhereClause'];
4
+ type ConvertOptions = {
5
+ /** Internal flag to track if we're inside a logical operator (and/or) */
6
+ insideLogicalOperator?: boolean;
7
+ /** If true, transform 'parent' field to 'documentId' (used for version queries) */
8
+ parentToDocumentId?: boolean;
9
+ };
10
+ export declare function convertPayloadWhereToContentAPI(where: undefined | Where, options?: ConvertOptions): WhereClause;
11
+ export {};
12
+ //# sourceMappingURL=where.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"where.d.ts","sourceRoot":"","sources":["../../../src/db-content-api/utilities/where.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAA;AAEnE,KAAK,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,CAAA;AASvD,KAAK,cAAc,GAAG;IACpB,yEAAyE;IACzE,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,mFAAmF;IACnF,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,CAAA;AAED,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,SAAS,GAAG,KAAK,EACxB,OAAO,GAAE,cAAmB,GAC3B,WAAW,CA2Db"}
@@ -0,0 +1,63 @@
1
+ export function convertPayloadWhereToContentAPI(where, options = {}) {
2
+ // Empty where {} should be { and: [] } not undefined
3
+ // Content API requires a where clause structure even for "no filter"
4
+ if (!where || Object.keys(where).length === 0) {
5
+ return {
6
+ and: []
7
+ };
8
+ }
9
+ const conditions = [];
10
+ for (const [key, value] of Object.entries(where)){
11
+ if (key === 'and') {
12
+ // Recursively convert nested 'and' conditions, preserving options
13
+ const nestedConditions = value.map((item)=>convertPayloadWhereToContentAPI(item, {
14
+ ...options,
15
+ insideLogicalOperator: true
16
+ }));
17
+ return {
18
+ and: nestedConditions
19
+ };
20
+ } else if (key === 'or') {
21
+ // Recursively convert nested 'or' conditions, preserving options
22
+ const nestedConditions = value.map((item)=>convertPayloadWhereToContentAPI(item, {
23
+ ...options,
24
+ insideLogicalOperator: true
25
+ }));
26
+ return {
27
+ or: nestedConditions
28
+ };
29
+ } else {
30
+ // TODO: fix this in content api
31
+ // WORKAROUND: Payload uses 'parent' for version queries, but Content API expects 'documentId'
32
+ let fieldPath = key;
33
+ if (options.parentToDocumentId && key === 'parent') {
34
+ fieldPath = 'documentId';
35
+ }
36
+ // Convert field conditions: { fieldName: { operator: value } }
37
+ // to: { path: fieldName, operator, value }
38
+ const operators = value;
39
+ for (const [op, operatorValue] of Object.entries(operators)){
40
+ let finalValue = operatorValue;
41
+ // Add wildcards for contains/like operators (Payload doesn't add them)
42
+ if ((op === 'contains' || op === 'like') && typeof operatorValue === 'string') {
43
+ finalValue = `%${operatorValue}%`;
44
+ }
45
+ conditions.push({
46
+ operator: op,
47
+ path: fieldPath,
48
+ value: finalValue
49
+ });
50
+ }
51
+ }
52
+ }
53
+ // If inside a logical operator (and/or), return conditions directly
54
+ // Otherwise, wrap in 'and' to match WhereClause type
55
+ if (options.insideLogicalOperator && conditions.length === 1) {
56
+ return conditions[0];
57
+ }
58
+ return {
59
+ and: conditions
60
+ };
61
+ }
62
+
63
+ //# sourceMappingURL=where.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/db-content-api/utilities/where.ts"],"sourcesContent":["import type { Where } from 'payload'\n\nimport type { components } from '../generated/content-api-types.js'\n\ntype WhereClause = components['schemas']['WhereClause']\n\n// Payload's format: { fieldName: { operator: value }, and: [...], or: [...] }\n// Content API expects: { and: [{ path, operator, value }], or: [{ path, operator, value }] }\n//\n// The format stays different. This allows the Content API to evolve its filter schema,\n// for example to support composite types like Point, which are not lexicographically sortable.\n// Semantics must remain identical to Payload.\n\ntype ConvertOptions = {\n /** Internal flag to track if we're inside a logical operator (and/or) */\n insideLogicalOperator?: boolean\n /** If true, transform 'parent' field to 'documentId' (used for version queries) */\n parentToDocumentId?: boolean\n}\n\nexport function convertPayloadWhereToContentAPI(\n where: undefined | Where,\n options: ConvertOptions = {},\n): WhereClause {\n // Empty where {} should be { and: [] } not undefined\n // Content API requires a where clause structure even for \"no filter\"\n if (!where || Object.keys(where).length === 0) {\n return { and: [] }\n }\n\n // Extract the condition type (the variant with 'path', 'operator', 'value') from WhereClause union\n type WhereCondition = Extract<WhereClause, { path: string }>\n const conditions: WhereClause[] = []\n\n for (const [key, value] of Object.entries(where)) {\n if (key === 'and') {\n // Recursively convert nested 'and' conditions, preserving options\n const nestedConditions = (value as Where[]).map((item) =>\n convertPayloadWhereToContentAPI(item, { ...options, insideLogicalOperator: true }),\n )\n return { and: nestedConditions }\n } else if (key === 'or') {\n // Recursively convert nested 'or' conditions, preserving options\n const nestedConditions = (value as Where[]).map((item) =>\n convertPayloadWhereToContentAPI(item, { ...options, insideLogicalOperator: true }),\n )\n return { or: nestedConditions }\n } else {\n // TODO: fix this in content api\n // WORKAROUND: Payload uses 'parent' for version queries, but Content API expects 'documentId'\n let fieldPath = key\n if (options.parentToDocumentId && key === 'parent') {\n fieldPath = 'documentId'\n }\n\n // Convert field conditions: { fieldName: { operator: value } }\n // to: { path: fieldName, operator, value }\n const operators = value as Record<string, unknown>\n for (const [op, operatorValue] of Object.entries(operators)) {\n let finalValue = operatorValue\n\n // Add wildcards for contains/like operators (Payload doesn't add them)\n if ((op === 'contains' || op === 'like') && typeof operatorValue === 'string') {\n finalValue = `%${operatorValue}%`\n }\n\n conditions.push({\n operator: op as WhereCondition['operator'],\n path: fieldPath,\n value: finalValue,\n } as WhereCondition)\n }\n }\n }\n\n // If inside a logical operator (and/or), return conditions directly\n // Otherwise, wrap in 'and' to match WhereClause type\n if (options.insideLogicalOperator && conditions.length === 1) {\n return conditions[0]\n }\n\n return { and: conditions }\n}\n"],"names":["convertPayloadWhereToContentAPI","where","options","Object","keys","length","and","conditions","key","value","entries","nestedConditions","map","item","insideLogicalOperator","or","fieldPath","parentToDocumentId","operators","op","operatorValue","finalValue","push","operator","path"],"mappings":"AAoBA,OAAO,SAASA,gCACdC,KAAwB,EACxBC,UAA0B,CAAC,CAAC;IAE5B,qDAAqD;IACrD,qEAAqE;IACrE,IAAI,CAACD,SAASE,OAAOC,IAAI,CAACH,OAAOI,MAAM,KAAK,GAAG;QAC7C,OAAO;YAAEC,KAAK,EAAE;QAAC;IACnB;IAIA,MAAMC,aAA4B,EAAE;IAEpC,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIN,OAAOO,OAAO,CAACT,OAAQ;QAChD,IAAIO,QAAQ,OAAO;YACjB,kEAAkE;YAClE,MAAMG,mBAAmB,AAACF,MAAkBG,GAAG,CAAC,CAACC,OAC/Cb,gCAAgCa,MAAM;oBAAE,GAAGX,OAAO;oBAAEY,uBAAuB;gBAAK;YAElF,OAAO;gBAAER,KAAKK;YAAiB;QACjC,OAAO,IAAIH,QAAQ,MAAM;YACvB,iEAAiE;YACjE,MAAMG,mBAAmB,AAACF,MAAkBG,GAAG,CAAC,CAACC,OAC/Cb,gCAAgCa,MAAM;oBAAE,GAAGX,OAAO;oBAAEY,uBAAuB;gBAAK;YAElF,OAAO;gBAAEC,IAAIJ;YAAiB;QAChC,OAAO;YACL,gCAAgC;YAChC,8FAA8F;YAC9F,IAAIK,YAAYR;YAChB,IAAIN,QAAQe,kBAAkB,IAAIT,QAAQ,UAAU;gBAClDQ,YAAY;YACd;YAEA,+DAA+D;YAC/D,2CAA2C;YAC3C,MAAME,YAAYT;YAClB,KAAK,MAAM,CAACU,IAAIC,cAAc,IAAIjB,OAAOO,OAAO,CAACQ,WAAY;gBAC3D,IAAIG,aAAaD;gBAEjB,uEAAuE;gBACvE,IAAI,AAACD,CAAAA,OAAO,cAAcA,OAAO,MAAK,KAAM,OAAOC,kBAAkB,UAAU;oBAC7EC,aAAa,CAAC,CAAC,EAAED,cAAc,CAAC,CAAC;gBACnC;gBAEAb,WAAWe,IAAI,CAAC;oBACdC,UAAUJ;oBACVK,MAAMR;oBACNP,OAAOY;gBACT;YACF;QACF;IACF;IAEA,oEAAoE;IACpE,qDAAqD;IACrD,IAAInB,QAAQY,qBAAqB,IAAIP,WAAWF,MAAM,KAAK,GAAG;QAC5D,OAAOE,UAAU,CAAC,EAAE;IACtB;IAEA,OAAO;QAAED,KAAKC;IAAW;AAC3B"}
@@ -0,0 +1,3 @@
1
+ import type { Endpoint } from 'payload';
2
+ export declare const health: Endpoint;
3
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/endpoints/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEvC,eAAO,MAAM,MAAM,EAAE,QAMpB,CAAA"}
@@ -0,0 +1,11 @@
1
+ export const health = {
2
+ handler: ()=>{
3
+ return Response.json({
4
+ status: 200
5
+ });
6
+ },
7
+ method: 'get',
8
+ path: '/health'
9
+ };
10
+
11
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/endpoints/health.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nexport const health: Endpoint = {\n handler: () => {\n return Response.json({ status: 200 })\n },\n method: 'get',\n path: '/health',\n}\n"],"names":["health","handler","Response","json","status","method","path"],"mappings":"AAEA,OAAO,MAAMA,SAAmB;IAC9BC,SAAS;QACP,OAAOC,SAASC,IAAI,CAAC;YAAEC,QAAQ;QAAI;IACrC;IACAC,QAAQ;IACRC,MAAM;AACR,EAAC"}
@@ -0,0 +1,3 @@
1
+ export { DefaultLoginButton } from '../oauth/components/LoginButton/index.js';
2
+ export { LogoutButton } from '../oauth/components/LogoutButton/index.js';
3
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAA;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { DefaultLoginButton } from '../oauth/components/LoginButton/index.js';
2
+ export { LogoutButton } from '../oauth/components/LogoutButton/index.js';
3
+
4
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { DefaultLoginButton } from '../oauth/components/LoginButton/index.js'\nexport { LogoutButton } from '../oauth/components/LogoutButton/index.js'\n"],"names":["DefaultLoginButton","LogoutButton"],"mappings":"AAAA,SAASA,kBAAkB,QAAQ,2CAA0C;AAC7E,SAASC,YAAY,QAAQ,4CAA2C"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
+ export { contentAPIAdapter } from './db-content-api/index.js';
1
2
  export { figmaContentSystem } from './plugin/adapter.js';
2
3
  export type { FigmaContentSystemOptions } from './plugin/adapter.js';
3
- export { buildConfig } from './plugin/build-config.js';
4
+ export { buildFigmaConfig } from './plugin/build-config.js';
4
5
  export type { FigmaConfig } from './plugin/build-config.js';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACxD,YAAY,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAGpE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAG7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACxD,YAAY,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAGpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA"}
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
+ // Export contentAPIAdapter for testing use cases
2
+ export { contentAPIAdapter } from './db-content-api/index.js';
1
3
  // Export database adapter for advanced use cases
2
4
  export { figmaContentSystem } from './plugin/adapter.js';
3
5
  // Export buildConfig wrapper and its config type
4
- export { buildConfig } from './plugin/build-config.js';
6
+ export { buildFigmaConfig } from './plugin/build-config.js';
5
7
 
6
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Export database adapter for advanced use cases\nexport { figmaContentSystem } from './plugin/adapter.js'\nexport type { FigmaContentSystemOptions } from './plugin/adapter.js'\n\n// Export buildConfig wrapper and its config type\nexport { buildConfig } from './plugin/build-config.js'\nexport type { FigmaConfig } from './plugin/build-config.js'\n"],"names":["figmaContentSystem","buildConfig"],"mappings":"AAAA,iDAAiD;AACjD,SAASA,kBAAkB,QAAQ,sBAAqB;AAGxD,iDAAiD;AACjD,SAASC,WAAW,QAAQ,2BAA0B"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Export contentAPIAdapter for testing use cases\nexport { contentAPIAdapter } from './db-content-api/index.js'\n\n// Export database adapter for advanced use cases\nexport { figmaContentSystem } from './plugin/adapter.js'\nexport type { FigmaContentSystemOptions } from './plugin/adapter.js'\n\n// Export buildConfig wrapper and its config type\nexport { buildFigmaConfig } from './plugin/build-config.js'\nexport type { FigmaConfig } from './plugin/build-config.js'\n"],"names":["contentAPIAdapter","figmaContentSystem","buildFigmaConfig"],"mappings":"AAAA,iDAAiD;AACjD,SAASA,iBAAiB,QAAQ,4BAA2B;AAE7D,iDAAiD;AACjD,SAASC,kBAAkB,QAAQ,sBAAqB;AAGxD,iDAAiD;AACjD,SAASC,gBAAgB,QAAQ,2BAA0B"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/oauth/components/LoginButton/index.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAElD,OAAO,cAAc,CAAA;AAIrB,KAAK,uBAAuB,GAAG;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAoDhE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/oauth/components/LoginButton/index.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA8B,MAAM,OAAO,CAAA;AAElD,OAAO,cAAc,CAAA;AAgDrB,KAAK,uBAAuB,GAAG;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAqDhE,CAAA"}
@@ -1,10 +1,49 @@
1
1
  'use client';
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- import { Button, useConfig } from '@payloadcms/ui';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useConfig } from '@payloadcms/ui';
4
4
  import { useSearchParams } from 'next/navigation.js';
5
5
  import React, { useEffect, useState } from 'react';
6
6
  import './index.scss';
7
7
  const baseClass = 'oauth-login';
8
+ // Figma logo SVG colored version
9
+ // const FigmaIcon: React.FC = () => (
10
+ // <svg fill="none" height="27" viewBox="0 0 400 600" width="18">
11
+ // <path
12
+ // d="M0 500C0 444.772 44.772 400 100 400H200V500C200 555.228 155.228 600 100 600C44.772 600 0 555.228 0 500Z"
13
+ // fill="#24CB71"
14
+ // />
15
+ // <path
16
+ // d="M200 0V200H300C355.228 200 400 155.228 400 100C400 44.772 355.228 0 300 0H200Z"
17
+ // fill="#FF7237"
18
+ // />
19
+ // <path
20
+ // d="M299.167 400C354.395 400 399.167 355.228 399.167 300C399.167 244.772 354.395 200 299.167 200C243.939 200 199.167 244.772 199.167 300C199.167 355.228 243.939 400 299.167 400Z"
21
+ // fill="#00B6FF"
22
+ // />
23
+ // <path
24
+ // d="M0 100C0 155.228 44.772 200 100 200H200V0H100C44.772 0 0 44.772 0 100Z"
25
+ // fill="#FF3737"
26
+ // />
27
+ // <path
28
+ // d="M0 300C0 355.228 44.772 400 100 400H200V200H100C44.772 200 0 244.772 0 300Z"
29
+ // fill="#874FFF"
30
+ // />
31
+ // </svg>
32
+ // )
33
+ // Figma logo SVG monochrome version
34
+ const FigmaIcon = ()=>/*#__PURE__*/ _jsx("svg", {
35
+ fill: "none",
36
+ height: "20px",
37
+ viewBox: "0 0 15 15",
38
+ width: "20px",
39
+ xmlns: "http://www.w3.org/2000/svg",
40
+ children: /*#__PURE__*/ _jsx("path", {
41
+ clipRule: "evenodd",
42
+ d: "M7.00005 2.04999H5.52505C4.71043 2.04999 4.05005 2.71037 4.05005 3.52499C4.05005 4.33961 4.71043 4.99999 5.52505 4.99999H7.00005V2.04999ZM7.00005 1.04999H8.00005H9.47505C10.842 1.04999 11.95 2.15808 11.95 3.52499C11.95 4.33163 11.5642 5.04815 10.9669 5.49999C11.5642 5.95184 11.95 6.66836 11.95 7.475C11.95 8.8419 10.842 9.95 9.47505 9.95C8.92236 9.95 8.41198 9.76884 8.00005 9.46266V9.95L8.00005 11.425C8.00005 12.7919 6.89195 13.9 5.52505 13.9C4.15814 13.9 3.05005 12.7919 3.05005 11.425C3.05005 10.6183 3.43593 9.90184 4.03317 9.44999C3.43593 8.99814 3.05005 8.28163 3.05005 7.475C3.05005 6.66836 3.43594 5.95184 4.03319 5.5C3.43594 5.04815 3.05005 4.33163 3.05005 3.52499C3.05005 2.15808 4.15814 1.04999 5.52505 1.04999H7.00005ZM8.00005 2.04999V4.99999H9.47505C10.2897 4.99999 10.95 4.33961 10.95 3.52499C10.95 2.71037 10.2897 2.04999 9.47505 2.04999H8.00005ZM5.52505 8.94998H7.00005L7.00005 7.4788L7.00005 7.475L7.00005 7.4712V6H5.52505C4.71043 6 4.05005 6.66038 4.05005 7.475C4.05005 8.28767 4.70727 8.94684 5.5192 8.94999L5.52505 8.94998ZM4.05005 11.425C4.05005 10.6123 4.70727 9.95315 5.5192 9.94999L5.52505 9.95H7.00005L7.00005 11.425C7.00005 12.2396 6.33967 12.9 5.52505 12.9C4.71043 12.9 4.05005 12.2396 4.05005 11.425ZM8.00005 7.47206C8.00164 6.65879 8.66141 6 9.47505 6C10.2897 6 10.95 6.66038 10.95 7.475C10.95 8.28962 10.2897 8.95 9.47505 8.95C8.66141 8.95 8.00164 8.29121 8.00005 7.47794V7.47206Z",
43
+ fill: "#FFFFFF",
44
+ fillRule: "evenodd"
45
+ })
46
+ });
8
47
  export const DefaultLoginButton = ({ disabled, endpointSlug })=>{
9
48
  const { config: { admin: { user: userSlug }, routes: { api }, serverURL } } = useConfig();
10
49
  const [authorizeURL, setAuthorizeURL] = useState('');
@@ -40,11 +79,16 @@ export const DefaultLoginButton = ({ disabled, endpointSlug })=>{
40
79
  }
41
80
  return /*#__PURE__*/ _jsx("div", {
42
81
  className: baseClass,
43
- children: /*#__PURE__*/ _jsx(Button, {
82
+ children: /*#__PURE__*/ _jsxs("a", {
44
83
  className: `${baseClass}__btn`,
45
- el: "anchor",
46
- url: authorizeURL,
47
- children: "Log in"
84
+ href: authorizeURL,
85
+ children: [
86
+ /*#__PURE__*/ _jsx(FigmaIcon, {}),
87
+ /*#__PURE__*/ _jsx("span", {
88
+ className: `${baseClass}__text`,
89
+ children: "Log in with Figma"
90
+ })
91
+ ]
48
92
  })
49
93
  });
50
94
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/oauth/components/LoginButton/index.tsx"],"sourcesContent":["'use client'\n\nimport { Button, useConfig } from '@payloadcms/ui'\nimport { useSearchParams } from 'next/navigation.js'\nimport React, { useEffect, useState } from 'react'\n\nimport './index.scss'\n\nconst baseClass = 'oauth-login'\n\ntype DefaultLoginButtonProps = {\n disabled?: boolean\n endpointSlug: string\n}\n\nexport const DefaultLoginButton: React.FC<DefaultLoginButtonProps> = ({\n disabled,\n endpointSlug,\n}: {\n disabled?: boolean\n endpointSlug: string\n}) => {\n const {\n config: {\n admin: { user: userSlug },\n routes: { api },\n serverURL,\n },\n } = useConfig()\n const [authorizeURL, setAuthorizeURL] = useState('')\n\n const searchParams = useSearchParams()\n const payloadRedirect = searchParams.get('redirect')\n\n useEffect(() => {\n if (payloadRedirect && !disabled) {\n // set cookie to redirect to the original page\n document.cookie = `payloadRedirect=${payloadRedirect}; path=/`\n }\n }, [payloadRedirect, disabled])\n\n useEffect(() => {\n const getAuthorizeURL = async () => {\n const serverURLFromWindow = window.location.origin\n const data = await fetch(\n `${serverURL}${api}/${userSlug}/${endpointSlug}/meta?serverURL=${serverURLFromWindow}`,\n ).then((res) => res.json())\n\n if (!disabled) {\n setAuthorizeURL(data.authorizeURL)\n }\n }\n\n void getAuthorizeURL()\n }, [api, serverURL, userSlug, disabled, endpointSlug])\n\n if (disabled) {\n return null\n }\n\n return (\n <div className={baseClass}>\n <Button className={`${baseClass}__btn`} el=\"anchor\" url={authorizeURL}>\n Log in\n </Button>\n </div>\n )\n}\n"],"names":["Button","useConfig","useSearchParams","React","useEffect","useState","baseClass","DefaultLoginButton","disabled","endpointSlug","config","admin","user","userSlug","routes","api","serverURL","authorizeURL","setAuthorizeURL","searchParams","payloadRedirect","get","document","cookie","getAuthorizeURL","serverURLFromWindow","window","location","origin","data","fetch","then","res","json","div","className","el","url"],"mappings":"AAAA;;AAEA,SAASA,MAAM,EAAEC,SAAS,QAAQ,iBAAgB;AAClD,SAASC,eAAe,QAAQ,qBAAoB;AACpD,OAAOC,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAElD,OAAO,eAAc;AAErB,MAAMC,YAAY;AAOlB,OAAO,MAAMC,qBAAwD,CAAC,EACpEC,QAAQ,EACRC,YAAY,EAIb;IACC,MAAM,EACJC,QAAQ,EACNC,OAAO,EAAEC,MAAMC,QAAQ,EAAE,EACzBC,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,EACF,GAAGf;IACJ,MAAM,CAACgB,cAAcC,gBAAgB,GAAGb,SAAS;IAEjD,MAAMc,eAAejB;IACrB,MAAMkB,kBAAkBD,aAAaE,GAAG,CAAC;IAEzCjB,UAAU;QACR,IAAIgB,mBAAmB,CAACZ,UAAU;YAChC,8CAA8C;YAC9Cc,SAASC,MAAM,GAAG,CAAC,gBAAgB,EAAEH,gBAAgB,QAAQ,CAAC;QAChE;IACF,GAAG;QAACA;QAAiBZ;KAAS;IAE9BJ,UAAU;QACR,MAAMoB,kBAAkB;YACtB,MAAMC,sBAAsBC,OAAOC,QAAQ,CAACC,MAAM;YAClD,MAAMC,OAAO,MAAMC,MACjB,GAAGd,YAAYD,IAAI,CAAC,EAAEF,SAAS,CAAC,EAAEJ,aAAa,gBAAgB,EAAEgB,qBAAqB,EACtFM,IAAI,CAAC,CAACC,MAAQA,IAAIC,IAAI;YAExB,IAAI,CAACzB,UAAU;gBACbU,gBAAgBW,KAAKZ,YAAY;YACnC;QACF;QAEA,KAAKO;IACP,GAAG;QAACT;QAAKC;QAAWH;QAAUL;QAAUC;KAAa;IAErD,IAAID,UAAU;QACZ,OAAO;IACT;IAEA,qBACE,KAAC0B;QAAIC,WAAW7B;kBACd,cAAA,KAACN;YAAOmC,WAAW,GAAG7B,UAAU,KAAK,CAAC;YAAE8B,IAAG;YAASC,KAAKpB;sBAAc;;;AAK7E,EAAC"}
1
+ {"version":3,"sources":["../../../../src/oauth/components/LoginButton/index.tsx"],"sourcesContent":["'use client'\n\nimport { useConfig } from '@payloadcms/ui'\nimport { useSearchParams } from 'next/navigation.js'\nimport React, { useEffect, useState } from 'react'\n\nimport './index.scss'\n\nconst baseClass = 'oauth-login'\n\n// Figma logo SVG colored version\n// const FigmaIcon: React.FC = () => (\n// <svg fill=\"none\" height=\"27\" viewBox=\"0 0 400 600\" width=\"18\">\n// <path\n// d=\"M0 500C0 444.772 44.772 400 100 400H200V500C200 555.228 155.228 600 100 600C44.772 600 0 555.228 0 500Z\"\n// fill=\"#24CB71\"\n// />\n// <path\n// d=\"M200 0V200H300C355.228 200 400 155.228 400 100C400 44.772 355.228 0 300 0H200Z\"\n// fill=\"#FF7237\"\n// />\n// <path\n// d=\"M299.167 400C354.395 400 399.167 355.228 399.167 300C399.167 244.772 354.395 200 299.167 200C243.939 200 199.167 244.772 199.167 300C199.167 355.228 243.939 400 299.167 400Z\"\n// fill=\"#00B6FF\"\n// />\n// <path\n// d=\"M0 100C0 155.228 44.772 200 100 200H200V0H100C44.772 0 0 44.772 0 100Z\"\n// fill=\"#FF3737\"\n// />\n// <path\n// d=\"M0 300C0 355.228 44.772 400 100 400H200V200H100C44.772 200 0 244.772 0 300Z\"\n// fill=\"#874FFF\"\n// />\n// </svg>\n// )\n\n// Figma logo SVG monochrome version\nconst FigmaIcon: React.FC = () => (\n <svg\n fill=\"none\"\n height=\"20px\"\n viewBox=\"0 0 15 15\"\n width=\"20px\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n clipRule=\"evenodd\"\n d=\"M7.00005 2.04999H5.52505C4.71043 2.04999 4.05005 2.71037 4.05005 3.52499C4.05005 4.33961 4.71043 4.99999 5.52505 4.99999H7.00005V2.04999ZM7.00005 1.04999H8.00005H9.47505C10.842 1.04999 11.95 2.15808 11.95 3.52499C11.95 4.33163 11.5642 5.04815 10.9669 5.49999C11.5642 5.95184 11.95 6.66836 11.95 7.475C11.95 8.8419 10.842 9.95 9.47505 9.95C8.92236 9.95 8.41198 9.76884 8.00005 9.46266V9.95L8.00005 11.425C8.00005 12.7919 6.89195 13.9 5.52505 13.9C4.15814 13.9 3.05005 12.7919 3.05005 11.425C3.05005 10.6183 3.43593 9.90184 4.03317 9.44999C3.43593 8.99814 3.05005 8.28163 3.05005 7.475C3.05005 6.66836 3.43594 5.95184 4.03319 5.5C3.43594 5.04815 3.05005 4.33163 3.05005 3.52499C3.05005 2.15808 4.15814 1.04999 5.52505 1.04999H7.00005ZM8.00005 2.04999V4.99999H9.47505C10.2897 4.99999 10.95 4.33961 10.95 3.52499C10.95 2.71037 10.2897 2.04999 9.47505 2.04999H8.00005ZM5.52505 8.94998H7.00005L7.00005 7.4788L7.00005 7.475L7.00005 7.4712V6H5.52505C4.71043 6 4.05005 6.66038 4.05005 7.475C4.05005 8.28767 4.70727 8.94684 5.5192 8.94999L5.52505 8.94998ZM4.05005 11.425C4.05005 10.6123 4.70727 9.95315 5.5192 9.94999L5.52505 9.95H7.00005L7.00005 11.425C7.00005 12.2396 6.33967 12.9 5.52505 12.9C4.71043 12.9 4.05005 12.2396 4.05005 11.425ZM8.00005 7.47206C8.00164 6.65879 8.66141 6 9.47505 6C10.2897 6 10.95 6.66038 10.95 7.475C10.95 8.28962 10.2897 8.95 9.47505 8.95C8.66141 8.95 8.00164 8.29121 8.00005 7.47794V7.47206Z\"\n fill=\"#FFFFFF\"\n fillRule=\"evenodd\"\n />\n </svg>\n)\n\ntype DefaultLoginButtonProps = {\n disabled?: boolean\n endpointSlug: string\n}\n\nexport const DefaultLoginButton: React.FC<DefaultLoginButtonProps> = ({\n disabled,\n endpointSlug,\n}: {\n disabled?: boolean\n endpointSlug: string\n}) => {\n const {\n config: {\n admin: { user: userSlug },\n routes: { api },\n serverURL,\n },\n } = useConfig()\n const [authorizeURL, setAuthorizeURL] = useState('')\n\n const searchParams = useSearchParams()\n const payloadRedirect = searchParams.get('redirect')\n\n useEffect(() => {\n if (payloadRedirect && !disabled) {\n // set cookie to redirect to the original page\n document.cookie = `payloadRedirect=${payloadRedirect}; path=/`\n }\n }, [payloadRedirect, disabled])\n\n useEffect(() => {\n const getAuthorizeURL = async () => {\n const serverURLFromWindow = window.location.origin\n const data = await fetch(\n `${serverURL}${api}/${userSlug}/${endpointSlug}/meta?serverURL=${serverURLFromWindow}`,\n ).then((res) => res.json())\n\n if (!disabled) {\n setAuthorizeURL(data.authorizeURL)\n }\n }\n\n void getAuthorizeURL()\n }, [api, serverURL, userSlug, disabled, endpointSlug])\n\n if (disabled) {\n return null\n }\n\n return (\n <div className={baseClass}>\n <a className={`${baseClass}__btn`} href={authorizeURL}>\n <FigmaIcon />\n <span className={`${baseClass}__text`}>Log in with Figma</span>\n </a>\n </div>\n )\n}\n"],"names":["useConfig","useSearchParams","React","useEffect","useState","baseClass","FigmaIcon","svg","fill","height","viewBox","width","xmlns","path","clipRule","d","fillRule","DefaultLoginButton","disabled","endpointSlug","config","admin","user","userSlug","routes","api","serverURL","authorizeURL","setAuthorizeURL","searchParams","payloadRedirect","get","document","cookie","getAuthorizeURL","serverURLFromWindow","window","location","origin","data","fetch","then","res","json","div","className","a","href","span"],"mappings":"AAAA;;AAEA,SAASA,SAAS,QAAQ,iBAAgB;AAC1C,SAASC,eAAe,QAAQ,qBAAoB;AACpD,OAAOC,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAElD,OAAO,eAAc;AAErB,MAAMC,YAAY;AAElB,iCAAiC;AACjC,sCAAsC;AACtC,mEAAmE;AACnE,YAAY;AACZ,oHAAoH;AACpH,uBAAuB;AACvB,SAAS;AACT,YAAY;AACZ,2FAA2F;AAC3F,uBAAuB;AACvB,SAAS;AACT,YAAY;AACZ,0LAA0L;AAC1L,uBAAuB;AACvB,SAAS;AACT,YAAY;AACZ,mFAAmF;AACnF,uBAAuB;AACvB,SAAS;AACT,YAAY;AACZ,wFAAwF;AACxF,uBAAuB;AACvB,SAAS;AACT,WAAW;AACX,IAAI;AAEJ,oCAAoC;AACpC,MAAMC,YAAsB,kBAC1B,KAACC;QACCC,MAAK;QACLC,QAAO;QACPC,SAAQ;QACRC,OAAM;QACNC,OAAM;kBAEN,cAAA,KAACC;YACCC,UAAS;YACTC,GAAE;YACFP,MAAK;YACLQ,UAAS;;;AAUf,OAAO,MAAMC,qBAAwD,CAAC,EACpEC,QAAQ,EACRC,YAAY,EAIb;IACC,MAAM,EACJC,QAAQ,EACNC,OAAO,EAAEC,MAAMC,QAAQ,EAAE,EACzBC,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,EACF,GAAG1B;IACJ,MAAM,CAAC2B,cAAcC,gBAAgB,GAAGxB,SAAS;IAEjD,MAAMyB,eAAe5B;IACrB,MAAM6B,kBAAkBD,aAAaE,GAAG,CAAC;IAEzC5B,UAAU;QACR,IAAI2B,mBAAmB,CAACZ,UAAU;YAChC,8CAA8C;YAC9Cc,SAASC,MAAM,GAAG,CAAC,gBAAgB,EAAEH,gBAAgB,QAAQ,CAAC;QAChE;IACF,GAAG;QAACA;QAAiBZ;KAAS;IAE9Bf,UAAU;QACR,MAAM+B,kBAAkB;YACtB,MAAMC,sBAAsBC,OAAOC,QAAQ,CAACC,MAAM;YAClD,MAAMC,OAAO,MAAMC,MACjB,GAAGd,YAAYD,IAAI,CAAC,EAAEF,SAAS,CAAC,EAAEJ,aAAa,gBAAgB,EAAEgB,qBAAqB,EACtFM,IAAI,CAAC,CAACC,MAAQA,IAAIC,IAAI;YAExB,IAAI,CAACzB,UAAU;gBACbU,gBAAgBW,KAAKZ,YAAY;YACnC;QACF;QAEA,KAAKO;IACP,GAAG;QAACT;QAAKC;QAAWH;QAAUL;QAAUC;KAAa;IAErD,IAAID,UAAU;QACZ,OAAO;IACT;IAEA,qBACE,KAAC0B;QAAIC,WAAWxC;kBACd,cAAA,MAACyC;YAAED,WAAW,GAAGxC,UAAU,KAAK,CAAC;YAAE0C,MAAMpB;;8BACvC,KAACrB;8BACD,KAAC0C;oBAAKH,WAAW,GAAGxC,UAAU,MAAM,CAAC;8BAAE;;;;;AAI/C,EAAC"}
@@ -1,10 +1,57 @@
1
1
  .oauth-login {
2
2
  display: flex;
3
3
  justify-content: center;
4
+ padding: 1rem 0;
4
5
 
5
- &__btn:focus {
6
- .btn__icon {
7
- background: none;
6
+ &__btn {
7
+ display: inline-flex;
8
+ align-items: center;
9
+ justify-content: center;
10
+ gap: 0.75rem;
11
+ padding: 0.75rem 1.5rem;
12
+ min-height: 3rem;
13
+ background-color: #4d49fc;
14
+ color: #ffffff;
15
+ border: none;
16
+ border-radius: 0.5rem;
17
+ font-size: 1rem;
18
+ font-weight: 450;
19
+ letter-spacing: 0.05px;
20
+ text-decoration: none;
21
+ cursor: pointer;
22
+ transition: background-color 0.2s ease, transform 0.1s ease;
23
+ box-shadow: none;
24
+
25
+ &:hover {
26
+ background-color: #4440e8;
27
+ transform: translateY(-1px);
28
+ }
29
+
30
+ &:active {
31
+ background-color: #3c38d4;
32
+ transform: translateY(0);
33
+ }
34
+
35
+ &:focus {
36
+ outline: none;
37
+ box-shadow: 0 0 0 2px rgba(77, 73, 252, 0.4);
8
38
  }
9
39
  }
40
+
41
+ &__icon {
42
+ flex-shrink: 0;
43
+ width: 20px;
44
+ height: 20px;
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ color: #ffffff;
49
+ }
50
+
51
+ &__text {
52
+ white-space: nowrap;
53
+ line-height: 1rem;
54
+ font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
55
+ Oxygen, Ubuntu, Cantarell, sans-serif;
56
+ }
10
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/oauth/components/LogoutButton/index.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,cAAc,CAAA;AAIrB,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CA2D/E,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/oauth/components/LogoutButton/index.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,cAAc,CAAA;AAIrB,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CA0D/E,CAAA"}
@@ -17,7 +17,6 @@ export const LogoutButton = ({ disabled, endpointSlug })=>{
17
17
  redirectToSet += `:${port}`;
18
18
  }
19
19
  redirectToSet += getAdminPath(config);
20
- // eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
21
20
  setRedirect(redirectToSet);
22
21
  }, [
23
22
  config
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/oauth/components/LogoutButton/index.tsx"],"sourcesContent":["'use client'\n\nimport { Logout, useConfig } from '@payloadcms/ui'\nimport React from 'react'\n\nimport { getAdminPath } from '../../utilities/getAdminPath.js'\nimport './index.scss'\n\nconst baseClass = 'oauth-logout'\n\nexport const LogoutButton: React.FC<{ disabled?: boolean; endpointSlug: string }> = ({\n disabled,\n endpointSlug,\n}) => {\n const {\n config,\n config: {\n admin: { user: userSlug },\n routes: { api },\n serverURL,\n },\n } = useConfig()\n\n const [redirect, setRedirect] = React.useState('')\n React.useEffect(() => {\n const protocol = window.location.protocol\n const domain = window.location.hostname\n const port = window.location.port\n\n let redirectToSet = `${protocol}//${domain}`\n if (port) {\n redirectToSet += `:${port}`\n }\n\n redirectToSet += getAdminPath(config)\n\n // eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect\n setRedirect(redirectToSet)\n }, [config])\n\n if (!redirect) {\n return null\n }\n\n if (disabled) {\n return <Logout />\n }\n\n return (\n <div className={baseClass}>\n <a\n aria-label=\"Logout\"\n href={`${serverURL}${api}/${userSlug}/${endpointSlug}/logout?redirect=${redirect}`}\n >\n <svg\n className=\"icon icon--logout\"\n fill=\"none\"\n viewBox=\"0 0 25 25\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path className=\"stroke\" d=\"M10 5H18V19H10\" />\n <g>\n <path className=\"stroke\" d=\"M8 8.5L4.46447 12.0355L8 15.5711\" />\n <line className=\"stroke\" x1=\"5\" x2=\"13\" y1=\"12\" y2=\"12\" />\n </g>\n </svg>\n </a>\n </div>\n )\n}\n"],"names":["Logout","useConfig","React","getAdminPath","baseClass","LogoutButton","disabled","endpointSlug","config","admin","user","userSlug","routes","api","serverURL","redirect","setRedirect","useState","useEffect","protocol","window","location","domain","hostname","port","redirectToSet","div","className","a","aria-label","href","svg","fill","viewBox","xmlns","path","d","g","line","x1","x2","y1","y2"],"mappings":"AAAA;;AAEA,SAASA,MAAM,EAAEC,SAAS,QAAQ,iBAAgB;AAClD,OAAOC,WAAW,QAAO;AAEzB,SAASC,YAAY,QAAQ,kCAAiC;AAC9D,OAAO,eAAc;AAErB,MAAMC,YAAY;AAElB,OAAO,MAAMC,eAAuE,CAAC,EACnFC,QAAQ,EACRC,YAAY,EACb;IACC,MAAM,EACJC,MAAM,EACNA,QAAQ,EACNC,OAAO,EAAEC,MAAMC,QAAQ,EAAE,EACzBC,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,EACF,GAAGb;IAEJ,MAAM,CAACc,UAAUC,YAAY,GAAGd,MAAMe,QAAQ,CAAC;IAC/Cf,MAAMgB,SAAS,CAAC;QACd,MAAMC,WAAWC,OAAOC,QAAQ,CAACF,QAAQ;QACzC,MAAMG,SAASF,OAAOC,QAAQ,CAACE,QAAQ;QACvC,MAAMC,OAAOJ,OAAOC,QAAQ,CAACG,IAAI;QAEjC,IAAIC,gBAAgB,GAAGN,SAAS,EAAE,EAAEG,QAAQ;QAC5C,IAAIE,MAAM;YACRC,iBAAiB,CAAC,CAAC,EAAED,MAAM;QAC7B;QAEAC,iBAAiBtB,aAAaK;QAE9B,uFAAuF;QACvFQ,YAAYS;IACd,GAAG;QAACjB;KAAO;IAEX,IAAI,CAACO,UAAU;QACb,OAAO;IACT;IAEA,IAAIT,UAAU;QACZ,qBAAO,KAACN;IACV;IAEA,qBACE,KAAC0B;QAAIC,WAAWvB;kBACd,cAAA,KAACwB;YACCC,cAAW;YACXC,MAAM,GAAGhB,YAAYD,IAAI,CAAC,EAAEF,SAAS,CAAC,EAAEJ,aAAa,iBAAiB,EAAEQ,UAAU;sBAElF,cAAA,MAACgB;gBACCJ,WAAU;gBACVK,MAAK;gBACLC,SAAQ;gBACRC,OAAM;;kCAEN,KAACC;wBAAKR,WAAU;wBAASS,GAAE;;kCAC3B,MAACC;;0CACC,KAACF;gCAAKR,WAAU;gCAASS,GAAE;;0CAC3B,KAACE;gCAAKX,WAAU;gCAASY,IAAG;gCAAIC,IAAG;gCAAKC,IAAG;gCAAKC,IAAG;;;;;;;;AAM/D,EAAC"}
1
+ {"version":3,"sources":["../../../../src/oauth/components/LogoutButton/index.tsx"],"sourcesContent":["'use client'\n\nimport { Logout, useConfig } from '@payloadcms/ui'\nimport React from 'react'\n\nimport { getAdminPath } from '../../utilities/getAdminPath.js'\nimport './index.scss'\n\nconst baseClass = 'oauth-logout'\n\nexport const LogoutButton: React.FC<{ disabled?: boolean; endpointSlug: string }> = ({\n disabled,\n endpointSlug,\n}) => {\n const {\n config,\n config: {\n admin: { user: userSlug },\n routes: { api },\n serverURL,\n },\n } = useConfig()\n\n const [redirect, setRedirect] = React.useState('')\n React.useEffect(() => {\n const protocol = window.location.protocol\n const domain = window.location.hostname\n const port = window.location.port\n\n let redirectToSet = `${protocol}//${domain}`\n if (port) {\n redirectToSet += `:${port}`\n }\n\n redirectToSet += getAdminPath(config)\n\n setRedirect(redirectToSet)\n }, [config])\n\n if (!redirect) {\n return null\n }\n\n if (disabled) {\n return <Logout />\n }\n\n return (\n <div className={baseClass}>\n <a\n aria-label=\"Logout\"\n href={`${serverURL}${api}/${userSlug}/${endpointSlug}/logout?redirect=${redirect}`}\n >\n <svg\n className=\"icon icon--logout\"\n fill=\"none\"\n viewBox=\"0 0 25 25\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path className=\"stroke\" d=\"M10 5H18V19H10\" />\n <g>\n <path className=\"stroke\" d=\"M8 8.5L4.46447 12.0355L8 15.5711\" />\n <line className=\"stroke\" x1=\"5\" x2=\"13\" y1=\"12\" y2=\"12\" />\n </g>\n </svg>\n </a>\n </div>\n )\n}\n"],"names":["Logout","useConfig","React","getAdminPath","baseClass","LogoutButton","disabled","endpointSlug","config","admin","user","userSlug","routes","api","serverURL","redirect","setRedirect","useState","useEffect","protocol","window","location","domain","hostname","port","redirectToSet","div","className","a","aria-label","href","svg","fill","viewBox","xmlns","path","d","g","line","x1","x2","y1","y2"],"mappings":"AAAA;;AAEA,SAASA,MAAM,EAAEC,SAAS,QAAQ,iBAAgB;AAClD,OAAOC,WAAW,QAAO;AAEzB,SAASC,YAAY,QAAQ,kCAAiC;AAC9D,OAAO,eAAc;AAErB,MAAMC,YAAY;AAElB,OAAO,MAAMC,eAAuE,CAAC,EACnFC,QAAQ,EACRC,YAAY,EACb;IACC,MAAM,EACJC,MAAM,EACNA,QAAQ,EACNC,OAAO,EAAEC,MAAMC,QAAQ,EAAE,EACzBC,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,EACF,GAAGb;IAEJ,MAAM,CAACc,UAAUC,YAAY,GAAGd,MAAMe,QAAQ,CAAC;IAC/Cf,MAAMgB,SAAS,CAAC;QACd,MAAMC,WAAWC,OAAOC,QAAQ,CAACF,QAAQ;QACzC,MAAMG,SAASF,OAAOC,QAAQ,CAACE,QAAQ;QACvC,MAAMC,OAAOJ,OAAOC,QAAQ,CAACG,IAAI;QAEjC,IAAIC,gBAAgB,GAAGN,SAAS,EAAE,EAAEG,QAAQ;QAC5C,IAAIE,MAAM;YACRC,iBAAiB,CAAC,CAAC,EAAED,MAAM;QAC7B;QAEAC,iBAAiBtB,aAAaK;QAE9BQ,YAAYS;IACd,GAAG;QAACjB;KAAO;IAEX,IAAI,CAACO,UAAU;QACb,OAAO;IACT;IAEA,IAAIT,UAAU;QACZ,qBAAO,KAACN;IACV;IAEA,qBACE,KAAC0B;QAAIC,WAAWvB;kBACd,cAAA,KAACwB;YACCC,cAAW;YACXC,MAAM,GAAGhB,YAAYD,IAAI,CAAC,EAAEF,SAAS,CAAC,EAAEJ,aAAa,iBAAiB,EAAEQ,UAAU;sBAElF,cAAA,MAACgB;gBACCJ,WAAU;gBACVK,MAAK;gBACLC,SAAQ;gBACRC,OAAM;;kCAEN,KAACC;wBAAKR,WAAU;wBAASS,GAAE;;kCAC3B,MAACC;;0CACC,KAACF;gCAAKR,WAAU;gCAASS,GAAE;;0CAC3B,KAACE;gCAAKX,WAAU;gCAASY,IAAG;gCAAIC,IAAG;gCAAKC,IAAG;gCAAKC,IAAG;;;;;;;;AAM/D,EAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/oauth/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,SAAS,EAAQ,MAAM,SAAS,CAAA;AAI5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAIhD,eAAO,MAAM,YAAY,UAAiC,CAAA;AAE1D,eAAO,MAAM,oBAAoB,EAAE,SAQlC,CAAA;AAED,eAAO,MAAM,aAAa,iDAKrB;IACD,UAAU,EAAE,gBAAgB,CAAA;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,UAAU,GAAG,SAAS,CAAA;CACtC,KAAG,cAiFH,CAAA"}
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/oauth/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,SAAS,EAAQ,MAAM,SAAS,CAAA;AAI5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAKhD,eAAO,MAAM,YAAY,UAAiC,CAAA;AAE1D,eAAO,MAAM,oBAAoB,EAAE,SAQlC,CAAA;AAED,eAAO,MAAM,aAAa,iDAKrB;IACD,UAAU,EAAE,gBAAgB,CAAA;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,UAAU,GAAG,SAAS,CAAA;CACtC,KAAG,cAuGH,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { v4 as uuid } from 'uuid';
2
2
  import { hasUserTokenPropsChanged } from './utilities/hasUserTokenPropsChanged.js';
3
+ import { isDuplicateKeyError } from './utilities/isDuplicateKeyError.js';
3
4
  export const defaultScope = [
4
5
  'openid',
5
6
  'profile',
@@ -60,11 +61,34 @@ export const defaultVerify = ({ collection, strategyName, usernameField })=>asyn
60
61
  if (typeof collection.auth === 'object' && !collection.auth.disableLocalStrategy) {
61
62
  newUser.password = uuid();
62
63
  }
63
- user = await payload.create({
64
- collection: collection.slug,
65
- data: newUser,
66
- depth
67
- });
64
+ try {
65
+ user = await payload.create({
66
+ collection: collection.slug,
67
+ data: newUser,
68
+ depth,
69
+ overrideAccess: true
70
+ });
71
+ } catch (createErr) {
72
+ // Race condition: if unique constraint violation, user was created by concurrent request
73
+ if (isDuplicateKeyError(createErr)) {
74
+ const retryResults = await payload.find({
75
+ collection: collection.slug,
76
+ depth,
77
+ limit: 1,
78
+ pagination: false,
79
+ where: {
80
+ [usernameField.name]: {
81
+ equals: token[tokenUsername]
82
+ }
83
+ }
84
+ });
85
+ if (retryResults.docs.length > 0) {
86
+ user = retryResults.docs[0];
87
+ }
88
+ } else {
89
+ throw createErr;
90
+ }
91
+ }
68
92
  }
69
93
  } catch (err) {
70
94
  payload.logger.error({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/oauth/defaults.ts"],"sourcesContent":["import type { CollectionConfig, EmailField, TextField, User } from 'payload'\n\nimport { v4 as uuid } from 'uuid'\n\nimport type { VerifyFunction } from './types.js'\n\nimport { hasUserTokenPropsChanged } from './utilities/hasUserTokenPropsChanged.js'\n\nexport const defaultScope = ['openid', 'profile', 'email']\n\nexport const defaultUsernameField: TextField = {\n name: 'preferredUsername',\n type: 'text',\n admin: {\n position: 'sidebar',\n readOnly: true,\n },\n unique: true,\n}\n\nexport const defaultVerify =\n ({\n collection,\n strategyName,\n usernameField,\n }: {\n collection: CollectionConfig\n strategyName: string\n usernameField: EmailField | TextField\n }): VerifyFunction =>\n async ({ payload, token }) => {\n let tokenUsername = 'preferred_username'\n\n if (usernameField.name !== 'preferredUsername') {\n tokenUsername = usernameField.name\n }\n\n if (!token[tokenUsername]) {\n return {\n user: null,\n }\n }\n\n let user: null | User = null\n const depth = typeof collection.auth === 'object' ? collection.auth.depth : undefined\n\n try {\n const results = await payload.find({\n collection: collection.slug,\n depth,\n limit: 1,\n pagination: false,\n where: {\n [usernameField.name]: { equals: token[tokenUsername] },\n },\n })\n\n if (results.docs.length > 0) {\n user = results.docs[0] as User\n // Update user with new token data\n if (hasUserTokenPropsChanged(user, token)) {\n user = (await payload.update({\n id: user.id,\n collection: collection.slug,\n data: {\n ...token,\n },\n depth,\n })) as User\n }\n } else {\n const newUser = {\n email: token.preferredUsername || token.email,\n [usernameField.name]: token[tokenUsername],\n ...token,\n }\n\n if (typeof collection.auth === 'object' && !collection.auth.disableLocalStrategy) {\n newUser.password = uuid()\n }\n\n user = (await payload.create({\n collection: collection.slug,\n data: newUser,\n depth,\n })) as User\n }\n } catch (err: unknown) {\n payload.logger.error({\n err,\n msg: 'Error verifying user from defaultVerify.',\n })\n return {\n user: null,\n }\n }\n\n if (user) {\n user.collection = collection.slug\n user._strategy = strategyName\n user.exp = token.exp\n\n return {\n user,\n }\n }\n\n return {\n user: null,\n }\n }\n"],"names":["v4","uuid","hasUserTokenPropsChanged","defaultScope","defaultUsernameField","name","type","admin","position","readOnly","unique","defaultVerify","collection","strategyName","usernameField","payload","token","tokenUsername","user","depth","auth","undefined","results","find","slug","limit","pagination","where","equals","docs","length","update","id","data","newUser","email","preferredUsername","disableLocalStrategy","password","create","err","logger","error","msg","_strategy","exp"],"mappings":"AAEA,SAASA,MAAMC,IAAI,QAAQ,OAAM;AAIjC,SAASC,wBAAwB,QAAQ,0CAAyC;AAElF,OAAO,MAAMC,eAAe;IAAC;IAAU;IAAW;CAAQ,CAAA;AAE1D,OAAO,MAAMC,uBAAkC;IAC7CC,MAAM;IACNC,MAAM;IACNC,OAAO;QACLC,UAAU;QACVC,UAAU;IACZ;IACAC,QAAQ;AACV,EAAC;AAED,OAAO,MAAMC,gBACX,CAAC,EACCC,UAAU,EACVC,YAAY,EACZC,aAAa,EAKd,GACD,OAAO,EAAEC,OAAO,EAAEC,KAAK,EAAE;QACvB,IAAIC,gBAAgB;QAEpB,IAAIH,cAAcT,IAAI,KAAK,qBAAqB;YAC9CY,gBAAgBH,cAAcT,IAAI;QACpC;QAEA,IAAI,CAACW,KAAK,CAACC,cAAc,EAAE;YACzB,OAAO;gBACLC,MAAM;YACR;QACF;QAEA,IAAIA,OAAoB;QACxB,MAAMC,QAAQ,OAAOP,WAAWQ,IAAI,KAAK,WAAWR,WAAWQ,IAAI,CAACD,KAAK,GAAGE;QAE5E,IAAI;YACF,MAAMC,UAAU,MAAMP,QAAQQ,IAAI,CAAC;gBACjCX,YAAYA,WAAWY,IAAI;gBAC3BL;gBACAM,OAAO;gBACPC,YAAY;gBACZC,OAAO;oBACL,CAACb,cAAcT,IAAI,CAAC,EAAE;wBAAEuB,QAAQZ,KAAK,CAACC,cAAc;oBAAC;gBACvD;YACF;YAEA,IAAIK,QAAQO,IAAI,CAACC,MAAM,GAAG,GAAG;gBAC3BZ,OAAOI,QAAQO,IAAI,CAAC,EAAE;gBACtB,kCAAkC;gBAClC,IAAI3B,yBAAyBgB,MAAMF,QAAQ;oBACzCE,OAAQ,MAAMH,QAAQgB,MAAM,CAAC;wBAC3BC,IAAId,KAAKc,EAAE;wBACXpB,YAAYA,WAAWY,IAAI;wBAC3BS,MAAM;4BACJ,GAAGjB,KAAK;wBACV;wBACAG;oBACF;gBACF;YACF,OAAO;gBACL,MAAMe,UAAU;oBACdC,OAAOnB,MAAMoB,iBAAiB,IAAIpB,MAAMmB,KAAK;oBAC7C,CAACrB,cAAcT,IAAI,CAAC,EAAEW,KAAK,CAACC,cAAc;oBAC1C,GAAGD,KAAK;gBACV;gBAEA,IAAI,OAAOJ,WAAWQ,IAAI,KAAK,YAAY,CAACR,WAAWQ,IAAI,CAACiB,oBAAoB,EAAE;oBAChFH,QAAQI,QAAQ,GAAGrC;gBACrB;gBAEAiB,OAAQ,MAAMH,QAAQwB,MAAM,CAAC;oBAC3B3B,YAAYA,WAAWY,IAAI;oBAC3BS,MAAMC;oBACNf;gBACF;YACF;QACF,EAAE,OAAOqB,KAAc;YACrBzB,QAAQ0B,MAAM,CAACC,KAAK,CAAC;gBACnBF;gBACAG,KAAK;YACP;YACA,OAAO;gBACLzB,MAAM;YACR;QACF;QAEA,IAAIA,MAAM;YACRA,KAAKN,UAAU,GAAGA,WAAWY,IAAI;YACjCN,KAAK0B,SAAS,GAAG/B;YACjBK,KAAK2B,GAAG,GAAG7B,MAAM6B,GAAG;YAEpB,OAAO;gBACL3B;YACF;QACF;QAEA,OAAO;YACLA,MAAM;QACR;IACF,EAAC"}
1
+ {"version":3,"sources":["../../src/oauth/defaults.ts"],"sourcesContent":["import type { CollectionConfig, EmailField, TextField, User } from 'payload'\n\nimport { v4 as uuid } from 'uuid'\n\nimport type { VerifyFunction } from './types.js'\n\nimport { hasUserTokenPropsChanged } from './utilities/hasUserTokenPropsChanged.js'\nimport { isDuplicateKeyError } from './utilities/isDuplicateKeyError.js'\n\nexport const defaultScope = ['openid', 'profile', 'email']\n\nexport const defaultUsernameField: TextField = {\n name: 'preferredUsername',\n type: 'text',\n admin: {\n position: 'sidebar',\n readOnly: true,\n },\n unique: true,\n}\n\nexport const defaultVerify =\n ({\n collection,\n strategyName,\n usernameField,\n }: {\n collection: CollectionConfig\n strategyName: string\n usernameField: EmailField | TextField\n }): VerifyFunction =>\n async ({ payload, token }) => {\n let tokenUsername = 'preferred_username'\n\n if (usernameField.name !== 'preferredUsername') {\n tokenUsername = usernameField.name\n }\n\n if (!token[tokenUsername]) {\n return {\n user: null,\n }\n }\n\n let user: null | User = null\n const depth = typeof collection.auth === 'object' ? collection.auth.depth : undefined\n\n try {\n const results = await payload.find({\n collection: collection.slug,\n depth,\n limit: 1,\n pagination: false,\n where: {\n [usernameField.name]: { equals: token[tokenUsername] },\n },\n })\n\n if (results.docs.length > 0) {\n user = results.docs[0] as User\n // Update user with new token data\n if (hasUserTokenPropsChanged(user, token)) {\n user = (await payload.update({\n id: user.id,\n collection: collection.slug,\n data: {\n ...token,\n },\n depth,\n })) as User\n }\n } else {\n const newUser = {\n email: token.preferredUsername || token.email,\n [usernameField.name]: token[tokenUsername],\n ...token,\n }\n\n if (typeof collection.auth === 'object' && !collection.auth.disableLocalStrategy) {\n newUser.password = uuid()\n }\n\n try {\n user = (await payload.create({\n collection: collection.slug,\n data: newUser,\n depth,\n overrideAccess: true,\n })) as User\n } catch (createErr: unknown) {\n // Race condition: if unique constraint violation, user was created by concurrent request\n if (isDuplicateKeyError(createErr)) {\n const retryResults = await payload.find({\n collection: collection.slug,\n depth,\n limit: 1,\n pagination: false,\n where: {\n [usernameField.name]: { equals: token[tokenUsername] },\n },\n })\n\n if (retryResults.docs.length > 0) {\n user = retryResults.docs[0] as User\n }\n } else {\n throw createErr\n }\n }\n }\n } catch (err: unknown) {\n payload.logger.error({\n err,\n msg: 'Error verifying user from defaultVerify.',\n })\n return {\n user: null,\n }\n }\n\n if (user) {\n user.collection = collection.slug\n user._strategy = strategyName\n user.exp = token.exp\n\n return {\n user,\n }\n }\n\n return {\n user: null,\n }\n }\n"],"names":["v4","uuid","hasUserTokenPropsChanged","isDuplicateKeyError","defaultScope","defaultUsernameField","name","type","admin","position","readOnly","unique","defaultVerify","collection","strategyName","usernameField","payload","token","tokenUsername","user","depth","auth","undefined","results","find","slug","limit","pagination","where","equals","docs","length","update","id","data","newUser","email","preferredUsername","disableLocalStrategy","password","create","overrideAccess","createErr","retryResults","err","logger","error","msg","_strategy","exp"],"mappings":"AAEA,SAASA,MAAMC,IAAI,QAAQ,OAAM;AAIjC,SAASC,wBAAwB,QAAQ,0CAAyC;AAClF,SAASC,mBAAmB,QAAQ,qCAAoC;AAExE,OAAO,MAAMC,eAAe;IAAC;IAAU;IAAW;CAAQ,CAAA;AAE1D,OAAO,MAAMC,uBAAkC;IAC7CC,MAAM;IACNC,MAAM;IACNC,OAAO;QACLC,UAAU;QACVC,UAAU;IACZ;IACAC,QAAQ;AACV,EAAC;AAED,OAAO,MAAMC,gBACX,CAAC,EACCC,UAAU,EACVC,YAAY,EACZC,aAAa,EAKd,GACD,OAAO,EAAEC,OAAO,EAAEC,KAAK,EAAE;QACvB,IAAIC,gBAAgB;QAEpB,IAAIH,cAAcT,IAAI,KAAK,qBAAqB;YAC9CY,gBAAgBH,cAAcT,IAAI;QACpC;QAEA,IAAI,CAACW,KAAK,CAACC,cAAc,EAAE;YACzB,OAAO;gBACLC,MAAM;YACR;QACF;QAEA,IAAIA,OAAoB;QACxB,MAAMC,QAAQ,OAAOP,WAAWQ,IAAI,KAAK,WAAWR,WAAWQ,IAAI,CAACD,KAAK,GAAGE;QAE5E,IAAI;YACF,MAAMC,UAAU,MAAMP,QAAQQ,IAAI,CAAC;gBACjCX,YAAYA,WAAWY,IAAI;gBAC3BL;gBACAM,OAAO;gBACPC,YAAY;gBACZC,OAAO;oBACL,CAACb,cAAcT,IAAI,CAAC,EAAE;wBAAEuB,QAAQZ,KAAK,CAACC,cAAc;oBAAC;gBACvD;YACF;YAEA,IAAIK,QAAQO,IAAI,CAACC,MAAM,GAAG,GAAG;gBAC3BZ,OAAOI,QAAQO,IAAI,CAAC,EAAE;gBACtB,kCAAkC;gBAClC,IAAI5B,yBAAyBiB,MAAMF,QAAQ;oBACzCE,OAAQ,MAAMH,QAAQgB,MAAM,CAAC;wBAC3BC,IAAId,KAAKc,EAAE;wBACXpB,YAAYA,WAAWY,IAAI;wBAC3BS,MAAM;4BACJ,GAAGjB,KAAK;wBACV;wBACAG;oBACF;gBACF;YACF,OAAO;gBACL,MAAMe,UAAU;oBACdC,OAAOnB,MAAMoB,iBAAiB,IAAIpB,MAAMmB,KAAK;oBAC7C,CAACrB,cAAcT,IAAI,CAAC,EAAEW,KAAK,CAACC,cAAc;oBAC1C,GAAGD,KAAK;gBACV;gBAEA,IAAI,OAAOJ,WAAWQ,IAAI,KAAK,YAAY,CAACR,WAAWQ,IAAI,CAACiB,oBAAoB,EAAE;oBAChFH,QAAQI,QAAQ,GAAGtC;gBACrB;gBAEA,IAAI;oBACFkB,OAAQ,MAAMH,QAAQwB,MAAM,CAAC;wBAC3B3B,YAAYA,WAAWY,IAAI;wBAC3BS,MAAMC;wBACNf;wBACAqB,gBAAgB;oBAClB;gBACF,EAAE,OAAOC,WAAoB;oBAC3B,yFAAyF;oBACzF,IAAIvC,oBAAoBuC,YAAY;wBAClC,MAAMC,eAAe,MAAM3B,QAAQQ,IAAI,CAAC;4BACtCX,YAAYA,WAAWY,IAAI;4BAC3BL;4BACAM,OAAO;4BACPC,YAAY;4BACZC,OAAO;gCACL,CAACb,cAAcT,IAAI,CAAC,EAAE;oCAAEuB,QAAQZ,KAAK,CAACC,cAAc;gCAAC;4BACvD;wBACF;wBAEA,IAAIyB,aAAab,IAAI,CAACC,MAAM,GAAG,GAAG;4BAChCZ,OAAOwB,aAAab,IAAI,CAAC,EAAE;wBAC7B;oBACF,OAAO;wBACL,MAAMY;oBACR;gBACF;YACF;QACF,EAAE,OAAOE,KAAc;YACrB5B,QAAQ6B,MAAM,CAACC,KAAK,CAAC;gBACnBF;gBACAG,KAAK;YACP;YACA,OAAO;gBACL5B,MAAM;YACR;QACF;QAEA,IAAIA,MAAM;YACRA,KAAKN,UAAU,GAAGA,WAAWY,IAAI;YACjCN,KAAK6B,SAAS,GAAGlC;YACjBK,KAAK8B,GAAG,GAAGhC,MAAMgC,GAAG;YAEpB,OAAO;gBACL9B;YACF;QACF;QAEA,OAAO;YACLA,MAAM;QACR;IACF,EAAC"}