@payloadcms/figma 0.0.1-alpha.26 → 0.0.1-alpha.27

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 (41) hide show
  1. package/dist/api/control-plane.d.ts +18 -0
  2. package/dist/api/control-plane.d.ts.map +1 -1
  3. package/dist/api/control-plane.js +27 -0
  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 +5 -2
  7. package/dist/api/figma-api.js.map +1 -1
  8. package/dist/commands/init.d.ts.map +1 -1
  9. package/dist/commands/init.js +41 -2
  10. package/dist/commands/init.js.map +1 -1
  11. package/dist/config/oauth.js +2 -1
  12. package/dist/config/oauth.js.map +1 -1
  13. package/dist/db-content-api/generated/content-api-types.d.ts +3129 -0
  14. package/dist/db-content-api/generated/content-api-types.d.ts.map +1 -0
  15. package/dist/db-content-api/generated/content-api-types.js +7 -0
  16. package/dist/db-content-api/generated/content-api-types.js.map +1 -0
  17. package/dist/db-content-api/index.d.ts +31 -0
  18. package/dist/db-content-api/index.d.ts.map +1 -0
  19. package/dist/db-content-api/index.js +825 -0
  20. package/dist/db-content-api/index.js.map +1 -0
  21. package/dist/db-content-api/types.d.ts +31 -0
  22. package/dist/db-content-api/types.d.ts.map +1 -0
  23. package/dist/db-content-api/types.js +7 -0
  24. package/dist/db-content-api/types.js.map +1 -0
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +2 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/oauth/endpoints/getLoginEndpoint.js +1 -1
  30. package/dist/oauth/endpoints/getLoginEndpoint.js.map +1 -1
  31. package/dist/oauth/strategy/index.d.ts.map +1 -1
  32. package/dist/oauth/strategy/index.js +4 -0
  33. package/dist/oauth/strategy/index.js.map +1 -1
  34. package/dist/plugin/build-config.d.ts.map +1 -1
  35. package/dist/plugin/build-config.js +35 -17
  36. package/dist/plugin/build-config.js.map +1 -1
  37. package/package.json +3 -1
  38. package/dist/db-adapter.d.ts +0 -17
  39. package/dist/db-adapter.d.ts.map +0 -1
  40. package/dist/db-adapter.js +0 -760
  41. package/dist/db-adapter.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/db-content-api/index.ts"],"sourcesContent":["import type {\n BaseDatabaseAdapter,\n CollectionConfig,\n Count,\n CountGlobalVersions,\n CountVersions,\n Create,\n CreateGlobal,\n CreateGlobalVersion,\n CreateVersion,\n DatabaseAdapterObj,\n DeleteMany,\n DeleteOne,\n DeleteVersions,\n Find,\n FindGlobal,\n FindGlobalVersions,\n FindOne,\n FindVersions,\n GlobalConfig,\n QueryDrafts,\n TraverseFieldsCallback,\n UpdateGlobal,\n UpdateGlobalVersion,\n UpdateMany,\n UpdateOne,\n UpdateVersion,\n Upsert,\n Where,\n} from 'payload'\n\nimport { createDatabaseAdapter, traverseFields } from 'payload'\nimport { v4 as uuid } from 'uuid'\n\nimport type { TokenStore } from '../auth/token-store.js'\nimport type { components } from './generated/content-api-types.js'\n\nimport { getValidProjectToken } from '../auth/project-token.js'\n\n// Field name mapping between Payload and Content API\n// TODO: Update these when Content API renames to internal_id/external_id (or similar)\nconst PAYLOAD_ID_FIELD = 'id'\nconst CONTENT_API_KEY_FIELD = 'key'\n\n// Module-level cache for devJwt tokens (encapsulated, not exposed on adapter)\nconst devJwtCache = new Map<string, string>()\n\n// Private helper to fetch JWT from dev endpoint (not exposed on adapter type)\nasync function fetchDevJwt(url: string, contentSystemId: string): Promise<string> {\n const usesSuperUser =\n !contentSystemId || contentSystemId === 'test-system' || contentSystemId === '*'\n const contentSystemIdForJWT = usesSuperUser ? '*' : contentSystemId\n\n const response = await fetch(`${url}/dev/jwt`, {\n body: JSON.stringify({ content_system_id: contentSystemIdForJWT }),\n headers: { 'Content-Type': 'application/json' },\n method: 'POST',\n })\n\n if (!response.ok) {\n throw new Error(`Failed to get dev JWT: ${response.status} ${response.statusText}`)\n }\n\n const { token } = await response.json()\n return token\n}\n\n// Discriminated union for auth modes\ntype ApiKeyAuth = {\n apiKey: string\n mode: 'apiKey'\n}\n\ntype TokenStoreAuth = {\n mode: 'tokenStore'\n tokenStore: TokenStore\n}\n\ntype DevJwtAuth = {\n mode: 'devJwt'\n}\n\ntype ContentAPIOptions = {\n auth: ApiKeyAuth | DevJwtAuth | TokenStoreAuth\n contentSystemId: string\n url: string\n}\n\nexport type ContentAPIAdapter = {\n auth: ApiKeyAuth | DevJwtAuth | TokenStoreAuth\n contentSystemId: string\n makeRequest<T = unknown>(\n path: string,\n options?: { body?: Record<string, unknown>; method?: string; retryCount?: number },\n ): Promise<T>\n url: string\n} & BaseDatabaseAdapter\n\nasync function init(this: ContentAPIAdapter) {\n // Log which auth mode is being used\n if (this.auth.mode === 'apiKey') {\n this.payload.logger.info('Using API Key authentication')\n } else if (this.auth.mode === 'tokenStore') {\n this.payload.logger.info('Using TokenStore authentication (local dev)')\n } else {\n this.payload.logger.info('Using Dev JWT authentication (testing)')\n }\n\n // Drop database if PAYLOAD_DROP_DATABASE is set (for tests)\n if (process.env.PAYLOAD_DROP_DATABASE === 'true') {\n this.payload.logger.info(`---- DROPPING CONTENT API SYSTEM (${this.contentSystemId}) ----`)\n try {\n await this.makeRequest('/dev/clear-db', {\n body: { contentSystemId: this.contentSystemId },\n method: 'POST',\n })\n this.payload.logger.info('---- DROPPED CONTENT API SYSTEM ----')\n } catch (error) {\n this.payload.logger.warn(`Failed to drop content system: ${(error as Error).message}`)\n }\n }\n\n // Create collections if they don't exist\n for (const collection of this.payload.config.collections) {\n await createCollectionIfNotExists.call(this, collection.slug)\n }\n\n // Create global collections\n for (const global of this.payload.config.globals || []) {\n await createCollectionIfNotExists.call(this, `_global-${global.slug}`)\n }\n\n return\n}\n\n// Helper to create a collection if it doesn't exist\nasync function createCollectionIfNotExists(this: ContentAPIAdapter, collectionKey: string) {\n try {\n await this.makeRequest('/api/v0/collections', {\n body: {\n name: collectionKey,\n contentSystemId: this.contentSystemId,\n key: collectionKey,\n },\n method: 'POST',\n })\n this.payload.logger.info(`Created collection: ${collectionKey}`)\n } catch (error) {\n // If collection already exists, that's fine - ignore the error\n const errorMessage = (error as Error).message\n if (!errorMessage.includes('already exists') && !errorMessage.includes('409')) {\n this.payload.logger.warn(`Failed to create collection ${collectionKey}: ${errorMessage}`)\n }\n }\n}\n\n// Helper function to make HTTP requests to the Content API\nasync function makeRequest<T>(\n this: ContentAPIAdapter,\n path: string,\n options: {\n body?: Record<string, unknown>\n method?: string\n retryCount?: number\n } = {},\n): Promise<T> {\n const { body, method = 'POST', retryCount = 0 } = options\n\n // Build auth header based on auth mode\n let authHeader: Record<string, string>\n\n if (this.auth.mode === 'apiKey') {\n authHeader = { 'X-Api-Key': this.auth.apiKey }\n } else if (this.auth.mode === 'tokenStore') {\n const token = await getValidProjectToken(this.auth.tokenStore, this.contentSystemId)\n if (!token) {\n throw new Error('Authentication required. Run `npx @payloadcms/figma login` to authenticate.')\n }\n authHeader = { Authorization: `Bearer ${token}` }\n } else {\n // devJwt - inline cache handling\n let token = devJwtCache.get(this.contentSystemId)\n if (!token) {\n token = await fetchDevJwt(this.url, this.contentSystemId)\n devJwtCache.set(this.contentSystemId, token)\n this.payload.logger.info(`Dev JWT acquired for content system: ${this.contentSystemId}`)\n }\n authHeader = { Authorization: `Bearer ${token}` }\n }\n\n const requestUrl = `${this.url}${path}`\n const response = await fetch(requestUrl, {\n body: body ? JSON.stringify(body) : undefined,\n headers: { 'Content-Type': 'application/json', ...authHeader },\n method,\n })\n\n // Read response as text first (better for debugging)\n const text = await response.text()\n\n // Handle 401 - retry logic differs per mode\n if (response.status === 401 && retryCount === 0 && this.auth.mode === 'devJwt') {\n this.payload.logger.info('Dev JWT expired, refreshing...')\n devJwtCache.delete(this.contentSystemId)\n return this.makeRequest(path, { body, method, retryCount: retryCount + 1 })\n }\n // tokenStore handles refresh internally via getValidProjectToken\n // apiKey doesn't expire - 401 means invalid key\n\n // Check HTTP status\n if (!response.ok) {\n this.payload.logger.error({ msg: `HTTP ${response.status} from ${path}`, response: text })\n throw new Error(`Content API HTTP ${response.status}: ${text.substring(0, 200)}`)\n }\n\n // Parse JSON response\n try {\n const parsed = JSON.parse(text)\n\n // Check if the response is an error object (HTTP 200 but with error in body)\n if (parsed && typeof parsed === 'object' && 'error' in parsed) {\n throw new Error(`Content API error: ${parsed.message || parsed.error}`)\n }\n\n return parsed as T\n } catch (error) {\n // If it's already our custom error, re-throw it\n if (error instanceof Error && error.message.startsWith('Content API error:')) {\n throw error\n }\n\n this.payload.logger.error({\n err: error instanceof Error ? error : new Error(String(error)),\n msg: `Failed to parse JSON response from ${path}`,\n response: text,\n })\n throw new Error(`Invalid JSON response from content API: ${text.substring(0, 100)}...`)\n }\n}\n\n// ⚠️ TEMPORARY WORKAROUND - Remove once Content API is fixed\n//\n// TODO: Content API should accept Payload's native Where format instead of requiring conversion.\n// This converter exists because after a GitHub merge, Content API changed to expect a different format.\n//\n// Payload's format: { fieldName: { operator: value }, and: [...], or: [...] }\n// Content API expects: { and: [{ path, operator, value }], or: [{ path, operator, value }] }\n//\n// Once Content API accepts Payload's format:\n// 1. Remove this function entirely\n// 2. Remove all calls to convertPayloadWhereToContentAPI()\n// 3. Pass `where` directly to Content API endpoints\n// 4. Update CONTENT_API_ISSUES.md to mark Workaround #1 as resolved\nfunction convertPayloadWhereToContentAPI(\n where: undefined | Where,\n insideLogicalOperator: boolean = false,\n):\n | ({ path: string } & components['schemas']['WhereClause'])\n | components['schemas']['WhereClause'] {\n // ⚠️ WORKAROUND: 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<components['schemas']['WhereClause'], { path: string }>\n const conditions: (components['schemas']['WhereClause'] | WhereCondition)[] = []\n\n for (const [key, value] of Object.entries(where)) {\n if (key === 'and') {\n // Recursively convert nested 'and' conditions\n const nestedConditions = (value as Where[]).map((item) =>\n convertPayloadWhereToContentAPI(item, true),\n )\n return { and: nestedConditions }\n } else if (key === 'or') {\n // Recursively convert nested 'or' conditions\n const nestedConditions = (value as Where[]).map((item) =>\n convertPayloadWhereToContentAPI(item, true),\n )\n return { or: nestedConditions }\n } else {\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 // Map Payload's 'id' field to Content API's 'key' field\n operator: op as WhereCondition['operator'],\n path: key === PAYLOAD_ID_FIELD ? CONTENT_API_KEY_FIELD : key,\n value: finalValue,\n })\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 (insideLogicalOperator && conditions.length === 1) {\n return conditions[0] as any\n }\n\n return { and: conditions } as components['schemas']['WhereClause']\n}\n\n// Add fallback sort to ensure consistent ordering when sorting by non-unique fields\n// Matches MongoDB adapter behavior\nfunction addFallbackSort(\n sort: string | string[] | undefined,\n collectionConfig: CollectionConfig | undefined,\n): string | string[] | undefined {\n if (!sort || !collectionConfig) {\n return sort\n }\n\n const sortArray = Array.isArray(sort) ? sort : [sort]\n\n // Determine fallback sort field\n let fallbackSort = '-id'\n if (collectionConfig.timestamps !== false) {\n fallbackSort = '-createdAt'\n }\n\n // Check if fallback sort is already included\n const hasFallback = sortArray.some(\n (item) => item === fallbackSort || item === fallbackSort.replace('-', ''),\n )\n\n if (hasFallback) {\n return sort\n }\n\n // Check if all sort fields are unique (then no fallback needed)\n // For simplicity, we'll always add fallback - checking uniqueness requires field traversal\n // which would be expensive. This matches the conservative approach.\n\n // Add fallback sort - always return array to preserve multiple sort fields\n return [...sortArray, fallbackSort]\n}\n\n// ⚠️ TEMPORARY WORKAROUND - Remove once Content API is fixed\n//\n// TODO: Content API should accept Payload's native Sort format instead of requiring conversion.\n// This converter exists because Content API expects a different format.\n//\n// Payload's format: \"-createdAt\" or [\"createdAt\", \"-updatedAt\"]\n// Content API expects: [{ path: \"createdAt\", direction: \"dsc\" }]\n//\n// Once Content API accepts Payload's format:\n// 1. Remove this function entirely\n// 2. Remove all calls to convertPayloadSortToContentAPI()\n// 3. Pass `sort` directly to Content API endpoints\nfunction convertPayloadSortToContentAPI(\n sort: string | string[] | undefined,\n): Array<{ direction: 'asc' | 'desc'; path: string }> | undefined {\n if (!sort) {\n return undefined\n }\n\n const sortArray = Array.isArray(sort) ? sort : [sort]\n\n return sortArray.map((field) => {\n let path = field\n let direction: 'asc' | 'desc' = 'asc'\n\n // Check if field starts with '-' for descending\n if (field.startsWith('-')) {\n path = field.substring(1) // Remove the '-'\n direction = 'desc'\n }\n\n // ⚠️ WORKAROUND: Strip \"version.\" prefix from field names\n // Payload sends \"-version.createdAt\" for version sort fields\n // but Content API expects just \"createdAt\"\n // TODO: Content API should handle version field paths correctly\n if (path.startsWith('version.')) {\n path = path.substring(8) // Remove \"version.\" prefix\n }\n\n return { direction, path }\n })\n}\n\n/**\n * Transform data before sending to Content API (WRITE operations)\n *\n * Conversions applied:\n * - RichText fields: Objects -> JSON strings\n * - Date fields: Date objects -> Unix timestamps (numbers)\n */\nfunction dataToContentAPI(this: ContentAPIAdapter, collectionSlug: string, data: unknown): unknown {\n if (!data || typeof data !== 'object') {\n return data\n }\n\n // Deep clone to avoid mutating original data\n const transformed = JSON.parse(JSON.stringify(data))\n\n // Get collection config\n const isGlobal = collectionSlug.startsWith('_global-')\n const actualSlug = isGlobal ? collectionSlug.substring(8) : collectionSlug\n const collectionConfig: CollectionConfig | GlobalConfig | undefined = isGlobal\n ? this.payload.config.globals?.find((g) => g.slug === actualSlug)\n : this.payload.config.collections.find((c) => c.slug === actualSlug)\n\n if (!collectionConfig?.fields) {\n return transformed\n }\n\n // Use Payload's traverseFields to iterate over all fields\n const callback: TraverseFieldsCallback = ({ field, ref }) => {\n if (!('name' in field) || !field.name) {\n return\n }\n if (!ref || typeof ref !== 'object') {\n return\n }\n\n const current = ref as Record<string, unknown>\n const value = current[field.name]\n\n if (value !== null && value !== undefined) {\n // RichText: object -> JSON string\n if (field.type === 'richText' && typeof value !== 'string') {\n current[field.name] = JSON.stringify(value)\n }\n // Date: Date -> Unix timestamp\n else if (field.type === 'date') {\n const dateValue = value instanceof Date ? value : new Date(value as number)\n if (!isNaN(dateValue.getTime())) {\n current[field.name] = dateValue.getTime()\n }\n }\n }\n }\n\n traverseFields({ callback, fields: collectionConfig.fields, ref: transformed })\n\n return transformed\n}\n\n/**\n * Transform data received from Content API (READ operations)\n *\n * Conversions applied:\n * - RichText fields: JSON strings -> Objects\n * - Date fields: Unix timestamps (numbers) -> Date objects\n */\nfunction dataFromContentAPI(\n this: ContentAPIAdapter,\n collectionSlug: string,\n data: unknown,\n): unknown {\n if (!data || typeof data !== 'object') {\n return data\n }\n\n // Deep clone to avoid mutating original data\n const transformed = JSON.parse(JSON.stringify(data))\n\n // Get collection config\n const isGlobal = collectionSlug.startsWith('_global-')\n const actualSlug = isGlobal ? collectionSlug.substring(8) : collectionSlug\n const collectionConfig: CollectionConfig | GlobalConfig | undefined = isGlobal\n ? this.payload.config.globals?.find((g) => g.slug === actualSlug)\n : this.payload.config.collections.find((c) => c.slug === actualSlug)\n\n if (!collectionConfig?.fields) {\n return transformed\n }\n\n // Use Payload's traverseFields to iterate over all fields\n const callback: TraverseFieldsCallback = ({ field, parentPath, ref }) => {\n if (!('name' in field) || !field.name) {\n return\n }\n if (!ref || typeof ref !== 'object') {\n return\n }\n\n const current = ref as Record<string, unknown>\n const value = current[field.name]\n\n if (value !== null && value !== undefined) {\n // RichText: JSON string -> object\n if (field.type === 'richText' && typeof value === 'string') {\n try {\n current[field.name] = JSON.parse(value)\n } catch (error) {\n const fieldPath = parentPath ? `${parentPath}.${field.name}` : field.name\n this.payload.logger.warn({\n err: error instanceof Error ? error : new Error(String(error)),\n msg: `Failed to parse richtext field '${fieldPath}' in collection '${collectionSlug}'`,\n })\n }\n }\n // Date: Unix timestamp or ISO string -> Date\n else if (field.type === 'date') {\n current[field.name] = new Date(value as number)\n }\n }\n }\n\n traverseFields({ callback, fields: collectionConfig.fields, ref: transformed })\n\n return transformed\n}\n\n// Helper to unwrap Content API document format to Payload format\n// Content API returns: { id, data: { ...fields }, createdAt, updatedAt }\n// Payload expects: { id, ...fields, createdAt, updatedAt }\nfunction unwrapDocument(\n this: ContentAPIAdapter,\n doc: components['schemas']['Document'] | components['schemas']['DocumentVersion'],\n collectionSlug?: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): any {\n if (!doc) {\n return doc\n }\n\n // TODO\n // Document has 'key', DocumentVersion has 'documentId'\n const docId = CONTENT_API_KEY_FIELD in doc ? doc[CONTENT_API_KEY_FIELD] : doc.documentId\n\n const baseDoc = {\n ...doc.data, // Spread the actual document fields\n createdAt: doc.createdAt,\n [PAYLOAD_ID_FIELD]: docId, // Map Content API's key to Payload's id\n updatedAt: doc.updatedAt,\n }\n\n // Transform data from Content API format to Payload format\n if (collectionSlug) {\n return dataFromContentAPI.call(this, collectionSlug, baseDoc)\n }\n\n return baseDoc\n}\n\nconst findMany = async function findMany(\n this: ContentAPIAdapter,\n {\n collectionSlug,\n limit,\n page,\n pagination,\n skip,\n sort,\n where,\n }: {\n collectionSlug: string\n limit: number\n page: number\n pagination?: boolean\n skip?: number\n sort?: string | string[]\n where: Where\n },\n) {\n // Payload semantics: limit: 0 means \"no limit\" (get all documents)\n // Pass this through to Content API which follows the same convention\n const effectiveLimit = limit\n const offset = skip ?? (limit === 0 ? 0 : (page - 1) * limit)\n\n // Add fallback sort to ensure consistent ordering (matching MongoDB behavior)\n const collectionConfig = this.payload.config.collections.find((c) => c.slug === collectionSlug)\n const sortWithFallback = addFallbackSort(sort, collectionConfig)\n\n const response = await this.makeRequest<components['schemas']['FindDocumentsResponse']>(\n '/api/v0/documents:find',\n {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n limit: effectiveLimit,\n offset,\n sort: convertPayloadSortToContentAPI(sortWithFallback),\n where: convertPayloadWhereToContentAPI(where),\n },\n method: 'POST',\n },\n )\n\n return {\n docs: response.result.data.map((doc) => unwrapDocument.call(this, doc, collectionSlug)),\n hasNextPage:\n pagination !== false &&\n limit > 0 &&\n response.result.pagination.total > offset + response.result.data.length,\n hasPrevPage: pagination !== false && offset > 0,\n limit,\n nextPage:\n pagination !== false &&\n response.result.pagination.total > offset + response.result.data.length\n ? page + 1\n : null,\n page,\n pagingCounter: offset + 1,\n prevPage: pagination !== false && offset > 0 ? page - 1 : null,\n totalDocs: response.result.pagination.total,\n totalPages: limit > 0 ? Math.ceil(response.result.pagination.total / limit) : 1,\n }\n}\n\nconst find: Find = async function find(\n this: ContentAPIAdapter,\n { collection: collectionSlug, limit = 0, page = 1, pagination, skip, sort, where },\n) {\n // Apply defaultSort from collection config if no sort is provided\n const collectionConfig = this.payload.config.collections.find((c) => c.slug === collectionSlug)\n const effectiveSort = sort || collectionConfig?.defaultSort\n\n return findMany.call(this, {\n collectionSlug,\n limit,\n page,\n pagination,\n skip,\n sort: effectiveSort,\n where: where ?? {},\n })\n}\n\nconst findVersions: FindVersions = async function findVersions(\n this: ContentAPIAdapter,\n { collection: collectionSlug, limit = 0, page = 1, pagination, skip, sort, where },\n) {\n const offset = skip ?? (page - 1) * limit\n\n const response = await this.makeRequest<components['schemas']['FindDocumentsResponse']>(\n '/api/v0/document_versions:find',\n {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n limit,\n offset,\n sort: convertPayloadSortToContentAPI(sort),\n where: convertPayloadWhereToContentAPI(where ?? {}),\n },\n method: 'POST',\n },\n )\n\n return {\n docs: response.result.data.map((doc) => unwrapDocument.call(this, doc, collectionSlug)),\n hasNextPage:\n pagination !== false &&\n limit > 0 &&\n response.result.pagination.total > offset + response.result.data.length,\n hasPrevPage: pagination !== false && offset > 0,\n limit,\n nextPage:\n pagination !== false &&\n response.result.pagination.total > offset + response.result.data.length\n ? page + 1\n : null,\n page,\n pagingCounter: offset + 1,\n prevPage: pagination !== false && offset > 0 ? page - 1 : null,\n totalDocs: response.result.pagination.total,\n totalPages: limit > 0 ? Math.ceil(response.result.pagination.total / limit) : 1,\n }\n}\n\nconst queryDrafts: QueryDrafts = async function queryDrafts(\n this: ContentAPIAdapter,\n { collection: collectionSlug, limit, page, pagination, sort, where = {} },\n) {\n // TODO: review this\n // Content API doesn't have a separate \"draft\" concept\n // It only has versions with a \"latest\" flag\n // PayloadCMS drafts would typically be versions where latest=false\n // But this mapping may need adjustment based on your use case\n const result = await this.findVersions({\n collection: collectionSlug,\n limit,\n page,\n pagination,\n sort,\n where: {\n ...where,\n // Query non-latest versions as \"drafts\"\n latest: { equals: false },\n },\n })\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return result as any\n}\n\nconst createVersion: CreateVersion = async function createVersion(\n this: ContentAPIAdapter,\n { autosave, collectionSlug, parent, versionData },\n) {\n const response = await this.makeRequest<components['schemas']['CreateDocumentVersionResponse']>(\n '/api/v0/document_versions:create',\n {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n data: dataToContentAPI.call(this, collectionSlug, versionData),\n documentKey: parent,\n latest: !autosave,\n },\n method: 'POST',\n },\n )\n\n // Handle union type response: { id: string } | { data: DocumentVersion }\n if ('data' in response.result) {\n return unwrapDocument.call(this, response.result.data, collectionSlug)\n }\n throw new Error('Unexpected response format from createVersion')\n}\n\nconst updateVersion: UpdateVersion = async function updateVersion(\n this: ContentAPIAdapter,\n { id, collection: collectionSlug, versionData, where },\n) {\n const response = await this.makeRequest<components['schemas']['UpdateDocumentVersionResponse']>(\n '/api/v0/document_versions:update',\n {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n createOnMissing: false,\n data: dataToContentAPI.call(this, collectionSlug, versionData),\n where: convertPayloadWhereToContentAPI(where ?? { id: { equals: id } }),\n },\n method: 'POST',\n },\n )\n\n // Handle union type response: { count: number } | { data: DocumentVersion[] }\n if (!response?.result || !('data' in response.result)) {\n throw new Error('No document data in updateVersion response')\n }\n\n return unwrapDocument.call(this, response.result.data[0], collectionSlug)\n}\n\nconst deleteVersions: DeleteVersions = async function deleteVersions(\n this: ContentAPIAdapter,\n { collection: collectionSlug, where },\n) {\n await this.makeRequest('/api/v0/document_versions:delete', {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n returning: false, // Don't return deleted data (future-proof for when Content API supports this)\n where: convertPayloadWhereToContentAPI(where),\n },\n method: 'POST',\n })\n}\n\nconst findOne: FindOne = async function findOne(this: ContentAPIAdapter, { collection, where }) {\n const {\n docs: [first],\n } = await this.find({ collection, limit: 1, pagination: false, where })\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (first ?? null) as any\n}\n\nconst updateMany: UpdateMany = async function updateMany(\n this: ContentAPIAdapter,\n { collection: collectionSlug, data, where },\n) {\n const response = await this.makeRequest<components['schemas']['UpdateDocumentResponse']>(\n '/api/v0/documents:update',\n {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n createOnMissing: false,\n data: dataToContentAPI.call(this, collectionSlug, data),\n returning: {},\n where: convertPayloadWhereToContentAPI(where),\n },\n method: 'POST',\n },\n )\n\n // Handle union type: { count: number } | { data: Document[] }\n if (response.result && 'data' in response.result) {\n return response.result.data.map((doc) => unwrapDocument.call(this, doc, collectionSlug))\n }\n return null\n}\n\nconst updateOne: UpdateOne = async function updateOne(\n this: ContentAPIAdapter,\n { id, collection: collectionSlug, data, where },\n) {\n const response = await this.makeRequest<components['schemas']['UpdateDocumentResponse']>(\n '/api/v0/documents:update',\n {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n createOnMissing: false,\n data: dataToContentAPI.call(this, collectionSlug, data),\n where: convertPayloadWhereToContentAPI(where ?? { id: { equals: id } }),\n },\n method: 'POST',\n },\n )\n\n // Handle union type: { count: number } | { data: Document[] }\n if (response.result && 'data' in response.result) {\n const doc = response.result.data[0]\n if (!doc) {\n throw new Error('No document data in updateOne response')\n }\n return unwrapDocument.call(this, doc, collectionSlug)\n }\n throw new Error('Unexpected response format from updateOne')\n}\n\nconst deleteMany: DeleteMany = async function deleteMany(\n this: ContentAPIAdapter,\n { collection: collectionSlug, where },\n) {\n await this.makeRequest('/api/v0/documents:delete', {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n returning: false, // Don't return deleted data (future-proof for when Content API supports this)\n where: convertPayloadWhereToContentAPI(where),\n },\n method: 'POST',\n })\n}\n\nconst deleteOne: DeleteOne = async function deleteOne(\n this: ContentAPIAdapter,\n { collection: collectionSlug, where },\n) {\n await this.makeRequest('/api/v0/documents:delete', {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n returning: false, // Don't return deleted data (future-proof for when Content API supports this)\n where: convertPayloadWhereToContentAPI(where),\n },\n method: 'POST',\n })\n}\n\nconst create: Create = async function create(\n this: ContentAPIAdapter,\n { collection: collectionSlug, data },\n) {\n // Generate a document key if not provided\n // Content API has two ID fields:\n // - `id` (UUID, auto-generated by DB, internal use only)\n // - `key` (text, public document identifier, maps to Payload's `id`)\n // If Payload doesn't provide an ID, we generate a UUID\n // (same as other SQL-based Payload adapters like db-postgres and db-drizzle)\n const key = data[PAYLOAD_ID_FIELD] || uuid()\n\n const response = await this.makeRequest<components['schemas']['CreateDocumentResponse']>(\n '/api/v0/documents:create',\n {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n data: dataToContentAPI.call(this, collectionSlug, data),\n key,\n // returning is optional and currently ignored by Content API (always returns full document)\n },\n method: 'POST',\n },\n )\n\n // Handle union type response: { id: string } | { data: Document }\n if ('data' in response.result) {\n return unwrapDocument.call(this, response.result.data, collectionSlug)\n }\n throw new Error('Unexpected response format from create')\n}\n\nconst count: Count = async function count(\n this: ContentAPIAdapter,\n { collection: collectionSlug, where },\n) {\n const response = await this.makeRequest<components['schemas']['CountDocumentResponse']>(\n '/api/v0/documents:count',\n {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n where: convertPayloadWhereToContentAPI(where),\n },\n method: 'POST',\n },\n )\n\n return { totalDocs: response.result.count }\n}\n\nconst countVersions: CountVersions = async function countVersions(\n this: ContentAPIAdapter,\n { collection: collectionSlug, where },\n) {\n const response = await this.makeRequest<components['schemas']['CountDocumentVersionResponse']>(\n '/api/v0/document_versions:count',\n {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n where: convertPayloadWhereToContentAPI(where),\n },\n method: 'POST',\n },\n )\n\n return { totalDocs: response.result.count }\n}\n\nconst upsert: Upsert = async function upsert(\n this: ContentAPIAdapter,\n { collection: collectionSlug, data, where },\n) {\n const response = await this.makeRequest<components['schemas']['UpdateDocumentResponse']>(\n '/api/v0/documents:update',\n {\n body: {\n collectionKey: collectionSlug,\n contentSystemId: this.contentSystemId,\n createOnMissing: true,\n data: dataToContentAPI.call(this, collectionSlug, data),\n where: convertPayloadWhereToContentAPI(where),\n },\n method: 'POST',\n },\n )\n\n // Handle union type: { count: number } | { data: Document[] }\n if (response.result && 'data' in response.result) {\n const doc = response.result.data[0]\n if (!doc) {\n throw new Error('No document data in upsert response')\n }\n return unwrapDocument.call(this, doc, collectionSlug)\n }\n throw new Error('Unexpected response format from upsert')\n}\n\n// TODO: global should be a prefix or a resource in the REST API / Table in the DB?\nconst getGlobalSlug = (slug: string) => `_global-${slug}`\n\nconst createGlobal: CreateGlobal = function (this: ContentAPIAdapter, { slug, data }) {\n return this.create({ collection: getGlobalSlug(slug), data: { ...data, globalType: slug } })\n}\n\nconst findGlobal: FindGlobal = function (this: ContentAPIAdapter, { slug, where = {} }) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return this.findOne({ collection: getGlobalSlug(slug), where }) as any\n}\n\nconst updateGlobal: UpdateGlobal = function (this: ContentAPIAdapter, { slug, data }) {\n return this.updateOne({ collection: getGlobalSlug(slug), data, where: {} })\n}\n\nconst findGlobalVersions: FindGlobalVersions = function (\n this: ContentAPIAdapter,\n { global: slug, limit, page, pagination, skip, sort, where },\n) {\n return this.findVersions({\n collection: getGlobalSlug(slug),\n limit,\n page,\n pagination,\n skip,\n sort,\n where,\n })\n}\n\nconst createGlobalVersion: CreateGlobalVersion = function (\n this: ContentAPIAdapter,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n { autosave, createdAt, globalSlug, updatedAt, versionData, ...rest }: any,\n) {\n return this.createVersion({\n autosave,\n collectionSlug: getGlobalSlug(globalSlug),\n createdAt,\n parent: rest.parent,\n updatedAt,\n versionData,\n })\n}\n\nconst updateGlobalVersion: UpdateGlobalVersion = function (\n this: ContentAPIAdapter,\n { id, global: slug, versionData, where, ...rest },\n) {\n // UpdateVersion accepts either id OR where, not both\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const args: any = {\n collection: getGlobalSlug(slug),\n versionData,\n ...rest,\n }\n\n if (id !== undefined) {\n args.id = id\n } else if (where !== undefined) {\n args.where = where\n }\n\n return this.updateVersion(args)\n}\n\nconst countGlobalVersions: CountGlobalVersions = function (\n this: ContentAPIAdapter,\n { global: slug, where },\n) {\n return this.countVersions({ collection: getGlobalSlug(slug), where })\n}\n\nexport const contentAPIAdapter = (opts: ContentAPIOptions): DatabaseAdapterObj => {\n return {\n name: 'content_api',\n defaultIDType: 'text',\n init: ({ payload }) => {\n return createDatabaseAdapter<ContentAPIAdapter>({\n name: 'content_api',\n auth: opts.auth,\n beginTransaction: () => {\n return Promise.resolve('no-op-transaction')\n },\n commitTransaction: async () => {},\n contentSystemId: opts.contentSystemId,\n count,\n countGlobalVersions,\n countVersions,\n create,\n createGlobal,\n createGlobalVersion,\n createVersion,\n defaultIDType: 'text',\n deleteMany,\n deleteOne,\n deleteVersions,\n find,\n findDistinct: () => {\n return Promise.reject(\n new Error('findDistinct is not yet implemented for Content API adapter'),\n )\n },\n findGlobal,\n findGlobalVersions,\n findOne,\n findVersions,\n init,\n makeRequest,\n packageName: '@payloadcms/db-content-api',\n payload,\n queryDrafts,\n rollbackTransaction: async () => {},\n updateGlobal,\n updateGlobalVersion,\n updateMany,\n updateOne,\n updateVersion,\n upsert,\n url: opts.url,\n })\n },\n }\n}\n"],"names":["createDatabaseAdapter","traverseFields","v4","uuid","getValidProjectToken","PAYLOAD_ID_FIELD","CONTENT_API_KEY_FIELD","devJwtCache","Map","fetchDevJwt","url","contentSystemId","usesSuperUser","contentSystemIdForJWT","response","fetch","body","JSON","stringify","content_system_id","headers","method","ok","Error","status","statusText","token","json","init","auth","mode","payload","logger","info","process","env","PAYLOAD_DROP_DATABASE","makeRequest","error","warn","message","collection","config","collections","createCollectionIfNotExists","call","slug","global","globals","collectionKey","name","key","errorMessage","includes","path","options","retryCount","authHeader","apiKey","tokenStore","Authorization","get","set","requestUrl","undefined","text","delete","msg","substring","parsed","parse","startsWith","err","String","convertPayloadWhereToContentAPI","where","insideLogicalOperator","Object","keys","length","and","conditions","value","entries","nestedConditions","map","item","or","operators","op","operatorValue","finalValue","push","operator","addFallbackSort","sort","collectionConfig","sortArray","Array","isArray","fallbackSort","timestamps","hasFallback","some","replace","convertPayloadSortToContentAPI","field","direction","dataToContentAPI","collectionSlug","data","transformed","isGlobal","actualSlug","find","g","c","fields","callback","ref","current","type","dateValue","Date","isNaN","getTime","dataFromContentAPI","parentPath","fieldPath","unwrapDocument","doc","docId","documentId","baseDoc","createdAt","updatedAt","findMany","limit","page","pagination","skip","effectiveLimit","offset","sortWithFallback","docs","result","hasNextPage","total","hasPrevPage","nextPage","pagingCounter","prevPage","totalDocs","totalPages","Math","ceil","effectiveSort","defaultSort","findVersions","queryDrafts","latest","equals","createVersion","autosave","parent","versionData","documentKey","updateVersion","id","createOnMissing","deleteVersions","returning","findOne","first","updateMany","updateOne","deleteMany","deleteOne","create","count","countVersions","upsert","getGlobalSlug","createGlobal","globalType","findGlobal","updateGlobal","findGlobalVersions","createGlobalVersion","globalSlug","rest","updateGlobalVersion","args","countGlobalVersions","contentAPIAdapter","opts","defaultIDType","beginTransaction","Promise","resolve","commitTransaction","findDistinct","reject","packageName","rollbackTransaction"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Type helpers for working with Content API generated types
3
+ */
4
+ import type { paths } from './generated/content-api-types.js';
5
+ /**
6
+ * All available API paths
7
+ */
8
+ export type APIPath = keyof paths;
9
+ /**
10
+ * Extract request body type for a given path and method
11
+ */
12
+ export type RequestBody<Path extends keyof paths, Method extends keyof paths[Path]> = paths[Path][Method] extends {
13
+ requestBody: {
14
+ content: {
15
+ 'application/json': infer T;
16
+ };
17
+ };
18
+ } ? T : never;
19
+ /**
20
+ * Extract response body type for a given path and method
21
+ */
22
+ export type ResponseBody<Path extends keyof paths, Method extends keyof paths[Path]> = paths[Path][Method] extends {
23
+ responses: {
24
+ 200: {
25
+ content: {
26
+ 'application/json': infer T;
27
+ };
28
+ };
29
+ };
30
+ } ? T : unknown;
31
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/db-content-api/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kCAAkC,CAAA;AAE7D;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,KAAK,CAAA;AAEjC;;GAEG;AACH,MAAM,MAAM,WAAW,CACrB,IAAI,SAAS,MAAM,KAAK,EACxB,MAAM,SAAS,MAAM,KAAK,CAAC,IAAI,CAAC,IAC9B,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS;IAAE,WAAW,EAAE;QAAE,OAAO,EAAE;YAAE,kBAAkB,EAAE,MAAM,CAAC,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,GACzF,CAAC,GACD,KAAK,CAAA;AAET;;GAEG;AACH,MAAM,MAAM,YAAY,CACtB,IAAI,SAAS,MAAM,KAAK,EACxB,MAAM,SAAS,MAAM,KAAK,CAAC,IAAI,CAAC,IAC9B,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS;IAAE,SAAS,EAAE;QAAE,GAAG,EAAE;YAAE,OAAO,EAAE;gBAAE,kBAAkB,EAAE,MAAM,CAAC,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,GAChG,CAAC,GACD,OAAO,CAAA"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Type helpers for working with Content API generated types
3
+ */ /**
4
+ * Extract response body type for a given path and method
5
+ */ export { };
6
+
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/db-content-api/types.ts"],"sourcesContent":["/**\n * Type helpers for working with Content API generated types\n */\n\nimport type { paths } from './generated/content-api-types.js'\n\n/**\n * All available API paths\n */\nexport type APIPath = keyof paths\n\n/**\n * Extract request body type for a given path and method\n */\nexport type RequestBody<\n Path extends keyof paths,\n Method extends keyof paths[Path],\n> = paths[Path][Method] extends { requestBody: { content: { 'application/json': infer T } } }\n ? T\n : never\n\n/**\n * Extract response body type for a given path and method\n */\nexport type ResponseBody<\n Path extends keyof paths,\n Method extends keyof paths[Path],\n> = paths[Path][Method] extends { responses: { 200: { content: { 'application/json': infer T } } } }\n ? T\n : unknown\n"],"names":[],"mappings":"AAAA;;CAEC,GAmBD;;CAEC,GACD,WAKW"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
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
4
  export { buildFigmaConfig } from './plugin/build-config.js';
@@ -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,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,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,3 +1,5 @@
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
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 { buildFigmaConfig } from './plugin/build-config.js'\nexport type { FigmaConfig } from './plugin/build-config.js'\n"],"names":["figmaContentSystem","buildFigmaConfig"],"mappings":"AAAA,iDAAiD;AACjD,SAASA,kBAAkB,QAAQ,sBAAqB;AAGxD,iDAAiD;AACjD,SAASC,gBAAgB,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"}
@@ -154,7 +154,7 @@ export const getLoginEndpoint = ({ collection, collectionOptions, endpointSlug,
154
154
  tokenRes
155
155
  });
156
156
  // Swap for project token
157
- const project_token = await getProjectToken(tokenRes.access_token, config.custom.figma.tenantId);
157
+ const project_token = await getProjectToken(tokenRes.access_token, config.custom.figma.contentSystemId);
158
158
  const refresh_token = access_token;
159
159
  // Store project token as access_token
160
160
  const token = project_token.token;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/oauth/endpoints/getLoginEndpoint.ts"],"sourcesContent":["import type { CollectionConfig, Endpoint } from 'payload'\n\nimport { APIError, generateCookie, parseCookies } from 'payload'\nimport { getSafeRedirect } from 'payload/shared'\n\nimport type { Strategy } from '../strategy/index.js'\nimport type { CollectionOptions, PluginOptions, StateObj } from '../types.js'\n\nimport { getProjectToken } from '../../api/figma-api.js'\nimport { createCookieOptions } from '../utilities/createCookieOptions.js'\nimport { createDebugLogger } from '../utilities/createDebugLogger.js'\nimport { extractOrigin } from '../utilities/extractOrigin.js'\nimport { getAdminPath } from '../utilities/getAdminPath.js'\nimport { getCookieExpiration } from '../utilities/getCookieExpiration.js'\n\ninterface Args {\n collection: CollectionConfig\n collectionOptions: CollectionOptions\n endpointSlug: string\n pluginOptions: PluginOptions\n strategy: Strategy\n}\n\nconst isAbsoluteURL = (url: string) => /^[a-z][a-z\\d+.-]*:/.test(url)\n\nexport const getLoginEndpoint = ({\n collection,\n collectionOptions,\n endpointSlug,\n pluginOptions,\n strategy,\n}: Args): Endpoint => ({\n handler: async (req) => {\n const { config } = req.payload\n const adminPath = getAdminPath(config)\n try {\n await strategy.ensureMeta()\n\n const path = req.pathname\n const debugLogger = createDebugLogger(req.payload, pluginOptions.debug)\n\n let jsonBody: Record<string, unknown> = {}\n\n const contentType = req.headers.get('content-type')\n\n // Type narrow PayloadRequst's Partial<Request>\n if (typeof req.json !== 'function' || typeof req.formData !== 'function') {\n debugLogger.info({\n msg: 'Request does not have json or formData methods',\n path,\n })\n\n return Response.redirect(`${pluginOptions.redirectServerURL || config.serverURL}/login`)\n }\n\n if (collectionOptions.authorizationURLParams?.response_mode === 'query') {\n if (Object.keys(req.query).length > 0) {\n jsonBody = req.query\n }\n } else if (contentType === 'application/json') {\n jsonBody = await req.json()\n } else if (contentType === 'application/x-www-form-urlencoded') {\n const formData = await req.formData()\n jsonBody = Object.fromEntries(formData.entries())\n }\n\n const stateRaw = jsonBody.state as string\n const state: StateObj = JSON.parse(Buffer.from(stateRaw, 'base64').toString('utf-8'))\n\n const redirectDestination =\n state.serverURL || pluginOptions.redirectServerURL || config.serverURL\n let failedRedirect = `${redirectDestination}${adminPath}/login`\n let redirectToUse = `${redirectDestination}${adminPath}`\n\n if (state.redirect) {\n redirectToUse = state.redirect\n }\n\n if (state.failedRedirect) {\n failedRedirect = state.failedRedirect\n }\n\n failedRedirect = getSafeRedirect({ allowAbsoluteUrls: true, redirectTo: failedRedirect })\n redirectToUse = getSafeRedirect({ allowAbsoluteUrls: true, redirectTo: redirectToUse })\n\n if (!isAbsoluteURL(failedRedirect)) {\n return Response.json({ error: 'Invalid failed redirect provided' }, { status: 403 })\n }\n if (!isAbsoluteURL(redirectToUse)) {\n return Response.json({ error: 'Invalid redirect provided' }, { status: 403 })\n }\n\n if (Array.isArray(req.payload.config.csrf) && req.payload.config.csrf.length > 0) {\n const failedRedirectOrigin = extractOrigin(failedRedirect)\n const redirectToUseOrigin = extractOrigin(redirectToUse)\n\n if (failedRedirectOrigin && !req.payload.config.csrf.includes(failedRedirectOrigin)) {\n req.payload.logger.error(\n `Failed redirect origin ${failedRedirectOrigin} is not allowed by CSRF configuration.`,\n )\n return Response.json(\n { error: 'Failed redirect origin is not allowed by CSRF configuration.' },\n { status: 403 },\n )\n }\n\n if (redirectToUseOrigin && !req.payload.config.csrf.includes(redirectToUseOrigin)) {\n req.payload.logger.error(\n `Redirect origin ${redirectToUseOrigin} is not allowed by CSRF configuration.`,\n )\n return Response.json(\n { error: 'Redirect origin is not allowed by CSRF configuration.' },\n { status: 403 },\n )\n }\n }\n\n // Verify signature\n if (strategy.name !== req.payload.decrypt(state.sig)) {\n req.payload.logger.error('Signature mismatch. Failing login and redirecting.')\n return Response.redirect(failedRedirect)\n }\n\n if (!strategy.meta?.token_endpoint) {\n debugLogger.error({\n msg: `No metadata was obtained from the identity provider. Failing login and redirecting.`,\n path,\n })\n return Response.redirect(failedRedirect)\n }\n\n debugLogger.info({ body: jsonBody, msg: 'Received login response body', path })\n\n if (!jsonBody?.code) {\n debugLogger.error({\n msg: `No authorization code present in body. Failing login and redirecting.`,\n path,\n })\n return Response.redirect(failedRedirect)\n }\n\n // Exchange `code` from body for refresh token\n const { code } = jsonBody\n\n if (typeof code !== 'string') {\n debugLogger.error({\n msg: `Authorization code present in body is not a string. Failing login and redirecting.`,\n path,\n })\n return Response.redirect(failedRedirect)\n }\n\n const body: Record<string, string> = {\n client_id: strategy.clientID,\n code,\n code_verifier: req.payload.decrypt(state.verifier),\n grant_type: 'authorization_code',\n redirect_uri: `${redirectDestination}${config?.routes?.api || '/api'}/${\n collection.slug\n }/${endpointSlug}/login`,\n }\n\n debugLogger.info({\n msg: 'Exchanging code for access token',\n path,\n requestBody: body,\n })\n\n if (strategy.clientSecret) {\n body.client_secret = strategy.clientSecret\n }\n\n const tokenRes = await fetch(strategy.meta?.token_endpoint, {\n body: new URLSearchParams(body),\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n method: 'POST',\n }).then((r) => r.json())\n\n debugLogger.info({ msg: 'Token Response', path, tokenRes })\n\n const { access_token, error, error_description, expires_in: refreshTokenExpires } = tokenRes\n\n debugLogger.info({ msg: 'tokenResss', tokenRes })\n\n // Swap for project token\n const project_token = await getProjectToken(\n tokenRes.access_token,\n config.custom.figma.tenantId,\n )\n const refresh_token = access_token\n\n // Store project token as access_token\n\n const token = project_token.token\n const expiresIn = project_token.expiresAt\n\n if (!token) {\n const errMsg = `No ${\n collectionOptions.token || 'access_token'\n } was returned from the identity provider.`\n req.payload.logger.error({ msg: errMsg, path })\n throw new APIError(errMsg)\n }\n\n const cookieOptions = createCookieOptions({ collection, headers: req.headers, pluginOptions })\n\n if (error) {\n req.payload.logger.error('Error swapping access code with access token:')\n req.payload.logger.error({ err: error, error_description })\n return Response.redirect(failedRedirect)\n }\n\n // get the payloadRedirect cookie value\n const cookies = parseCookies(req.headers)\n\n const payloadRedirect =\n 'payloadRedirect' in cookies ? (cookies.payloadRedirect as string) : ''\n\n if (!req.responseHeaders) {\n req.responseHeaders = new Headers()\n }\n\n if (payloadRedirect) {\n if (isAbsoluteURL(payloadRedirect)) {\n redirectToUse = payloadRedirect\n } else {\n redirectToUse += payloadRedirect\n }\n\n req.responseHeaders.append(\n 'Set-Cookie',\n `payloadRedirect=${redirectToUse}; Max-Age=0; Path=/;`,\n )\n }\n\n if (refresh_token && !collectionOptions.usePayloadJWT) {\n debugLogger.info('Setting refresh token cookie')\n const refreshCookie = generateCookie({\n returnCookieAsObject: false,\n ...cookieOptions,\n name: `${strategy.cookieName}-refresh`,\n value: refresh_token,\n // Default to 1 year if no expiration\n expires: getCookieExpiration(cookieOptions?.expires ?? refreshTokenExpires ?? 31_556_952),\n }) as string\n\n req.responseHeaders.append('Set-Cookie', refreshCookie)\n }\n\n const tokenExpires = cookieOptions?.expires\n ? getCookieExpiration(cookieOptions.expires)\n : new Date(expiresIn) // Project token uses epoch time\n const tokenCookie = generateCookie({\n ...cookieOptions,\n name: strategy.cookieName,\n expires: tokenExpires,\n returnCookieAsObject: false,\n value: token,\n }) as string\n\n req.responseHeaders.append('Set-Cookie', tokenCookie)\n\n return Response.redirect(redirectToUse)\n } catch (err: unknown) {\n req.payload.logger.error({ err, msg: 'Error while attempting to login', path: req.pathname })\n\n return Response.json({ error: 'Error while attempting to login' }, { status: 500 })\n }\n },\n method: collectionOptions.authorizationURLParams?.response_mode === 'query' ? 'get' : 'post',\n path: `/${endpointSlug}/login`,\n})\n"],"names":["APIError","generateCookie","parseCookies","getSafeRedirect","getProjectToken","createCookieOptions","createDebugLogger","extractOrigin","getAdminPath","getCookieExpiration","isAbsoluteURL","url","test","getLoginEndpoint","collection","collectionOptions","endpointSlug","pluginOptions","strategy","handler","req","config","payload","adminPath","ensureMeta","path","pathname","debugLogger","debug","jsonBody","contentType","headers","get","json","formData","info","msg","Response","redirect","redirectServerURL","serverURL","authorizationURLParams","response_mode","Object","keys","query","length","fromEntries","entries","stateRaw","state","JSON","parse","Buffer","from","toString","redirectDestination","failedRedirect","redirectToUse","allowAbsoluteUrls","redirectTo","error","status","Array","isArray","csrf","failedRedirectOrigin","redirectToUseOrigin","includes","logger","name","decrypt","sig","meta","token_endpoint","body","code","client_id","clientID","code_verifier","verifier","grant_type","redirect_uri","routes","api","slug","requestBody","clientSecret","client_secret","tokenRes","fetch","URLSearchParams","method","then","r","access_token","error_description","expires_in","refreshTokenExpires","project_token","custom","figma","tenantId","refresh_token","token","expiresIn","expiresAt","errMsg","cookieOptions","err","cookies","payloadRedirect","responseHeaders","Headers","append","usePayloadJWT","refreshCookie","returnCookieAsObject","cookieName","value","expires","tokenExpires","Date","tokenCookie"],"mappings":"AAEA,SAASA,QAAQ,EAAEC,cAAc,EAAEC,YAAY,QAAQ,UAAS;AAChE,SAASC,eAAe,QAAQ,iBAAgB;AAKhD,SAASC,eAAe,QAAQ,yBAAwB;AACxD,SAASC,mBAAmB,QAAQ,sCAAqC;AACzE,SAASC,iBAAiB,QAAQ,oCAAmC;AACrE,SAASC,aAAa,QAAQ,gCAA+B;AAC7D,SAASC,YAAY,QAAQ,+BAA8B;AAC3D,SAASC,mBAAmB,QAAQ,sCAAqC;AAUzE,MAAMC,gBAAgB,CAACC,MAAgB,qBAAqBC,IAAI,CAACD;AAEjE,OAAO,MAAME,mBAAmB,CAAC,EAC/BC,UAAU,EACVC,iBAAiB,EACjBC,YAAY,EACZC,aAAa,EACbC,QAAQ,EACH,GAAgB,CAAA;QACrBC,SAAS,OAAOC;YACd,MAAM,EAAEC,MAAM,EAAE,GAAGD,IAAIE,OAAO;YAC9B,MAAMC,YAAYf,aAAaa;YAC/B,IAAI;gBACF,MAAMH,SAASM,UAAU;gBAEzB,MAAMC,OAAOL,IAAIM,QAAQ;gBACzB,MAAMC,cAAcrB,kBAAkBc,IAAIE,OAAO,EAAEL,cAAcW,KAAK;gBAEtE,IAAIC,WAAoC,CAAC;gBAEzC,MAAMC,cAAcV,IAAIW,OAAO,CAACC,GAAG,CAAC;gBAEpC,+CAA+C;gBAC/C,IAAI,OAAOZ,IAAIa,IAAI,KAAK,cAAc,OAAOb,IAAIc,QAAQ,KAAK,YAAY;oBACxEP,YAAYQ,IAAI,CAAC;wBACfC,KAAK;wBACLX;oBACF;oBAEA,OAAOY,SAASC,QAAQ,CAAC,GAAGrB,cAAcsB,iBAAiB,IAAIlB,OAAOmB,SAAS,CAAC,MAAM,CAAC;gBACzF;gBAEA,IAAIzB,kBAAkB0B,sBAAsB,EAAEC,kBAAkB,SAAS;oBACvE,IAAIC,OAAOC,IAAI,CAACxB,IAAIyB,KAAK,EAAEC,MAAM,GAAG,GAAG;wBACrCjB,WAAWT,IAAIyB,KAAK;oBACtB;gBACF,OAAO,IAAIf,gBAAgB,oBAAoB;oBAC7CD,WAAW,MAAMT,IAAIa,IAAI;gBAC3B,OAAO,IAAIH,gBAAgB,qCAAqC;oBAC9D,MAAMI,WAAW,MAAMd,IAAIc,QAAQ;oBACnCL,WAAWc,OAAOI,WAAW,CAACb,SAASc,OAAO;gBAChD;gBAEA,MAAMC,WAAWpB,SAASqB,KAAK;gBAC/B,MAAMA,QAAkBC,KAAKC,KAAK,CAACC,OAAOC,IAAI,CAACL,UAAU,UAAUM,QAAQ,CAAC;gBAE5E,MAAMC,sBACJN,MAAMV,SAAS,IAAIvB,cAAcsB,iBAAiB,IAAIlB,OAAOmB,SAAS;gBACxE,IAAIiB,iBAAiB,GAAGD,sBAAsBjC,UAAU,MAAM,CAAC;gBAC/D,IAAImC,gBAAgB,GAAGF,sBAAsBjC,WAAW;gBAExD,IAAI2B,MAAMZ,QAAQ,EAAE;oBAClBoB,gBAAgBR,MAAMZ,QAAQ;gBAChC;gBAEA,IAAIY,MAAMO,cAAc,EAAE;oBACxBA,iBAAiBP,MAAMO,cAAc;gBACvC;gBAEAA,iBAAiBtD,gBAAgB;oBAAEwD,mBAAmB;oBAAMC,YAAYH;gBAAe;gBACvFC,gBAAgBvD,gBAAgB;oBAAEwD,mBAAmB;oBAAMC,YAAYF;gBAAc;gBAErF,IAAI,CAAChD,cAAc+C,iBAAiB;oBAClC,OAAOpB,SAASJ,IAAI,CAAC;wBAAE4B,OAAO;oBAAmC,GAAG;wBAAEC,QAAQ;oBAAI;gBACpF;gBACA,IAAI,CAACpD,cAAcgD,gBAAgB;oBACjC,OAAOrB,SAASJ,IAAI,CAAC;wBAAE4B,OAAO;oBAA4B,GAAG;wBAAEC,QAAQ;oBAAI;gBAC7E;gBAEA,IAAIC,MAAMC,OAAO,CAAC5C,IAAIE,OAAO,CAACD,MAAM,CAAC4C,IAAI,KAAK7C,IAAIE,OAAO,CAACD,MAAM,CAAC4C,IAAI,CAACnB,MAAM,GAAG,GAAG;oBAChF,MAAMoB,uBAAuB3D,cAAckD;oBAC3C,MAAMU,sBAAsB5D,cAAcmD;oBAE1C,IAAIQ,wBAAwB,CAAC9C,IAAIE,OAAO,CAACD,MAAM,CAAC4C,IAAI,CAACG,QAAQ,CAACF,uBAAuB;wBACnF9C,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CACtB,CAAC,uBAAuB,EAAEK,qBAAqB,sCAAsC,CAAC;wBAExF,OAAO7B,SAASJ,IAAI,CAClB;4BAAE4B,OAAO;wBAA+D,GACxE;4BAAEC,QAAQ;wBAAI;oBAElB;oBAEA,IAAIK,uBAAuB,CAAC/C,IAAIE,OAAO,CAACD,MAAM,CAAC4C,IAAI,CAACG,QAAQ,CAACD,sBAAsB;wBACjF/C,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CACtB,CAAC,gBAAgB,EAAEM,oBAAoB,sCAAsC,CAAC;wBAEhF,OAAO9B,SAASJ,IAAI,CAClB;4BAAE4B,OAAO;wBAAwD,GACjE;4BAAEC,QAAQ;wBAAI;oBAElB;gBACF;gBAEA,mBAAmB;gBACnB,IAAI5C,SAASoD,IAAI,KAAKlD,IAAIE,OAAO,CAACiD,OAAO,CAACrB,MAAMsB,GAAG,GAAG;oBACpDpD,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CAAC;oBACzB,OAAOxB,SAASC,QAAQ,CAACmB;gBAC3B;gBAEA,IAAI,CAACvC,SAASuD,IAAI,EAAEC,gBAAgB;oBAClC/C,YAAYkC,KAAK,CAAC;wBAChBzB,KAAK,CAAC,mFAAmF,CAAC;wBAC1FX;oBACF;oBACA,OAAOY,SAASC,QAAQ,CAACmB;gBAC3B;gBAEA9B,YAAYQ,IAAI,CAAC;oBAAEwC,MAAM9C;oBAAUO,KAAK;oBAAgCX;gBAAK;gBAE7E,IAAI,CAACI,UAAU+C,MAAM;oBACnBjD,YAAYkC,KAAK,CAAC;wBAChBzB,KAAK,CAAC,qEAAqE,CAAC;wBAC5EX;oBACF;oBACA,OAAOY,SAASC,QAAQ,CAACmB;gBAC3B;gBAEA,8CAA8C;gBAC9C,MAAM,EAAEmB,IAAI,EAAE,GAAG/C;gBAEjB,IAAI,OAAO+C,SAAS,UAAU;oBAC5BjD,YAAYkC,KAAK,CAAC;wBAChBzB,KAAK,CAAC,kFAAkF,CAAC;wBACzFX;oBACF;oBACA,OAAOY,SAASC,QAAQ,CAACmB;gBAC3B;gBAEA,MAAMkB,OAA+B;oBACnCE,WAAW3D,SAAS4D,QAAQ;oBAC5BF;oBACAG,eAAe3D,IAAIE,OAAO,CAACiD,OAAO,CAACrB,MAAM8B,QAAQ;oBACjDC,YAAY;oBACZC,cAAc,GAAG1B,sBAAsBnC,QAAQ8D,QAAQC,OAAO,OAAO,CAAC,EACpEtE,WAAWuE,IAAI,CAChB,CAAC,EAAErE,aAAa,MAAM,CAAC;gBAC1B;gBAEAW,YAAYQ,IAAI,CAAC;oBACfC,KAAK;oBACLX;oBACA6D,aAAaX;gBACf;gBAEA,IAAIzD,SAASqE,YAAY,EAAE;oBACzBZ,KAAKa,aAAa,GAAGtE,SAASqE,YAAY;gBAC5C;gBAEA,MAAME,WAAW,MAAMC,MAAMxE,SAASuD,IAAI,EAAEC,gBAAgB;oBAC1DC,MAAM,IAAIgB,gBAAgBhB;oBAC1B5C,SAAS;wBACP,gBAAgB;oBAClB;oBACA6D,QAAQ;gBACV,GAAGC,IAAI,CAAC,CAACC,IAAMA,EAAE7D,IAAI;gBAErBN,YAAYQ,IAAI,CAAC;oBAAEC,KAAK;oBAAkBX;oBAAMgE;gBAAS;gBAEzD,MAAM,EAAEM,YAAY,EAAElC,KAAK,EAAEmC,iBAAiB,EAAEC,YAAYC,mBAAmB,EAAE,GAAGT;gBAEpF9D,YAAYQ,IAAI,CAAC;oBAAEC,KAAK;oBAAcqD;gBAAS;gBAE/C,yBAAyB;gBACzB,MAAMU,gBAAgB,MAAM/F,gBAC1BqF,SAASM,YAAY,EACrB1E,OAAO+E,MAAM,CAACC,KAAK,CAACC,QAAQ;gBAE9B,MAAMC,gBAAgBR;gBAEtB,sCAAsC;gBAEtC,MAAMS,QAAQL,cAAcK,KAAK;gBACjC,MAAMC,YAAYN,cAAcO,SAAS;gBAEzC,IAAI,CAACF,OAAO;oBACV,MAAMG,SAAS,CAAC,GAAG,EACjB5F,kBAAkByF,KAAK,IAAI,eAC5B,yCAAyC,CAAC;oBAC3CpF,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CAAC;wBAAEzB,KAAKuE;wBAAQlF;oBAAK;oBAC7C,MAAM,IAAIzB,SAAS2G;gBACrB;gBAEA,MAAMC,gBAAgBvG,oBAAoB;oBAAES;oBAAYiB,SAASX,IAAIW,OAAO;oBAAEd;gBAAc;gBAE5F,IAAI4C,OAAO;oBACTzC,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CAAC;oBACzBzC,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CAAC;wBAAEgD,KAAKhD;wBAAOmC;oBAAkB;oBACzD,OAAO3D,SAASC,QAAQ,CAACmB;gBAC3B;gBAEA,uCAAuC;gBACvC,MAAMqD,UAAU5G,aAAakB,IAAIW,OAAO;gBAExC,MAAMgF,kBACJ,qBAAqBD,UAAWA,QAAQC,eAAe,GAAc;gBAEvE,IAAI,CAAC3F,IAAI4F,eAAe,EAAE;oBACxB5F,IAAI4F,eAAe,GAAG,IAAIC;gBAC5B;gBAEA,IAAIF,iBAAiB;oBACnB,IAAIrG,cAAcqG,kBAAkB;wBAClCrD,gBAAgBqD;oBAClB,OAAO;wBACLrD,iBAAiBqD;oBACnB;oBAEA3F,IAAI4F,eAAe,CAACE,MAAM,CACxB,cACA,CAAC,gBAAgB,EAAExD,cAAc,oBAAoB,CAAC;gBAE1D;gBAEA,IAAI6C,iBAAiB,CAACxF,kBAAkBoG,aAAa,EAAE;oBACrDxF,YAAYQ,IAAI,CAAC;oBACjB,MAAMiF,gBAAgBnH,eAAe;wBACnCoH,sBAAsB;wBACtB,GAAGT,aAAa;wBAChBtC,MAAM,GAAGpD,SAASoG,UAAU,CAAC,QAAQ,CAAC;wBACtCC,OAAOhB;wBACP,qCAAqC;wBACrCiB,SAAS/G,oBAAoBmG,eAAeY,WAAWtB,uBAAuB;oBAChF;oBAEA9E,IAAI4F,eAAe,CAACE,MAAM,CAAC,cAAcE;gBAC3C;gBAEA,MAAMK,eAAeb,eAAeY,UAChC/G,oBAAoBmG,cAAcY,OAAO,IACzC,IAAIE,KAAKjB,WAAW,gCAAgC;;gBACxD,MAAMkB,cAAc1H,eAAe;oBACjC,GAAG2G,aAAa;oBAChBtC,MAAMpD,SAASoG,UAAU;oBACzBE,SAASC;oBACTJ,sBAAsB;oBACtBE,OAAOf;gBACT;gBAEApF,IAAI4F,eAAe,CAACE,MAAM,CAAC,cAAcS;gBAEzC,OAAOtF,SAASC,QAAQ,CAACoB;YAC3B,EAAE,OAAOmD,KAAc;gBACrBzF,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CAAC;oBAAEgD;oBAAKzE,KAAK;oBAAmCX,MAAML,IAAIM,QAAQ;gBAAC;gBAE3F,OAAOW,SAASJ,IAAI,CAAC;oBAAE4B,OAAO;gBAAkC,GAAG;oBAAEC,QAAQ;gBAAI;YACnF;QACF;QACA8B,QAAQ7E,kBAAkB0B,sBAAsB,EAAEC,kBAAkB,UAAU,QAAQ;QACtFjB,MAAM,CAAC,CAAC,EAAET,aAAa,MAAM,CAAC;IAChC,CAAA,EAAE"}
1
+ {"version":3,"sources":["../../../src/oauth/endpoints/getLoginEndpoint.ts"],"sourcesContent":["import type { CollectionConfig, Endpoint } from 'payload'\n\nimport { APIError, generateCookie, parseCookies } from 'payload'\nimport { getSafeRedirect } from 'payload/shared'\n\nimport type { Strategy } from '../strategy/index.js'\nimport type { CollectionOptions, PluginOptions, StateObj } from '../types.js'\n\nimport { getProjectToken } from '../../api/figma-api.js'\nimport { createCookieOptions } from '../utilities/createCookieOptions.js'\nimport { createDebugLogger } from '../utilities/createDebugLogger.js'\nimport { extractOrigin } from '../utilities/extractOrigin.js'\nimport { getAdminPath } from '../utilities/getAdminPath.js'\nimport { getCookieExpiration } from '../utilities/getCookieExpiration.js'\n\ninterface Args {\n collection: CollectionConfig\n collectionOptions: CollectionOptions\n endpointSlug: string\n pluginOptions: PluginOptions\n strategy: Strategy\n}\n\nconst isAbsoluteURL = (url: string) => /^[a-z][a-z\\d+.-]*:/.test(url)\n\nexport const getLoginEndpoint = ({\n collection,\n collectionOptions,\n endpointSlug,\n pluginOptions,\n strategy,\n}: Args): Endpoint => ({\n handler: async (req) => {\n const { config } = req.payload\n const adminPath = getAdminPath(config)\n try {\n await strategy.ensureMeta()\n\n const path = req.pathname\n const debugLogger = createDebugLogger(req.payload, pluginOptions.debug)\n\n let jsonBody: Record<string, unknown> = {}\n\n const contentType = req.headers.get('content-type')\n\n // Type narrow PayloadRequst's Partial<Request>\n if (typeof req.json !== 'function' || typeof req.formData !== 'function') {\n debugLogger.info({\n msg: 'Request does not have json or formData methods',\n path,\n })\n\n return Response.redirect(`${pluginOptions.redirectServerURL || config.serverURL}/login`)\n }\n\n if (collectionOptions.authorizationURLParams?.response_mode === 'query') {\n if (Object.keys(req.query).length > 0) {\n jsonBody = req.query\n }\n } else if (contentType === 'application/json') {\n jsonBody = await req.json()\n } else if (contentType === 'application/x-www-form-urlencoded') {\n const formData = await req.formData()\n jsonBody = Object.fromEntries(formData.entries())\n }\n\n const stateRaw = jsonBody.state as string\n const state: StateObj = JSON.parse(Buffer.from(stateRaw, 'base64').toString('utf-8'))\n\n const redirectDestination =\n state.serverURL || pluginOptions.redirectServerURL || config.serverURL\n let failedRedirect = `${redirectDestination}${adminPath}/login`\n let redirectToUse = `${redirectDestination}${adminPath}`\n\n if (state.redirect) {\n redirectToUse = state.redirect\n }\n\n if (state.failedRedirect) {\n failedRedirect = state.failedRedirect\n }\n\n failedRedirect = getSafeRedirect({ allowAbsoluteUrls: true, redirectTo: failedRedirect })\n redirectToUse = getSafeRedirect({ allowAbsoluteUrls: true, redirectTo: redirectToUse })\n\n if (!isAbsoluteURL(failedRedirect)) {\n return Response.json({ error: 'Invalid failed redirect provided' }, { status: 403 })\n }\n if (!isAbsoluteURL(redirectToUse)) {\n return Response.json({ error: 'Invalid redirect provided' }, { status: 403 })\n }\n\n if (Array.isArray(req.payload.config.csrf) && req.payload.config.csrf.length > 0) {\n const failedRedirectOrigin = extractOrigin(failedRedirect)\n const redirectToUseOrigin = extractOrigin(redirectToUse)\n\n if (failedRedirectOrigin && !req.payload.config.csrf.includes(failedRedirectOrigin)) {\n req.payload.logger.error(\n `Failed redirect origin ${failedRedirectOrigin} is not allowed by CSRF configuration.`,\n )\n return Response.json(\n { error: 'Failed redirect origin is not allowed by CSRF configuration.' },\n { status: 403 },\n )\n }\n\n if (redirectToUseOrigin && !req.payload.config.csrf.includes(redirectToUseOrigin)) {\n req.payload.logger.error(\n `Redirect origin ${redirectToUseOrigin} is not allowed by CSRF configuration.`,\n )\n return Response.json(\n { error: 'Redirect origin is not allowed by CSRF configuration.' },\n { status: 403 },\n )\n }\n }\n\n // Verify signature\n if (strategy.name !== req.payload.decrypt(state.sig)) {\n req.payload.logger.error('Signature mismatch. Failing login and redirecting.')\n return Response.redirect(failedRedirect)\n }\n\n if (!strategy.meta?.token_endpoint) {\n debugLogger.error({\n msg: `No metadata was obtained from the identity provider. Failing login and redirecting.`,\n path,\n })\n return Response.redirect(failedRedirect)\n }\n\n debugLogger.info({ body: jsonBody, msg: 'Received login response body', path })\n\n if (!jsonBody?.code) {\n debugLogger.error({\n msg: `No authorization code present in body. Failing login and redirecting.`,\n path,\n })\n return Response.redirect(failedRedirect)\n }\n\n // Exchange `code` from body for refresh token\n const { code } = jsonBody\n\n if (typeof code !== 'string') {\n debugLogger.error({\n msg: `Authorization code present in body is not a string. Failing login and redirecting.`,\n path,\n })\n return Response.redirect(failedRedirect)\n }\n\n const body: Record<string, string> = {\n client_id: strategy.clientID,\n code,\n code_verifier: req.payload.decrypt(state.verifier),\n grant_type: 'authorization_code',\n redirect_uri: `${redirectDestination}${config?.routes?.api || '/api'}/${\n collection.slug\n }/${endpointSlug}/login`,\n }\n\n debugLogger.info({\n msg: 'Exchanging code for access token',\n path,\n requestBody: body,\n })\n\n if (strategy.clientSecret) {\n body.client_secret = strategy.clientSecret\n }\n\n const tokenRes = await fetch(strategy.meta?.token_endpoint, {\n body: new URLSearchParams(body),\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n method: 'POST',\n }).then((r) => r.json())\n\n debugLogger.info({ msg: 'Token Response', path, tokenRes })\n\n const { access_token, error, error_description, expires_in: refreshTokenExpires } = tokenRes\n\n debugLogger.info({ msg: 'tokenResss', tokenRes })\n\n // Swap for project token\n const project_token = await getProjectToken(\n tokenRes.access_token,\n config.custom.figma.contentSystemId,\n )\n const refresh_token = access_token\n\n // Store project token as access_token\n\n const token = project_token.token\n const expiresIn = project_token.expiresAt\n\n if (!token) {\n const errMsg = `No ${\n collectionOptions.token || 'access_token'\n } was returned from the identity provider.`\n req.payload.logger.error({ msg: errMsg, path })\n throw new APIError(errMsg)\n }\n\n const cookieOptions = createCookieOptions({ collection, headers: req.headers, pluginOptions })\n\n if (error) {\n req.payload.logger.error('Error swapping access code with access token:')\n req.payload.logger.error({ err: error, error_description })\n return Response.redirect(failedRedirect)\n }\n\n // get the payloadRedirect cookie value\n const cookies = parseCookies(req.headers)\n\n const payloadRedirect =\n 'payloadRedirect' in cookies ? (cookies.payloadRedirect as string) : ''\n\n if (!req.responseHeaders) {\n req.responseHeaders = new Headers()\n }\n\n if (payloadRedirect) {\n if (isAbsoluteURL(payloadRedirect)) {\n redirectToUse = payloadRedirect\n } else {\n redirectToUse += payloadRedirect\n }\n\n req.responseHeaders.append(\n 'Set-Cookie',\n `payloadRedirect=${redirectToUse}; Max-Age=0; Path=/;`,\n )\n }\n\n if (refresh_token && !collectionOptions.usePayloadJWT) {\n debugLogger.info('Setting refresh token cookie')\n const refreshCookie = generateCookie({\n returnCookieAsObject: false,\n ...cookieOptions,\n name: `${strategy.cookieName}-refresh`,\n value: refresh_token,\n // Default to 1 year if no expiration\n expires: getCookieExpiration(cookieOptions?.expires ?? refreshTokenExpires ?? 31_556_952),\n }) as string\n\n req.responseHeaders.append('Set-Cookie', refreshCookie)\n }\n\n const tokenExpires = cookieOptions?.expires\n ? getCookieExpiration(cookieOptions.expires)\n : new Date(expiresIn) // Project token uses epoch time\n const tokenCookie = generateCookie({\n ...cookieOptions,\n name: strategy.cookieName,\n expires: tokenExpires,\n returnCookieAsObject: false,\n value: token,\n }) as string\n\n req.responseHeaders.append('Set-Cookie', tokenCookie)\n\n return Response.redirect(redirectToUse)\n } catch (err: unknown) {\n req.payload.logger.error({ err, msg: 'Error while attempting to login', path: req.pathname })\n\n return Response.json({ error: 'Error while attempting to login' }, { status: 500 })\n }\n },\n method: collectionOptions.authorizationURLParams?.response_mode === 'query' ? 'get' : 'post',\n path: `/${endpointSlug}/login`,\n})\n"],"names":["APIError","generateCookie","parseCookies","getSafeRedirect","getProjectToken","createCookieOptions","createDebugLogger","extractOrigin","getAdminPath","getCookieExpiration","isAbsoluteURL","url","test","getLoginEndpoint","collection","collectionOptions","endpointSlug","pluginOptions","strategy","handler","req","config","payload","adminPath","ensureMeta","path","pathname","debugLogger","debug","jsonBody","contentType","headers","get","json","formData","info","msg","Response","redirect","redirectServerURL","serverURL","authorizationURLParams","response_mode","Object","keys","query","length","fromEntries","entries","stateRaw","state","JSON","parse","Buffer","from","toString","redirectDestination","failedRedirect","redirectToUse","allowAbsoluteUrls","redirectTo","error","status","Array","isArray","csrf","failedRedirectOrigin","redirectToUseOrigin","includes","logger","name","decrypt","sig","meta","token_endpoint","body","code","client_id","clientID","code_verifier","verifier","grant_type","redirect_uri","routes","api","slug","requestBody","clientSecret","client_secret","tokenRes","fetch","URLSearchParams","method","then","r","access_token","error_description","expires_in","refreshTokenExpires","project_token","custom","figma","contentSystemId","refresh_token","token","expiresIn","expiresAt","errMsg","cookieOptions","err","cookies","payloadRedirect","responseHeaders","Headers","append","usePayloadJWT","refreshCookie","returnCookieAsObject","cookieName","value","expires","tokenExpires","Date","tokenCookie"],"mappings":"AAEA,SAASA,QAAQ,EAAEC,cAAc,EAAEC,YAAY,QAAQ,UAAS;AAChE,SAASC,eAAe,QAAQ,iBAAgB;AAKhD,SAASC,eAAe,QAAQ,yBAAwB;AACxD,SAASC,mBAAmB,QAAQ,sCAAqC;AACzE,SAASC,iBAAiB,QAAQ,oCAAmC;AACrE,SAASC,aAAa,QAAQ,gCAA+B;AAC7D,SAASC,YAAY,QAAQ,+BAA8B;AAC3D,SAASC,mBAAmB,QAAQ,sCAAqC;AAUzE,MAAMC,gBAAgB,CAACC,MAAgB,qBAAqBC,IAAI,CAACD;AAEjE,OAAO,MAAME,mBAAmB,CAAC,EAC/BC,UAAU,EACVC,iBAAiB,EACjBC,YAAY,EACZC,aAAa,EACbC,QAAQ,EACH,GAAgB,CAAA;QACrBC,SAAS,OAAOC;YACd,MAAM,EAAEC,MAAM,EAAE,GAAGD,IAAIE,OAAO;YAC9B,MAAMC,YAAYf,aAAaa;YAC/B,IAAI;gBACF,MAAMH,SAASM,UAAU;gBAEzB,MAAMC,OAAOL,IAAIM,QAAQ;gBACzB,MAAMC,cAAcrB,kBAAkBc,IAAIE,OAAO,EAAEL,cAAcW,KAAK;gBAEtE,IAAIC,WAAoC,CAAC;gBAEzC,MAAMC,cAAcV,IAAIW,OAAO,CAACC,GAAG,CAAC;gBAEpC,+CAA+C;gBAC/C,IAAI,OAAOZ,IAAIa,IAAI,KAAK,cAAc,OAAOb,IAAIc,QAAQ,KAAK,YAAY;oBACxEP,YAAYQ,IAAI,CAAC;wBACfC,KAAK;wBACLX;oBACF;oBAEA,OAAOY,SAASC,QAAQ,CAAC,GAAGrB,cAAcsB,iBAAiB,IAAIlB,OAAOmB,SAAS,CAAC,MAAM,CAAC;gBACzF;gBAEA,IAAIzB,kBAAkB0B,sBAAsB,EAAEC,kBAAkB,SAAS;oBACvE,IAAIC,OAAOC,IAAI,CAACxB,IAAIyB,KAAK,EAAEC,MAAM,GAAG,GAAG;wBACrCjB,WAAWT,IAAIyB,KAAK;oBACtB;gBACF,OAAO,IAAIf,gBAAgB,oBAAoB;oBAC7CD,WAAW,MAAMT,IAAIa,IAAI;gBAC3B,OAAO,IAAIH,gBAAgB,qCAAqC;oBAC9D,MAAMI,WAAW,MAAMd,IAAIc,QAAQ;oBACnCL,WAAWc,OAAOI,WAAW,CAACb,SAASc,OAAO;gBAChD;gBAEA,MAAMC,WAAWpB,SAASqB,KAAK;gBAC/B,MAAMA,QAAkBC,KAAKC,KAAK,CAACC,OAAOC,IAAI,CAACL,UAAU,UAAUM,QAAQ,CAAC;gBAE5E,MAAMC,sBACJN,MAAMV,SAAS,IAAIvB,cAAcsB,iBAAiB,IAAIlB,OAAOmB,SAAS;gBACxE,IAAIiB,iBAAiB,GAAGD,sBAAsBjC,UAAU,MAAM,CAAC;gBAC/D,IAAImC,gBAAgB,GAAGF,sBAAsBjC,WAAW;gBAExD,IAAI2B,MAAMZ,QAAQ,EAAE;oBAClBoB,gBAAgBR,MAAMZ,QAAQ;gBAChC;gBAEA,IAAIY,MAAMO,cAAc,EAAE;oBACxBA,iBAAiBP,MAAMO,cAAc;gBACvC;gBAEAA,iBAAiBtD,gBAAgB;oBAAEwD,mBAAmB;oBAAMC,YAAYH;gBAAe;gBACvFC,gBAAgBvD,gBAAgB;oBAAEwD,mBAAmB;oBAAMC,YAAYF;gBAAc;gBAErF,IAAI,CAAChD,cAAc+C,iBAAiB;oBAClC,OAAOpB,SAASJ,IAAI,CAAC;wBAAE4B,OAAO;oBAAmC,GAAG;wBAAEC,QAAQ;oBAAI;gBACpF;gBACA,IAAI,CAACpD,cAAcgD,gBAAgB;oBACjC,OAAOrB,SAASJ,IAAI,CAAC;wBAAE4B,OAAO;oBAA4B,GAAG;wBAAEC,QAAQ;oBAAI;gBAC7E;gBAEA,IAAIC,MAAMC,OAAO,CAAC5C,IAAIE,OAAO,CAACD,MAAM,CAAC4C,IAAI,KAAK7C,IAAIE,OAAO,CAACD,MAAM,CAAC4C,IAAI,CAACnB,MAAM,GAAG,GAAG;oBAChF,MAAMoB,uBAAuB3D,cAAckD;oBAC3C,MAAMU,sBAAsB5D,cAAcmD;oBAE1C,IAAIQ,wBAAwB,CAAC9C,IAAIE,OAAO,CAACD,MAAM,CAAC4C,IAAI,CAACG,QAAQ,CAACF,uBAAuB;wBACnF9C,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CACtB,CAAC,uBAAuB,EAAEK,qBAAqB,sCAAsC,CAAC;wBAExF,OAAO7B,SAASJ,IAAI,CAClB;4BAAE4B,OAAO;wBAA+D,GACxE;4BAAEC,QAAQ;wBAAI;oBAElB;oBAEA,IAAIK,uBAAuB,CAAC/C,IAAIE,OAAO,CAACD,MAAM,CAAC4C,IAAI,CAACG,QAAQ,CAACD,sBAAsB;wBACjF/C,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CACtB,CAAC,gBAAgB,EAAEM,oBAAoB,sCAAsC,CAAC;wBAEhF,OAAO9B,SAASJ,IAAI,CAClB;4BAAE4B,OAAO;wBAAwD,GACjE;4BAAEC,QAAQ;wBAAI;oBAElB;gBACF;gBAEA,mBAAmB;gBACnB,IAAI5C,SAASoD,IAAI,KAAKlD,IAAIE,OAAO,CAACiD,OAAO,CAACrB,MAAMsB,GAAG,GAAG;oBACpDpD,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CAAC;oBACzB,OAAOxB,SAASC,QAAQ,CAACmB;gBAC3B;gBAEA,IAAI,CAACvC,SAASuD,IAAI,EAAEC,gBAAgB;oBAClC/C,YAAYkC,KAAK,CAAC;wBAChBzB,KAAK,CAAC,mFAAmF,CAAC;wBAC1FX;oBACF;oBACA,OAAOY,SAASC,QAAQ,CAACmB;gBAC3B;gBAEA9B,YAAYQ,IAAI,CAAC;oBAAEwC,MAAM9C;oBAAUO,KAAK;oBAAgCX;gBAAK;gBAE7E,IAAI,CAACI,UAAU+C,MAAM;oBACnBjD,YAAYkC,KAAK,CAAC;wBAChBzB,KAAK,CAAC,qEAAqE,CAAC;wBAC5EX;oBACF;oBACA,OAAOY,SAASC,QAAQ,CAACmB;gBAC3B;gBAEA,8CAA8C;gBAC9C,MAAM,EAAEmB,IAAI,EAAE,GAAG/C;gBAEjB,IAAI,OAAO+C,SAAS,UAAU;oBAC5BjD,YAAYkC,KAAK,CAAC;wBAChBzB,KAAK,CAAC,kFAAkF,CAAC;wBACzFX;oBACF;oBACA,OAAOY,SAASC,QAAQ,CAACmB;gBAC3B;gBAEA,MAAMkB,OAA+B;oBACnCE,WAAW3D,SAAS4D,QAAQ;oBAC5BF;oBACAG,eAAe3D,IAAIE,OAAO,CAACiD,OAAO,CAACrB,MAAM8B,QAAQ;oBACjDC,YAAY;oBACZC,cAAc,GAAG1B,sBAAsBnC,QAAQ8D,QAAQC,OAAO,OAAO,CAAC,EACpEtE,WAAWuE,IAAI,CAChB,CAAC,EAAErE,aAAa,MAAM,CAAC;gBAC1B;gBAEAW,YAAYQ,IAAI,CAAC;oBACfC,KAAK;oBACLX;oBACA6D,aAAaX;gBACf;gBAEA,IAAIzD,SAASqE,YAAY,EAAE;oBACzBZ,KAAKa,aAAa,GAAGtE,SAASqE,YAAY;gBAC5C;gBAEA,MAAME,WAAW,MAAMC,MAAMxE,SAASuD,IAAI,EAAEC,gBAAgB;oBAC1DC,MAAM,IAAIgB,gBAAgBhB;oBAC1B5C,SAAS;wBACP,gBAAgB;oBAClB;oBACA6D,QAAQ;gBACV,GAAGC,IAAI,CAAC,CAACC,IAAMA,EAAE7D,IAAI;gBAErBN,YAAYQ,IAAI,CAAC;oBAAEC,KAAK;oBAAkBX;oBAAMgE;gBAAS;gBAEzD,MAAM,EAAEM,YAAY,EAAElC,KAAK,EAAEmC,iBAAiB,EAAEC,YAAYC,mBAAmB,EAAE,GAAGT;gBAEpF9D,YAAYQ,IAAI,CAAC;oBAAEC,KAAK;oBAAcqD;gBAAS;gBAE/C,yBAAyB;gBACzB,MAAMU,gBAAgB,MAAM/F,gBAC1BqF,SAASM,YAAY,EACrB1E,OAAO+E,MAAM,CAACC,KAAK,CAACC,eAAe;gBAErC,MAAMC,gBAAgBR;gBAEtB,sCAAsC;gBAEtC,MAAMS,QAAQL,cAAcK,KAAK;gBACjC,MAAMC,YAAYN,cAAcO,SAAS;gBAEzC,IAAI,CAACF,OAAO;oBACV,MAAMG,SAAS,CAAC,GAAG,EACjB5F,kBAAkByF,KAAK,IAAI,eAC5B,yCAAyC,CAAC;oBAC3CpF,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CAAC;wBAAEzB,KAAKuE;wBAAQlF;oBAAK;oBAC7C,MAAM,IAAIzB,SAAS2G;gBACrB;gBAEA,MAAMC,gBAAgBvG,oBAAoB;oBAAES;oBAAYiB,SAASX,IAAIW,OAAO;oBAAEd;gBAAc;gBAE5F,IAAI4C,OAAO;oBACTzC,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CAAC;oBACzBzC,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CAAC;wBAAEgD,KAAKhD;wBAAOmC;oBAAkB;oBACzD,OAAO3D,SAASC,QAAQ,CAACmB;gBAC3B;gBAEA,uCAAuC;gBACvC,MAAMqD,UAAU5G,aAAakB,IAAIW,OAAO;gBAExC,MAAMgF,kBACJ,qBAAqBD,UAAWA,QAAQC,eAAe,GAAc;gBAEvE,IAAI,CAAC3F,IAAI4F,eAAe,EAAE;oBACxB5F,IAAI4F,eAAe,GAAG,IAAIC;gBAC5B;gBAEA,IAAIF,iBAAiB;oBACnB,IAAIrG,cAAcqG,kBAAkB;wBAClCrD,gBAAgBqD;oBAClB,OAAO;wBACLrD,iBAAiBqD;oBACnB;oBAEA3F,IAAI4F,eAAe,CAACE,MAAM,CACxB,cACA,CAAC,gBAAgB,EAAExD,cAAc,oBAAoB,CAAC;gBAE1D;gBAEA,IAAI6C,iBAAiB,CAACxF,kBAAkBoG,aAAa,EAAE;oBACrDxF,YAAYQ,IAAI,CAAC;oBACjB,MAAMiF,gBAAgBnH,eAAe;wBACnCoH,sBAAsB;wBACtB,GAAGT,aAAa;wBAChBtC,MAAM,GAAGpD,SAASoG,UAAU,CAAC,QAAQ,CAAC;wBACtCC,OAAOhB;wBACP,qCAAqC;wBACrCiB,SAAS/G,oBAAoBmG,eAAeY,WAAWtB,uBAAuB;oBAChF;oBAEA9E,IAAI4F,eAAe,CAACE,MAAM,CAAC,cAAcE;gBAC3C;gBAEA,MAAMK,eAAeb,eAAeY,UAChC/G,oBAAoBmG,cAAcY,OAAO,IACzC,IAAIE,KAAKjB,WAAW,gCAAgC;;gBACxD,MAAMkB,cAAc1H,eAAe;oBACjC,GAAG2G,aAAa;oBAChBtC,MAAMpD,SAASoG,UAAU;oBACzBE,SAASC;oBACTJ,sBAAsB;oBACtBE,OAAOf;gBACT;gBAEApF,IAAI4F,eAAe,CAACE,MAAM,CAAC,cAAcS;gBAEzC,OAAOtF,SAASC,QAAQ,CAACoB;YAC3B,EAAE,OAAOmD,KAAc;gBACrBzF,IAAIE,OAAO,CAAC+C,MAAM,CAACR,KAAK,CAAC;oBAAEgD;oBAAKzE,KAAK;oBAAmCX,MAAML,IAAIM,QAAQ;gBAAC;gBAE3F,OAAOW,SAASJ,IAAI,CAAC;oBAAE4B,OAAO;gBAAkC,GAAG;oBAAEC,QAAQ;gBAAI;YACnF;QACF;QACA8B,QAAQ7E,kBAAkB0B,sBAAsB,EAAEC,kBAAkB,UAAU,QAAQ;QACtFjB,MAAM,CAAC,CAAC,EAAET,aAAa,MAAM,CAAC;IAChC,CAAA,EAAE"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/oauth/strategy/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAA;AAEnC,OAAO,KAAK,EACV,wBAAwB,EACxB,kBAAkB,EAClB,gBAAgB,EAChB,OAAO,EACR,MAAM,SAAS,CAAA;AAEhB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAG5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AASnF,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,gBAAgB,EAAE,MAAM,CAAA;IACxB,aAAa,EAAE,aAAa,CAAA;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,cAAc,CAAA;CACvB;AAED,qBAAa,QAAQ;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,UAAU,EAAE,MAAM,CAAA;IAElB,KAAK,EAAE,OAAO,CAAA;IAGd,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAElC,mBAAmB,EAAE,MAAM,CAAA;IAC3B,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,CAAA;KACjB,CAAA;IACD,IAAI,CAAC,EAAE;QACL,sBAAsB,EAAE,MAAM,CAAA;QAC9B,oBAAoB,EAAE,MAAM,CAAA;QAC5B,QAAQ,EAAE,MAAM,CAAA;QAChB,cAAc,EAAE,MAAM,CAAA;QACtB,iBAAiB,EAAE,MAAM,CAAA;KAC1B,CAAA;IACD,mBAAmB,CAAC,EAAE,IAAI,CAAA;IAE1B,WAAW,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,aAAa,CAAA;IAC5B,MAAM,EAAE,cAAc,CAAA;gBAEV,OAAO,EAAE,OAAO;IAiBtB,YAAY,CAAC,EACjB,aAAa,EACb,OAAO,EACP,OAAO,GACR,EAAE,wBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAyJnD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAe3B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAkD1B,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA6C1D,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,KAAK,GAAG,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC;CAmB3F;AAED,KAAK,aAAa,GAAG;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/oauth/strategy/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,cAAc,CAAA;AAEnC,OAAO,KAAK,EACV,wBAAwB,EACxB,kBAAkB,EAClB,gBAAgB,EAChB,OAAO,EACR,MAAM,SAAS,CAAA;AAEhB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAG5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AASnF,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,gBAAgB,EAAE,MAAM,CAAA;IACxB,aAAa,EAAE,aAAa,CAAA;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,cAAc,CAAA;CACvB;AAED,qBAAa,QAAQ;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,gBAAgB,CAAA;IAC5B,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,UAAU,EAAE,MAAM,CAAA;IAElB,KAAK,EAAE,OAAO,CAAA;IAGd,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAElC,mBAAmB,EAAE,MAAM,CAAA;IAC3B,IAAI,CAAC,EAAE;QACL,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,CAAA;KACjB,CAAA;IACD,IAAI,CAAC,EAAE;QACL,sBAAsB,EAAE,MAAM,CAAA;QAC9B,oBAAoB,EAAE,MAAM,CAAA;QAC5B,QAAQ,EAAE,MAAM,CAAA;QAChB,cAAc,EAAE,MAAM,CAAA;QACtB,iBAAiB,EAAE,MAAM,CAAA;KAC1B,CAAA;IACD,mBAAmB,CAAC,EAAE,IAAI,CAAA;IAE1B,WAAW,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,aAAa,CAAA;IAC5B,MAAM,EAAE,cAAc,CAAA;gBAEV,OAAO,EAAE,OAAO;IAiBtB,YAAY,CAAC,EACjB,aAAa,EACb,OAAO,EACP,OAAO,GACR,EAAE,wBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAyJnD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAe3B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAwD1B,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA6C1D,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,KAAK,GAAG,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC;CAmB3F;AAED,KAAK,aAAa,GAAG;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA"}
@@ -200,6 +200,10 @@ export class Strategy {
200
200
  for(let attempt = 1; attempt <= 5; attempt++){
201
201
  try {
202
202
  this.meta = await fetch(this.identityMetadataURL).then((res)=>res.json());
203
+ if (this.meta) {
204
+ // TODO: This is a hack to get the DefaultLoginButton to work with dynamic OAuth client registration
205
+ this.meta.authorization_endpoint = this.meta?.authorization_endpoint + '/cms';
206
+ }
203
207
  this.debugLog(`fetchMeta - success on attempt ${attempt}`);
204
208
  if (this.meta?.jwks_uri) {
205
209
  this.jwks = await fetch(this.meta.jwks_uri).then((res)=>res.json());
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/oauth/strategy/index.ts"],"sourcesContent":["import type jwt from 'jsonwebtoken'\n/* eslint-disable @typescript-eslint/restrict-template-expressions */\nimport type {\n AuthStrategyFunctionArgs,\n AuthStrategyResult,\n CollectionConfig,\n Payload,\n} from 'payload'\n\nimport * as jose from 'jose'\nimport { APIError, parseCookies } from 'payload'\n\nimport type { CollectionOptions, PluginOptions, VerifyFunction } from '../types.js'\n\nimport { validateProjectToken } from '../../auth/jwt-validator.js'\nimport { getEnvironment } from '../../constants.js'\nimport { createDebugLogger } from '../utilities/createDebugLogger.js'\nimport { getTokenExp } from '../utilities/getTokenExp.js'\nimport { mergeHeaders } from '../utilities/mergeHeaders.js'\nimport { refreshTokens } from '../utilities/refreshTokens.js'\n\nexport interface Options {\n clientID: string\n clientSecret?: string\n collection: CollectionConfig\n collectionOptions: CollectionOptions\n cookieName: string\n debug?: boolean\n identityMetadata: string\n pluginOptions: PluginOptions\n strategyName: string\n verify: VerifyFunction\n}\n\nexport class Strategy {\n clientID: string\n clientSecret?: string\n collection: CollectionConfig\n collectionOptions: CollectionOptions\n cookieName: string\n\n debug: boolean\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n debugLog: (...args: any[]) => void\n\n identityMetadataURL: string\n jwks?: {\n keys: jose.JWK[]\n }\n meta?: {\n authorization_endpoint: string\n end_session_endpoint: string\n jwks_uri: string\n token_endpoint: string\n userinfo_endpoint: string\n }\n metaLastFetchedTime?: Date\n\n metaPromise?: Promise<void>\n metaPromiseResolve?: () => void\n name: string\n pluginOptions: PluginOptions\n verify: VerifyFunction\n\n constructor(options: Options) {\n this.verify = options.verify\n this.cookieName = options.cookieName\n this.clientID = options.clientID\n this.clientSecret = options.clientSecret\n this.identityMetadataURL = options.identityMetadata\n this.name = options.strategyName\n this.collection = options.collection\n this.collectionOptions = options.collectionOptions\n this.pluginOptions = options.pluginOptions\n this.debug = options.debug || false\n // eslint-disable-next-line no-console, @typescript-eslint/no-explicit-any\n this.debugLog = options.debug ? (...args: any[]) => console.log(...args) : () => null\n // Prevent wokiness with `this`\n this.ensureMeta = this.ensureMeta.bind(this)\n }\n\n async authenticate({\n canSetHeaders,\n headers,\n payload,\n }: AuthStrategyFunctionArgs): Promise<AuthStrategyResult> {\n const debugLogger = createDebugLogger(payload, this.debug)\n await this.ensureMeta()\n\n const cookies = parseCookies(headers)\n\n let oauthToken = cookies.get(this.cookieName)\n const refreshToken = cookies.get(`${this.cookieName}-refresh`)\n\n debugLogger.info({\n msg: 'Retrieved tokens from cookies',\n oauthToken,\n refreshToken,\n })\n\n if (!this.collectionOptions.disableJWTFromHeader) {\n // Parse Authorization header if exists\n const jwtFromHeader = headers.get('authorization')\n if (typeof jwtFromHeader === 'string' && jwtFromHeader.startsWith('Bearer ')) {\n debugLogger.info({\n jwtFromHeader,\n msg: 'Found bearer token in authorization header',\n })\n oauthToken = jwtFromHeader.replace('Bearer ', '')\n }\n }\n\n if (!oauthToken) {\n if (refreshToken && canSetHeaders) {\n debugLogger.info({\n msg: 'No access token found, but refresh token exists. Attempting to refresh...',\n refreshToken,\n })\n const refreshed = await refreshTokens({ payload, refreshToken, strategy: this })\n if (refreshed) {\n const verifyResult = await this.verify({\n headers,\n payload,\n token: refreshed.decodedOauthToken,\n })\n\n debugLogger.info({\n msg: 'Token refreshed. Verifying...',\n verifyResult,\n })\n\n if (verifyResult.responseHeaders) {\n mergeHeaders(verifyResult.responseHeaders, refreshed.headers)\n }\n\n return {\n responseHeaders: refreshed.headers,\n user: verifyResult.user,\n }\n } else {\n debugLogger.info({\n msg: 'Token refresh failed',\n refreshed,\n refreshToken,\n })\n }\n } else {\n return {\n user: null,\n }\n }\n }\n\n let oauthTokenVerifyResult: Error | jwt.JwtPayload | null = null\n\n // First, try to verify token\n if (oauthToken) {\n oauthTokenVerifyResult = await this.jwtVerify({ payload, token: oauthToken })\n\n // If verify comes back null, there is no user\n if (oauthTokenVerifyResult === null) {\n return {\n user: null,\n }\n }\n\n // If verify comes back truthy, use it\n // but first set exp from refresh token\n // because access exp is likely very short lived\n if (\n typeof oauthTokenVerifyResult === 'object' &&\n !(oauthTokenVerifyResult instanceof Error)\n ) {\n if (refreshToken) {\n const refreshTokenExp = getTokenExp({ debugLogger, token: refreshToken })\n\n if (refreshTokenExp) {\n oauthTokenVerifyResult.exp = refreshTokenExp\n }\n }\n\n return this.verify({\n headers,\n payload,\n token: oauthTokenVerifyResult,\n })\n }\n }\n\n if (\n oauthTokenVerifyResult instanceof Error &&\n oauthTokenVerifyResult.name === 'TokenExpiredError' &&\n refreshToken &&\n !this.collectionOptions.usePayloadJWT &&\n canSetHeaders\n ) {\n const refreshed = await refreshTokens({ payload, refreshToken, strategy: this })\n\n debugLogger.info({\n msg: 'Token expired. Refreshing...',\n refreshed,\n refreshToken,\n })\n\n if (refreshed) {\n const verifyResult = await this.verify({\n headers,\n payload,\n token: refreshed.decodedOauthToken,\n })\n\n debugLogger.info({\n msg: 'Token refreshed. Verifying...',\n verifyResult,\n })\n\n if (verifyResult.responseHeaders) {\n mergeHeaders(verifyResult.responseHeaders, refreshed.headers)\n }\n\n return {\n responseHeaders: refreshed.headers,\n user: verifyResult.user,\n }\n } else {\n debugLogger.info({\n msg: 'Token refresh failed',\n refreshed,\n refreshToken,\n })\n }\n }\n\n return {\n user: null,\n }\n }\n\n async ensureMeta(): Promise<void> {\n if (this.metaPromise) {\n this.debugLog('strategy - metaPromise exists. Waiting for it to resolve...')\n await this.metaPromise\n }\n\n // If no meta or this.metaLastFetchedTime is more than 24 hours old, fetch meta\n if (!this.metaLastFetchedTime || Date.now() - this.metaLastFetchedTime.getTime() > 86_400_000) {\n this.debugLog(\n `Meta is stale. Fetching... Last fetched: ${this.metaLastFetchedTime || 'never'}`,\n )\n await this.fetchMeta()\n }\n }\n\n async fetchMeta(): Promise<void> {\n // If already in-flight, return the existing promise\n if (this.metaPromise) {\n this.debugLog('fetchMeta - returning existing metaPromise')\n return this.metaPromise\n }\n\n this.debugLog('fetchMeta - creating new metaPromise...')\n\n // Build the shared promise\n this.metaPromise = (async () => {\n let lastError: unknown\n\n for (let attempt = 1; attempt <= 5; attempt++) {\n try {\n this.meta = await fetch(this.identityMetadataURL).then((res) => res.json())\n this.debugLog(`fetchMeta - success on attempt ${attempt}`)\n\n if (this.meta?.jwks_uri) {\n this.jwks = await fetch(this.meta.jwks_uri).then((res) => res.json())\n }\n\n this.metaLastFetchedTime = new Date()\n this.debugLog(`fetchMeta - finished at ${this.metaLastFetchedTime.toISOString()}`)\n return\n } catch (error: unknown) {\n lastError = error\n this.debugLog(`fetchMeta - FAILED attempt ${attempt}/5: ${(error as Error)?.message}`)\n\n if (attempt < 5) {\n // Exponential backoff (up to 1s)\n await new Promise((resolve) => setTimeout(resolve, Math.min(attempt * 200, 1000)))\n }\n }\n }\n\n throw new APIError(\n `Failed to fetch identity metadata from \"${this.identityMetadataURL}\". Last error: ${\n (lastError as Error)?.message ?? 'unknown'\n }`,\n )\n })()\n\n try {\n await this.metaPromise\n } finally {\n this.metaPromise = undefined\n }\n }\n\n async generateOidcPEM(kid: string, alg: string): Promise<string> {\n const keys = this && this.jwks && Array.isArray(this.jwks.keys) ? this.jwks.keys : null\n\n let pubKey: null | string = null\n let foundKey = false\n\n if (!kid) {\n throw new Error('kid is missing')\n }\n\n if (!alg) {\n throw new Error('alg is missing')\n }\n\n if (!keys) {\n throw new Error('keys is missing')\n }\n\n for (const key of keys) {\n if (!('kid' in key) || key.kid !== kid) {\n continue\n }\n\n const cryptoKey = await jose.importJWK(key, alg)\n if (!(cryptoKey instanceof CryptoKey)) {\n throw new Error('importJWK did not return a CryptoKey')\n }\n\n pubKey = await jose.exportSPKI(cryptoKey)\n foundKey = true\n\n break\n }\n\n if (!foundKey) {\n throw new Error('a key with the specific kid cannot be found')\n }\n\n if (!pubKey) {\n throw new Error('generating public key pem failed')\n }\n\n return pubKey\n }\n\n async jwtVerify({ payload, token }: JwtVerifyArgs): Promise<Error | jwt.JwtPayload | null> {\n try {\n const verified = await validateProjectToken(token, getEnvironment())\n if (typeof verified !== 'string') {\n return verified\n }\n } catch (err: unknown) {\n payload.logger.error({\n err,\n msg: 'Error verifying jwt token',\n })\n\n if (err instanceof Error) {\n return err\n }\n return null\n }\n return null\n }\n}\n\ntype JwtVerifyArgs = {\n payload: Payload\n token: string\n}\n"],"names":["jose","APIError","parseCookies","validateProjectToken","getEnvironment","createDebugLogger","getTokenExp","mergeHeaders","refreshTokens","Strategy","clientID","clientSecret","collection","collectionOptions","cookieName","debug","debugLog","identityMetadataURL","jwks","meta","metaLastFetchedTime","metaPromise","metaPromiseResolve","name","pluginOptions","verify","options","identityMetadata","strategyName","args","console","log","ensureMeta","bind","authenticate","canSetHeaders","headers","payload","debugLogger","cookies","oauthToken","get","refreshToken","info","msg","disableJWTFromHeader","jwtFromHeader","startsWith","replace","refreshed","strategy","verifyResult","token","decodedOauthToken","responseHeaders","user","oauthTokenVerifyResult","jwtVerify","Error","refreshTokenExp","exp","usePayloadJWT","Date","now","getTime","fetchMeta","lastError","attempt","fetch","then","res","json","jwks_uri","toISOString","error","message","Promise","resolve","setTimeout","Math","min","undefined","generateOidcPEM","kid","alg","keys","Array","isArray","pubKey","foundKey","key","cryptoKey","importJWK","CryptoKey","exportSPKI","verified","err","logger"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/oauth/strategy/index.ts"],"sourcesContent":["import type jwt from 'jsonwebtoken'\n/* eslint-disable @typescript-eslint/restrict-template-expressions */\nimport type {\n AuthStrategyFunctionArgs,\n AuthStrategyResult,\n CollectionConfig,\n Payload,\n} from 'payload'\n\nimport * as jose from 'jose'\nimport { APIError, parseCookies } from 'payload'\n\nimport type { CollectionOptions, PluginOptions, VerifyFunction } from '../types.js'\n\nimport { validateProjectToken } from '../../auth/jwt-validator.js'\nimport { getEnvironment } from '../../constants.js'\nimport { createDebugLogger } from '../utilities/createDebugLogger.js'\nimport { getTokenExp } from '../utilities/getTokenExp.js'\nimport { mergeHeaders } from '../utilities/mergeHeaders.js'\nimport { refreshTokens } from '../utilities/refreshTokens.js'\n\nexport interface Options {\n clientID: string\n clientSecret?: string\n collection: CollectionConfig\n collectionOptions: CollectionOptions\n cookieName: string\n debug?: boolean\n identityMetadata: string\n pluginOptions: PluginOptions\n strategyName: string\n verify: VerifyFunction\n}\n\nexport class Strategy {\n clientID: string\n clientSecret?: string\n collection: CollectionConfig\n collectionOptions: CollectionOptions\n cookieName: string\n\n debug: boolean\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n debugLog: (...args: any[]) => void\n\n identityMetadataURL: string\n jwks?: {\n keys: jose.JWK[]\n }\n meta?: {\n authorization_endpoint: string\n end_session_endpoint: string\n jwks_uri: string\n token_endpoint: string\n userinfo_endpoint: string\n }\n metaLastFetchedTime?: Date\n\n metaPromise?: Promise<void>\n metaPromiseResolve?: () => void\n name: string\n pluginOptions: PluginOptions\n verify: VerifyFunction\n\n constructor(options: Options) {\n this.verify = options.verify\n this.cookieName = options.cookieName\n this.clientID = options.clientID\n this.clientSecret = options.clientSecret\n this.identityMetadataURL = options.identityMetadata\n this.name = options.strategyName\n this.collection = options.collection\n this.collectionOptions = options.collectionOptions\n this.pluginOptions = options.pluginOptions\n this.debug = options.debug || false\n // eslint-disable-next-line no-console, @typescript-eslint/no-explicit-any\n this.debugLog = options.debug ? (...args: any[]) => console.log(...args) : () => null\n // Prevent wokiness with `this`\n this.ensureMeta = this.ensureMeta.bind(this)\n }\n\n async authenticate({\n canSetHeaders,\n headers,\n payload,\n }: AuthStrategyFunctionArgs): Promise<AuthStrategyResult> {\n const debugLogger = createDebugLogger(payload, this.debug)\n await this.ensureMeta()\n\n const cookies = parseCookies(headers)\n\n let oauthToken = cookies.get(this.cookieName)\n const refreshToken = cookies.get(`${this.cookieName}-refresh`)\n\n debugLogger.info({\n msg: 'Retrieved tokens from cookies',\n oauthToken,\n refreshToken,\n })\n\n if (!this.collectionOptions.disableJWTFromHeader) {\n // Parse Authorization header if exists\n const jwtFromHeader = headers.get('authorization')\n if (typeof jwtFromHeader === 'string' && jwtFromHeader.startsWith('Bearer ')) {\n debugLogger.info({\n jwtFromHeader,\n msg: 'Found bearer token in authorization header',\n })\n oauthToken = jwtFromHeader.replace('Bearer ', '')\n }\n }\n\n if (!oauthToken) {\n if (refreshToken && canSetHeaders) {\n debugLogger.info({\n msg: 'No access token found, but refresh token exists. Attempting to refresh...',\n refreshToken,\n })\n const refreshed = await refreshTokens({ payload, refreshToken, strategy: this })\n if (refreshed) {\n const verifyResult = await this.verify({\n headers,\n payload,\n token: refreshed.decodedOauthToken,\n })\n\n debugLogger.info({\n msg: 'Token refreshed. Verifying...',\n verifyResult,\n })\n\n if (verifyResult.responseHeaders) {\n mergeHeaders(verifyResult.responseHeaders, refreshed.headers)\n }\n\n return {\n responseHeaders: refreshed.headers,\n user: verifyResult.user,\n }\n } else {\n debugLogger.info({\n msg: 'Token refresh failed',\n refreshed,\n refreshToken,\n })\n }\n } else {\n return {\n user: null,\n }\n }\n }\n\n let oauthTokenVerifyResult: Error | jwt.JwtPayload | null = null\n\n // First, try to verify token\n if (oauthToken) {\n oauthTokenVerifyResult = await this.jwtVerify({ payload, token: oauthToken })\n\n // If verify comes back null, there is no user\n if (oauthTokenVerifyResult === null) {\n return {\n user: null,\n }\n }\n\n // If verify comes back truthy, use it\n // but first set exp from refresh token\n // because access exp is likely very short lived\n if (\n typeof oauthTokenVerifyResult === 'object' &&\n !(oauthTokenVerifyResult instanceof Error)\n ) {\n if (refreshToken) {\n const refreshTokenExp = getTokenExp({ debugLogger, token: refreshToken })\n\n if (refreshTokenExp) {\n oauthTokenVerifyResult.exp = refreshTokenExp\n }\n }\n\n return this.verify({\n headers,\n payload,\n token: oauthTokenVerifyResult,\n })\n }\n }\n\n if (\n oauthTokenVerifyResult instanceof Error &&\n oauthTokenVerifyResult.name === 'TokenExpiredError' &&\n refreshToken &&\n !this.collectionOptions.usePayloadJWT &&\n canSetHeaders\n ) {\n const refreshed = await refreshTokens({ payload, refreshToken, strategy: this })\n\n debugLogger.info({\n msg: 'Token expired. Refreshing...',\n refreshed,\n refreshToken,\n })\n\n if (refreshed) {\n const verifyResult = await this.verify({\n headers,\n payload,\n token: refreshed.decodedOauthToken,\n })\n\n debugLogger.info({\n msg: 'Token refreshed. Verifying...',\n verifyResult,\n })\n\n if (verifyResult.responseHeaders) {\n mergeHeaders(verifyResult.responseHeaders, refreshed.headers)\n }\n\n return {\n responseHeaders: refreshed.headers,\n user: verifyResult.user,\n }\n } else {\n debugLogger.info({\n msg: 'Token refresh failed',\n refreshed,\n refreshToken,\n })\n }\n }\n\n return {\n user: null,\n }\n }\n\n async ensureMeta(): Promise<void> {\n if (this.metaPromise) {\n this.debugLog('strategy - metaPromise exists. Waiting for it to resolve...')\n await this.metaPromise\n }\n\n // If no meta or this.metaLastFetchedTime is more than 24 hours old, fetch meta\n if (!this.metaLastFetchedTime || Date.now() - this.metaLastFetchedTime.getTime() > 86_400_000) {\n this.debugLog(\n `Meta is stale. Fetching... Last fetched: ${this.metaLastFetchedTime || 'never'}`,\n )\n await this.fetchMeta()\n }\n }\n\n async fetchMeta(): Promise<void> {\n // If already in-flight, return the existing promise\n if (this.metaPromise) {\n this.debugLog('fetchMeta - returning existing metaPromise')\n return this.metaPromise\n }\n\n this.debugLog('fetchMeta - creating new metaPromise...')\n\n // Build the shared promise\n this.metaPromise = (async () => {\n let lastError: unknown\n\n for (let attempt = 1; attempt <= 5; attempt++) {\n try {\n this.meta = await fetch(this.identityMetadataURL).then((res) => res.json())\n\n if (this.meta) {\n // TODO: This is a hack to get the DefaultLoginButton to work with dynamic OAuth client registration\n this.meta.authorization_endpoint = this.meta?.authorization_endpoint + '/cms'\n }\n\n this.debugLog(`fetchMeta - success on attempt ${attempt}`)\n\n if (this.meta?.jwks_uri) {\n this.jwks = await fetch(this.meta.jwks_uri).then((res) => res.json())\n }\n\n this.metaLastFetchedTime = new Date()\n this.debugLog(`fetchMeta - finished at ${this.metaLastFetchedTime.toISOString()}`)\n return\n } catch (error: unknown) {\n lastError = error\n this.debugLog(`fetchMeta - FAILED attempt ${attempt}/5: ${(error as Error)?.message}`)\n\n if (attempt < 5) {\n // Exponential backoff (up to 1s)\n await new Promise((resolve) => setTimeout(resolve, Math.min(attempt * 200, 1000)))\n }\n }\n }\n\n throw new APIError(\n `Failed to fetch identity metadata from \"${this.identityMetadataURL}\". Last error: ${\n (lastError as Error)?.message ?? 'unknown'\n }`,\n )\n })()\n\n try {\n await this.metaPromise\n } finally {\n this.metaPromise = undefined\n }\n }\n\n async generateOidcPEM(kid: string, alg: string): Promise<string> {\n const keys = this && this.jwks && Array.isArray(this.jwks.keys) ? this.jwks.keys : null\n\n let pubKey: null | string = null\n let foundKey = false\n\n if (!kid) {\n throw new Error('kid is missing')\n }\n\n if (!alg) {\n throw new Error('alg is missing')\n }\n\n if (!keys) {\n throw new Error('keys is missing')\n }\n\n for (const key of keys) {\n if (!('kid' in key) || key.kid !== kid) {\n continue\n }\n\n const cryptoKey = await jose.importJWK(key, alg)\n if (!(cryptoKey instanceof CryptoKey)) {\n throw new Error('importJWK did not return a CryptoKey')\n }\n\n pubKey = await jose.exportSPKI(cryptoKey)\n foundKey = true\n\n break\n }\n\n if (!foundKey) {\n throw new Error('a key with the specific kid cannot be found')\n }\n\n if (!pubKey) {\n throw new Error('generating public key pem failed')\n }\n\n return pubKey\n }\n\n async jwtVerify({ payload, token }: JwtVerifyArgs): Promise<Error | jwt.JwtPayload | null> {\n try {\n const verified = await validateProjectToken(token, getEnvironment())\n if (typeof verified !== 'string') {\n return verified\n }\n } catch (err: unknown) {\n payload.logger.error({\n err,\n msg: 'Error verifying jwt token',\n })\n\n if (err instanceof Error) {\n return err\n }\n return null\n }\n return null\n }\n}\n\ntype JwtVerifyArgs = {\n payload: Payload\n token: string\n}\n"],"names":["jose","APIError","parseCookies","validateProjectToken","getEnvironment","createDebugLogger","getTokenExp","mergeHeaders","refreshTokens","Strategy","clientID","clientSecret","collection","collectionOptions","cookieName","debug","debugLog","identityMetadataURL","jwks","meta","metaLastFetchedTime","metaPromise","metaPromiseResolve","name","pluginOptions","verify","options","identityMetadata","strategyName","args","console","log","ensureMeta","bind","authenticate","canSetHeaders","headers","payload","debugLogger","cookies","oauthToken","get","refreshToken","info","msg","disableJWTFromHeader","jwtFromHeader","startsWith","replace","refreshed","strategy","verifyResult","token","decodedOauthToken","responseHeaders","user","oauthTokenVerifyResult","jwtVerify","Error","refreshTokenExp","exp","usePayloadJWT","Date","now","getTime","fetchMeta","lastError","attempt","fetch","then","res","json","authorization_endpoint","jwks_uri","toISOString","error","message","Promise","resolve","setTimeout","Math","min","undefined","generateOidcPEM","kid","alg","keys","Array","isArray","pubKey","foundKey","key","cryptoKey","importJWK","CryptoKey","exportSPKI","verified","err","logger"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"build-config.d.ts","sourceRoot":"","sources":["../../src/plugin/build-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAWtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;CAC1B,GAAG;IACF,KAAK,EAAE;QACL,eAAe,EAAE,MAAM,CAAA;QACvB,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAC3B,CAAA;CACF,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAC1C,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;AAE7B;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAsEpF"}
1
+ {"version":3,"file":"build-config.d.ts","sourceRoot":"","sources":["../../src/plugin/build-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAUtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;CAC1B,GAAG;IACF,KAAK,EAAE;QACL,eAAe,EAAE,MAAM,CAAA;QACvB,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAC3B,CAAA;CACF,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,QAAQ,CAAC,GAC1C,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;AAE7B;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CA8EpF"}
@@ -1,8 +1,7 @@
1
1
  import { lexicalEditor } from '@payloadcms/richtext-lexical';
2
2
  import { buildConfig as payloadBuildConfig } from 'payload';
3
- import { getValidProjectToken } from '../auth/project-token.js';
4
3
  import { getTokenStore } from '../auth/token-store.js';
5
- import { contentAPIAdapter } from '../db-adapter.js';
4
+ import { contentAPIAdapter } from '../db-content-api/index.js';
6
5
  import { health } from '../endpoints/health.js';
7
6
  import { oAuth2Plugin } from '../oauth/index.js';
8
7
  /**
@@ -19,14 +18,39 @@ import { oAuth2Plugin } from '../oauth/index.js';
19
18
  if (!config.figma.contentSystemId) {
20
19
  throw new Error('FIGMA_CONTENT_SYSTEM_ID is required. ' + 'Ensure your .env file contains: FIGMA_CONTENT_SYSTEM_ID=your-content-system-id');
21
20
  }
22
- const contentSystemId = config.figma.contentSystemId;
23
- let projectToken = '';
24
- if (!process.env.FIGMA_CONTENT_API_ACCESS_KEY) {
25
- const tokenStore = getTokenStore();
26
- const retrievedToken = await getValidProjectToken(tokenStore, contentSystemId);
27
- if (retrievedToken) {
28
- projectToken = retrievedToken;
29
- }
21
+ const DEFAULT_CONTENT_API_URL = 'https://us-east-1.cms-tenants-001-staging.figmacontentstaging.com';
22
+ const url = process.env.FIGMA_CONTENT_API_URL || DEFAULT_CONTENT_API_URL;
23
+ const { contentSystemId } = config.figma;
24
+ // Determine database adapter based on environment
25
+ let db;
26
+ if (config.figma.useContentSystem === false) {
27
+ db = config.db;
28
+ } else if (process.env.FIGMA_CONTENT_API_ACCESS_KEY) {
29
+ db = contentAPIAdapter({
30
+ auth: {
31
+ apiKey: process.env.FIGMA_CONTENT_API_ACCESS_KEY,
32
+ mode: 'apiKey'
33
+ },
34
+ contentSystemId,
35
+ url
36
+ });
37
+ } else if (process.env.FIGMA_DEV_JWT === 'true') {
38
+ db = contentAPIAdapter({
39
+ auth: {
40
+ mode: 'devJwt'
41
+ },
42
+ contentSystemId,
43
+ url
44
+ });
45
+ } else {
46
+ db = contentAPIAdapter({
47
+ auth: {
48
+ mode: 'tokenStore',
49
+ tokenStore: getTokenStore()
50
+ },
51
+ contentSystemId,
52
+ url
53
+ });
30
54
  }
31
55
  // Build complete config with Figma platform defaults
32
56
  const configWithFigmaDefaults = {
@@ -34,13 +58,7 @@ import { oAuth2Plugin } from '../oauth/index.js';
34
58
  custom: {
35
59
  figma: config.figma || {}
36
60
  },
37
- // TODO: - cms-tenants-001-staging needs to be dynamic in the future
38
- db: config.figma.useContentSystem !== false ? contentAPIAdapter({
39
- contentApiKey: process.env.FIGMA_CONTENT_API_ACCESS_KEY,
40
- contentApiUrl: process.env.FIGMA_CONTENT_API_URL || 'https://us-east-1.cms-tenants-001-staging.figmacontentstaging.com',
41
- contentSystemId: config.figma.contentSystemId,
42
- projectToken
43
- }) : config.db,
61
+ db,
44
62
  editor: config.editor ?? lexicalEditor(),
45
63
  endpoints: [
46
64
  ...config.endpoints ?? [],
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/plugin/build-config.ts"],"sourcesContent":["import type { Config, SanitizedConfig } from 'payload'\n\nimport { lexicalEditor } from '@payloadcms/richtext-lexical'\nimport { buildConfig as payloadBuildConfig } from 'payload'\n\nimport { getValidProjectToken } from '../auth/project-token.js'\nimport { getTokenStore } from '../auth/token-store.js'\nimport { contentAPIAdapter } from '../db-adapter.js'\nimport { health } from '../endpoints/health.js'\nimport { oAuth2Plugin } from '../oauth/index.js'\n\n/**\n * Configuration type for Payload projects on the Figma platform.\n *\n * Differences from standard Payload Config:\n * - `db`: Omitted (auto-injected by Figma platform)\n * - `secret`: Omitted (auto-injected by Figma platform)\n * - `editor`: Optional (defaults to lexicalEditor() if not provided)\n *\n * @example\n * // Minimal config\n * const config: FigmaConfig = {\n * figma: {\n * contentSystemId: process.env.FIGMA_CONTENT_SYSTEM_ID!\n * },\n * collections: [...]\n * }\n *\n * @example\n * // With custom editor\n * const config: FigmaConfig = {\n * figma: {\n * contentSystemId: process.env.FIGMA_CONTENT_SYSTEM_ID!\n * },\n * collections: [...],\n * editor: lexicalEditor({ features: [...] })\n * }\n *\n * @example\n * // Disable Content System (use custom db)\n * const config: FigmaConfig = {\n * figma: {\n * contentSystemId: process.env.FIGMA_CONTENT_SYSTEM_ID!,\n * useContentSystem: false\n * },\n * db: mongooseAdapter({ url: process.env.DATABASE_URI }),\n * collections: [...]\n * }\n */\nexport type FigmaConfig = {\n editor?: Config['editor']\n} & {\n figma: {\n contentSystemId: string\n useContentSystem?: boolean\n }\n} & Omit<Config, 'db' | 'editor' | 'secret'> &\n Partial<Pick<Config, 'db'>>\n\n/**\n * Figma platform wrapper for Payload's buildConfig.\n * Automatically injects:\n * - Figma database adapter\n * - Secret (platform-provided)\n * - Default lexicalEditor (if no custom editor specified)\n *\n * @param config - Payload configuration (db and secret omitted, editor optional)\n * @returns Promise<SanitizedConfig> - Built Payload configuration\n */\nexport async function buildFigmaConfig(config: FigmaConfig): Promise<SanitizedConfig> {\n // Validate required environment variable\n if (!config.figma.contentSystemId) {\n throw new Error(\n 'FIGMA_CONTENT_SYSTEM_ID is required. ' +\n 'Ensure your .env file contains: FIGMA_CONTENT_SYSTEM_ID=your-content-system-id',\n )\n }\n\n const contentSystemId = config.figma.contentSystemId\n\n let projectToken = ''\n\n if (!process.env.FIGMA_CONTENT_API_ACCESS_KEY) {\n const tokenStore = getTokenStore()\n const retrievedToken = await getValidProjectToken(tokenStore, contentSystemId)\n if (retrievedToken) {\n projectToken = retrievedToken\n }\n }\n\n // Build complete config with Figma platform defaults\n const configWithFigmaDefaults: Config = {\n ...config,\n custom: {\n figma: config.figma || {},\n },\n // TODO: - cms-tenants-001-staging needs to be dynamic in the future\n db:\n config.figma.useContentSystem !== false\n ? contentAPIAdapter({\n contentApiKey: process.env.FIGMA_CONTENT_API_ACCESS_KEY!,\n contentApiUrl:\n process.env.FIGMA_CONTENT_API_URL ||\n 'https://us-east-1.cms-tenants-001-staging.figmacontentstaging.com',\n contentSystemId: config.figma.contentSystemId,\n projectToken,\n })\n : config.db!,\n editor: config.editor ?? lexicalEditor(),\n endpoints: [...(config.endpoints ?? []), health],\n secret: 'MY_SECRET',\n // Add oauth to plugins if not already present\n plugins: [\n ...(config.plugins ?? []),\n oAuth2Plugin({\n collections: [\n {\n slug: 'users',\n // Use adapter because Figma app doesn't support OIDC scopes\n authorizationURLParams: {\n response_mode: 'query',\n response_type: 'code',\n },\n clientID: process.env.FIGMA_OAUTH_CLIENT_ID!,\n clientSecret: process.env.FIGMA_OAUTH_CLIENT_SECRET,\n identityMetadata: 'https://staging.figma.com/.well-known/openid-configuration',\n scope: ['current_user:read'],\n token: 'id_token', // Adapter creates JWT id_token from Figma user info\n usernameField: 'email',\n },\n ],\n debug: !!process.env.DEBUG,\n disabled: false,\n }),\n ],\n }\n\n // Delegate to Payload's buildConfig\n return await payloadBuildConfig(configWithFigmaDefaults)\n}\n"],"names":["lexicalEditor","buildConfig","payloadBuildConfig","getValidProjectToken","getTokenStore","contentAPIAdapter","health","oAuth2Plugin","buildFigmaConfig","config","figma","contentSystemId","Error","projectToken","process","env","FIGMA_CONTENT_API_ACCESS_KEY","tokenStore","retrievedToken","configWithFigmaDefaults","custom","db","useContentSystem","contentApiKey","contentApiUrl","FIGMA_CONTENT_API_URL","editor","endpoints","secret","plugins","collections","slug","authorizationURLParams","response_mode","response_type","clientID","FIGMA_OAUTH_CLIENT_ID","clientSecret","FIGMA_OAUTH_CLIENT_SECRET","identityMetadata","scope","token","usernameField","debug","DEBUG","disabled"],"mappings":"AAEA,SAASA,aAAa,QAAQ,+BAA8B;AAC5D,SAASC,eAAeC,kBAAkB,QAAQ,UAAS;AAE3D,SAASC,oBAAoB,QAAQ,2BAA0B;AAC/D,SAASC,aAAa,QAAQ,yBAAwB;AACtD,SAASC,iBAAiB,QAAQ,mBAAkB;AACpD,SAASC,MAAM,QAAQ,yBAAwB;AAC/C,SAASC,YAAY,QAAQ,oBAAmB;AAkDhD;;;;;;;;;CASC,GACD,OAAO,eAAeC,iBAAiBC,MAAmB;IACxD,yCAAyC;IACzC,IAAI,CAACA,OAAOC,KAAK,CAACC,eAAe,EAAE;QACjC,MAAM,IAAIC,MACR,0CACE;IAEN;IAEA,MAAMD,kBAAkBF,OAAOC,KAAK,CAACC,eAAe;IAEpD,IAAIE,eAAe;IAEnB,IAAI,CAACC,QAAQC,GAAG,CAACC,4BAA4B,EAAE;QAC7C,MAAMC,aAAab;QACnB,MAAMc,iBAAiB,MAAMf,qBAAqBc,YAAYN;QAC9D,IAAIO,gBAAgB;YAClBL,eAAeK;QACjB;IACF;IAEA,qDAAqD;IACrD,MAAMC,0BAAkC;QACtC,GAAGV,MAAM;QACTW,QAAQ;YACNV,OAAOD,OAAOC,KAAK,IAAI,CAAC;QAC1B;QACA,oEAAoE;QACpEW,IACEZ,OAAOC,KAAK,CAACY,gBAAgB,KAAK,QAC9BjB,kBAAkB;YAChBkB,eAAeT,QAAQC,GAAG,CAACC,4BAA4B;YACvDQ,eACEV,QAAQC,GAAG,CAACU,qBAAqB,IACjC;YACFd,iBAAiBF,OAAOC,KAAK,CAACC,eAAe;YAC7CE;QACF,KACAJ,OAAOY,EAAE;QACfK,QAAQjB,OAAOiB,MAAM,IAAI1B;QACzB2B,WAAW;eAAKlB,OAAOkB,SAAS,IAAI,EAAE;YAAGrB;SAAO;QAChDsB,QAAQ;QACR,8CAA8C;QAC9CC,SAAS;eACHpB,OAAOoB,OAAO,IAAI,EAAE;YACxBtB,aAAa;gBACXuB,aAAa;oBACX;wBACEC,MAAM;wBACN,4DAA4D;wBAC5DC,wBAAwB;4BACtBC,eAAe;4BACfC,eAAe;wBACjB;wBACAC,UAAUrB,QAAQC,GAAG,CAACqB,qBAAqB;wBAC3CC,cAAcvB,QAAQC,GAAG,CAACuB,yBAAyB;wBACnDC,kBAAkB;wBAClBC,OAAO;4BAAC;yBAAoB;wBAC5BC,OAAO;wBACPC,eAAe;oBACjB;iBACD;gBACDC,OAAO,CAAC,CAAC7B,QAAQC,GAAG,CAAC6B,KAAK;gBAC1BC,UAAU;YACZ;SACD;IACH;IAEA,oCAAoC;IACpC,OAAO,MAAM3C,mBAAmBiB;AAClC"}
1
+ {"version":3,"sources":["../../src/plugin/build-config.ts"],"sourcesContent":["import type { Config, SanitizedConfig } from 'payload'\n\nimport { lexicalEditor } from '@payloadcms/richtext-lexical'\nimport { buildConfig as payloadBuildConfig } from 'payload'\n\nimport { getTokenStore } from '../auth/token-store.js'\nimport { contentAPIAdapter } from '../db-content-api/index.js'\nimport { health } from '../endpoints/health.js'\nimport { oAuth2Plugin } from '../oauth/index.js'\n\n/**\n * Configuration type for Payload projects on the Figma platform.\n *\n * Differences from standard Payload Config:\n * - `db`: Omitted (auto-injected by Figma platform)\n * - `secret`: Omitted (auto-injected by Figma platform)\n * - `editor`: Optional (defaults to lexicalEditor() if not provided)\n *\n * @example\n * // Minimal config\n * const config: FigmaConfig = {\n * figma: {\n * contentSystemId: process.env.FIGMA_CONTENT_SYSTEM_ID!\n * },\n * collections: [...]\n * }\n *\n * @example\n * // With custom editor\n * const config: FigmaConfig = {\n * figma: {\n * contentSystemId: process.env.FIGMA_CONTENT_SYSTEM_ID!\n * },\n * collections: [...],\n * editor: lexicalEditor({ features: [...] })\n * }\n *\n * @example\n * // Disable Content System (use custom db)\n * const config: FigmaConfig = {\n * figma: {\n * contentSystemId: process.env.FIGMA_CONTENT_SYSTEM_ID!,\n * useContentSystem: false\n * },\n * db: mongooseAdapter({ url: process.env.DATABASE_URI }),\n * collections: [...]\n * }\n */\nexport type FigmaConfig = {\n editor?: Config['editor']\n} & {\n figma: {\n contentSystemId: string\n useContentSystem?: boolean\n }\n} & Omit<Config, 'db' | 'editor' | 'secret'> &\n Partial<Pick<Config, 'db'>>\n\n/**\n * Figma platform wrapper for Payload's buildConfig.\n * Automatically injects:\n * - Figma database adapter\n * - Secret (platform-provided)\n * - Default lexicalEditor (if no custom editor specified)\n *\n * @param config - Payload configuration (db and secret omitted, editor optional)\n * @returns Promise<SanitizedConfig> - Built Payload configuration\n */\nexport async function buildFigmaConfig(config: FigmaConfig): Promise<SanitizedConfig> {\n // Validate required environment variable\n if (!config.figma.contentSystemId) {\n throw new Error(\n 'FIGMA_CONTENT_SYSTEM_ID is required. ' +\n 'Ensure your .env file contains: FIGMA_CONTENT_SYSTEM_ID=your-content-system-id',\n )\n }\n\n const DEFAULT_CONTENT_API_URL =\n 'https://us-east-1.cms-tenants-001-staging.figmacontentstaging.com'\n\n const url = process.env.FIGMA_CONTENT_API_URL || DEFAULT_CONTENT_API_URL\n const { contentSystemId } = config.figma\n\n // Determine database adapter based on environment\n let db: Config['db']\n\n if (config.figma.useContentSystem === false) {\n db = config.db!\n } else if (process.env.FIGMA_CONTENT_API_ACCESS_KEY) {\n db = contentAPIAdapter({\n auth: { apiKey: process.env.FIGMA_CONTENT_API_ACCESS_KEY, mode: 'apiKey' },\n contentSystemId,\n url,\n })\n } else if (process.env.FIGMA_DEV_JWT === 'true') {\n db = contentAPIAdapter({\n auth: { mode: 'devJwt' },\n contentSystemId,\n url,\n })\n } else {\n db = contentAPIAdapter({\n auth: { mode: 'tokenStore', tokenStore: getTokenStore() },\n contentSystemId,\n url,\n })\n }\n\n // Build complete config with Figma platform defaults\n const configWithFigmaDefaults: Config = {\n ...config,\n custom: {\n figma: config.figma || {},\n },\n db,\n editor: config.editor ?? lexicalEditor(),\n endpoints: [...(config.endpoints ?? []), health],\n secret: 'MY_SECRET',\n // Add oauth to plugins if not already present\n plugins: [\n ...(config.plugins ?? []),\n oAuth2Plugin({\n collections: [\n {\n slug: 'users',\n // Use adapter because Figma app doesn't support OIDC scopes\n authorizationURLParams: {\n response_mode: 'query',\n response_type: 'code',\n },\n clientID: process.env.FIGMA_OAUTH_CLIENT_ID!,\n clientSecret: process.env.FIGMA_OAUTH_CLIENT_SECRET,\n identityMetadata: 'https://staging.figma.com/.well-known/openid-configuration',\n scope: ['current_user:read'],\n token: 'id_token', // Adapter creates JWT id_token from Figma user info\n usernameField: 'email',\n },\n ],\n debug: !!process.env.DEBUG,\n disabled: false,\n }),\n ],\n }\n\n // Delegate to Payload's buildConfig\n return await payloadBuildConfig(configWithFigmaDefaults)\n}\n"],"names":["lexicalEditor","buildConfig","payloadBuildConfig","getTokenStore","contentAPIAdapter","health","oAuth2Plugin","buildFigmaConfig","config","figma","contentSystemId","Error","DEFAULT_CONTENT_API_URL","url","process","env","FIGMA_CONTENT_API_URL","db","useContentSystem","FIGMA_CONTENT_API_ACCESS_KEY","auth","apiKey","mode","FIGMA_DEV_JWT","tokenStore","configWithFigmaDefaults","custom","editor","endpoints","secret","plugins","collections","slug","authorizationURLParams","response_mode","response_type","clientID","FIGMA_OAUTH_CLIENT_ID","clientSecret","FIGMA_OAUTH_CLIENT_SECRET","identityMetadata","scope","token","usernameField","debug","DEBUG","disabled"],"mappings":"AAEA,SAASA,aAAa,QAAQ,+BAA8B;AAC5D,SAASC,eAAeC,kBAAkB,QAAQ,UAAS;AAE3D,SAASC,aAAa,QAAQ,yBAAwB;AACtD,SAASC,iBAAiB,QAAQ,6BAA4B;AAC9D,SAASC,MAAM,QAAQ,yBAAwB;AAC/C,SAASC,YAAY,QAAQ,oBAAmB;AAkDhD;;;;;;;;;CASC,GACD,OAAO,eAAeC,iBAAiBC,MAAmB;IACxD,yCAAyC;IACzC,IAAI,CAACA,OAAOC,KAAK,CAACC,eAAe,EAAE;QACjC,MAAM,IAAIC,MACR,0CACE;IAEN;IAEA,MAAMC,0BACJ;IAEF,MAAMC,MAAMC,QAAQC,GAAG,CAACC,qBAAqB,IAAIJ;IACjD,MAAM,EAAEF,eAAe,EAAE,GAAGF,OAAOC,KAAK;IAExC,kDAAkD;IAClD,IAAIQ;IAEJ,IAAIT,OAAOC,KAAK,CAACS,gBAAgB,KAAK,OAAO;QAC3CD,KAAKT,OAAOS,EAAE;IAChB,OAAO,IAAIH,QAAQC,GAAG,CAACI,4BAA4B,EAAE;QACnDF,KAAKb,kBAAkB;YACrBgB,MAAM;gBAAEC,QAAQP,QAAQC,GAAG,CAACI,4BAA4B;gBAAEG,MAAM;YAAS;YACzEZ;YACAG;QACF;IACF,OAAO,IAAIC,QAAQC,GAAG,CAACQ,aAAa,KAAK,QAAQ;QAC/CN,KAAKb,kBAAkB;YACrBgB,MAAM;gBAAEE,MAAM;YAAS;YACvBZ;YACAG;QACF;IACF,OAAO;QACLI,KAAKb,kBAAkB;YACrBgB,MAAM;gBAAEE,MAAM;gBAAcE,YAAYrB;YAAgB;YACxDO;YACAG;QACF;IACF;IAEA,qDAAqD;IACrD,MAAMY,0BAAkC;QACtC,GAAGjB,MAAM;QACTkB,QAAQ;YACNjB,OAAOD,OAAOC,KAAK,IAAI,CAAC;QAC1B;QACAQ;QACAU,QAAQnB,OAAOmB,MAAM,IAAI3B;QACzB4B,WAAW;eAAKpB,OAAOoB,SAAS,IAAI,EAAE;YAAGvB;SAAO;QAChDwB,QAAQ;QACR,8CAA8C;QAC9CC,SAAS;eACHtB,OAAOsB,OAAO,IAAI,EAAE;YACxBxB,aAAa;gBACXyB,aAAa;oBACX;wBACEC,MAAM;wBACN,4DAA4D;wBAC5DC,wBAAwB;4BACtBC,eAAe;4BACfC,eAAe;wBACjB;wBACAC,UAAUtB,QAAQC,GAAG,CAACsB,qBAAqB;wBAC3CC,cAAcxB,QAAQC,GAAG,CAACwB,yBAAyB;wBACnDC,kBAAkB;wBAClBC,OAAO;4BAAC;yBAAoB;wBAC5BC,OAAO;wBACPC,eAAe;oBACjB;iBACD;gBACDC,OAAO,CAAC,CAAC9B,QAAQC,GAAG,CAAC8B,KAAK;gBAC1BC,UAAU;YACZ;SACD;IACH;IAEA,oCAAoC;IACpC,OAAO,MAAM5C,mBAAmBuB;AAClC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/figma",
3
- "version": "0.0.1-alpha.26",
3
+ "version": "0.0.1-alpha.27",
4
4
  "license": "SEE LICENSE IN LICENSE.md",
5
5
  "type": "module",
6
6
  "exports": {
@@ -43,6 +43,7 @@
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "22.12.0",
46
+ "openapi-typescript": "^7.10.1",
46
47
  "tsx": "4.20.6",
47
48
  "typescript": "5.9.3",
48
49
  "vitest": "3.2.4"
@@ -72,6 +73,7 @@
72
73
  "debug:refresh-token": "tsx scripts/refresh-token.ts",
73
74
  "debug:tokens": "tsx scripts/debug-tokens.ts",
74
75
  "debug:write-token": "tsx scripts/write-token.ts",
76
+ "generate:types": "tsx scripts/generate-types.ts",
75
77
  "lint": "eslint .",
76
78
  "lint:fix": "eslint . --fix",
77
79
  "start": "pnpm build && node ./bin/cli.js",