@payloadcms/figma 0.0.1-alpha.33 → 0.0.1-alpha.35
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.
- package/dist/auth/oauth-flow.d.ts.map +1 -1
- package/dist/auth/oauth-flow.js +6 -5
- package/dist/auth/oauth-flow.js.map +1 -1
- package/dist/auth/refresh.d.ts.map +1 -1
- package/dist/auth/refresh.js +14 -9
- package/dist/auth/refresh.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +19 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/build-lambda-zip.d.ts +5 -0
- package/dist/commands/build-lambda-zip.d.ts.map +1 -0
- package/dist/commands/build-lambda-zip.js +19 -0
- package/dist/commands/build-lambda-zip.js.map +1 -0
- package/dist/commands/deploy.js +3 -3
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/init.js +2 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list-tokens.d.ts.map +1 -1
- package/dist/commands/list-tokens.js +3 -1
- package/dist/commands/list-tokens.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +8 -5
- package/dist/commands/login.js.map +1 -1
- package/dist/config/oauth.d.ts +3 -17
- package/dist/config/oauth.d.ts.map +1 -1
- package/dist/config/oauth.js +18 -34
- package/dist/config/oauth.js.map +1 -1
- package/dist/constants.d.ts +7 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +13 -5
- package/dist/constants.js.map +1 -1
- package/dist/db-content-api/README.md +0 -10
- package/dist/db-content-api/generated/content-api-types.d.ts +171 -25
- package/dist/db-content-api/generated/content-api-types.d.ts.map +1 -1
- package/dist/db-content-api/generated/content-api-types.js.map +1 -1
- package/dist/db-content-api/index.d.ts.map +1 -1
- package/dist/db-content-api/index.js +7 -8
- package/dist/db-content-api/index.js.map +1 -1
- package/dist/db-content-api/temp-utilities/sorting.d.ts +2 -6
- package/dist/db-content-api/temp-utilities/sorting.d.ts.map +1 -1
- package/dist/db-content-api/temp-utilities/sorting.js +2 -41
- package/dist/db-content-api/temp-utilities/sorting.js.map +1 -1
- package/dist/db-content-api/utilities/data/index.d.ts +2 -0
- package/dist/db-content-api/utilities/data/index.d.ts.map +1 -1
- package/dist/db-content-api/utilities/data/index.js +7 -0
- package/dist/db-content-api/utilities/data/index.js.map +1 -1
- package/dist/db-content-api/utilities/data/removeVirtualFields.d.ts +12 -0
- package/dist/db-content-api/utilities/data/removeVirtualFields.d.ts.map +1 -0
- package/dist/db-content-api/utilities/data/removeVirtualFields.js +54 -0
- package/dist/db-content-api/utilities/data/removeVirtualFields.js.map +1 -0
- package/dist/db-content-api/utilities/joins.d.ts +4 -4
- package/dist/db-content-api/utilities/joins.d.ts.map +1 -1
- package/dist/db-content-api/utilities/joins.js +12 -6
- package/dist/db-content-api/utilities/joins.js.map +1 -1
- package/dist/oauth/strategy/index.d.ts.map +1 -1
- package/dist/oauth/strategy/index.js +33 -12
- package/dist/oauth/strategy/index.js.map +1 -1
- package/dist/plugin/build-config.d.ts.map +1 -1
- package/dist/plugin/build-config.js +7 -0
- package/dist/plugin/build-config.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/asset-collection.d.ts +3 -6
- package/dist/utils/asset-collection.d.ts.map +1 -1
- package/dist/utils/asset-collection.js +10 -34
- package/dist/utils/asset-collection.js.map +1 -1
- package/dist/utils/build-lambda-zip.d.ts +14 -0
- package/dist/utils/build-lambda-zip.d.ts.map +1 -0
- package/dist/utils/build-lambda-zip.js +81 -0
- package/dist/utils/build-lambda-zip.js.map +1 -0
- package/dist/utils/config.js +1 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/env-management.js +2 -2
- package/dist/utils/env-management.js.map +1 -1
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +7 -3
- package/dist/utils/formatter.js.map +1 -1
- package/dist/utils/lambda-config.d.ts +3 -1
- package/dist/utils/lambda-config.d.ts.map +1 -1
- package/dist/utils/lambda-config.js +13 -22
- package/dist/utils/lambda-config.js.map +1 -1
- package/dist/utils/messages.d.ts.map +1 -1
- package/dist/utils/messages.js +2 -0
- package/dist/utils/messages.js.map +1 -1
- package/dist/utils/payload-config-modifier.d.ts.map +1 -1
- package/dist/utils/payload-config-modifier.js +7 -4
- package/dist/utils/payload-config-modifier.js.map +1 -1
- package/dist/utils/payload-package-check.d.ts +7 -1
- package/dist/utils/payload-package-check.d.ts.map +1 -1
- package/dist/utils/payload-package-check.js +29 -15
- package/dist/utils/payload-package-check.js.map +1 -1
- package/dist/utils/project.d.ts.map +1 -1
- package/dist/utils/project.js +4 -3
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/typescript-validator.d.ts.map +1 -1
- package/dist/utils/typescript-validator.js +7 -4
- package/dist/utils/typescript-validator.js.map +1 -1
- package/package.json +18 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/db-content-api/utilities/joins.ts"],"sourcesContent":["import type { JoinQuery, Payload
|
|
1
|
+
{"version":3,"sources":["../../../src/db-content-api/utilities/joins.ts"],"sourcesContent":["import type { JoinQuery, Payload } from 'payload'\n\nimport type { components } from '../generated/content-api-types.js'\n\nimport { addFallbackSort } from '../temp-utilities/sorting.js'\nimport { convertPayloadWhereToContentAPI } from './where.js'\n\n// JoinClause is an array type, so we extract the element type\ntype ContentAPIJoin = components['schemas']['JoinClause'][number]\n\n/**\n * Convert Payload's JoinQuery to Content API's join format.\n *\n * ## Content API Join Limitations\n *\n * The following Payload join features are NOT YET supported by Content API:\n *\n * 1. **hasMany relationships** - Content API's join uses `data#>'{path}'#>>'{}'` to extract\n * a single ID. HasMany relationships store arrays `[\"id1\", \"id2\"]` which can't match.\n *\n * 2. **Array field relationships** - `on: 'array.category'` expects iteration over array\n * elements, but Content API treats the path as a single JSONB extraction.\n *\n * 3. **Polymorphic relationships** - Stored as `{ relationTo, value }` objects, but\n * Content API expects a simple ID string.\n *\n * 4. **Localized relationship fields** - Locale-aware joins not implemented.\n *\n * Note: \"Where querying through joins\" (e.g., `where: { 'relatedPosts.title': { equals: 'x' } }`)\n * is a separate Payload feature that filters documents based on joined data. This is NOT\n * a join feature but a where clause feature, and would need separate Content API support.\n *\n * Payload's JoinQuery format (at runtime):\n * {\n * 'group.relatedPosts': { // joinPath - where results go in the document\n * sort: '-title',\n * limit: 10,\n * page: 2, // page-based pagination\n * where: { ... }, // Payload where format\n * count: true\n * }\n * }\n *\n * Content API's join format:\n * [{\n * collectionId: 'posts', // collection to join FROM\n * on: 'group.category', // field in joined collection pointing to this doc\n * path: 'group.relatedPosts', // where to put results\n * count: false,\n * where: { ... }, // Content API where format\n * sort: '-title',\n * limit: 10,\n * offset: 10 // offset-based pagination\n * }]\n *\n * The mapping requires the collection config to resolve:\n * - Which collection each join field refers to\n * - What the 'on' field is for each join\n */\nexport function convertPayloadJoinsToContentAPI(\n payload: Payload,\n collectionSlug: string,\n joins: false | JoinQuery | undefined,\n): ContentAPIJoin[] | undefined {\n const collectionConfig = payload.config.collections.find((c) => c.slug === collectionSlug)\n if (!collectionConfig) {\n return undefined\n }\n // joins === false means explicitly disable all joins\n // joins === undefined means use defaults (no custom query params)\n if (joins === false || !joins) {\n return undefined\n }\n\n const result: ContentAPIJoin[] = []\n\n // Iterate through all join paths in the query\n for (const [joinPath, joinQueryValue] of Object.entries(joins)) {\n // joinQuery === false means skip this specific join\n if (joinQueryValue === false) {\n continue\n }\n\n // Normalize undefined/empty to empty object\n const joinQuery = joinQueryValue ?? {}\n\n // Find the SanitizedJoin config for this joinPath\n // SanitizedJoins is indexed by the collection being joined FROM\n let foundJoin: { collectionSlug: string; on: string } | undefined\n\n // Search through all collections in the joins config\n for (const [collectionSlug, sanitizedJoins] of Object.entries(collectionConfig.joins)) {\n for (const sanitizedJoin of sanitizedJoins) {\n if (sanitizedJoin.joinPath === joinPath) {\n foundJoin = {\n collectionSlug,\n on: sanitizedJoin.field.on,\n }\n break\n }\n }\n if (foundJoin) {\n break\n }\n }\n\n // Also check polymorphic joins\n if (!foundJoin) {\n for (const sanitizedJoin of collectionConfig.polymorphicJoins) {\n if (sanitizedJoin.joinPath === joinPath) {\n // For polymorphic joins, collection is an array - use first one\n const collections = sanitizedJoin.field.collection\n foundJoin = {\n collectionSlug: Array.isArray(collections) ? collections[0] : collections,\n on: sanitizedJoin.field.on,\n }\n break\n }\n }\n }\n\n if (!foundJoin) {\n payload.logger.warn(\n `Join path '${joinPath}' not found in collection config for '${collectionConfig.slug}'`,\n )\n continue\n }\n\n // Convert pagination: Payload uses page, Content API JoinClause uses offset\n let offset: number | undefined\n if (joinQuery.page && joinQuery.page > 1 && joinQuery.limit) {\n offset = (joinQuery.page - 1) * joinQuery.limit\n }\n\n // Add fallback sort for the joined collection\n const sortWithFallback = addFallbackSort(joinQuery.sort, payload, foundJoin.collectionSlug)\n\n const contentAPIJoin: ContentAPIJoin = {\n collectionId: foundJoin.collectionSlug,\n count: joinQuery.count ?? false,\n on: foundJoin.on,\n path: joinPath,\n ...(joinQuery.limit !== undefined && { limit: joinQuery.limit }),\n ...(offset !== undefined && { offset }),\n ...(sortWithFallback && { sort: sortWithFallback }),\n ...(joinQuery.where && { where: convertPayloadWhereToContentAPI(joinQuery.where) }),\n }\n\n result.push(contentAPIJoin)\n }\n\n return result.length > 0 ? result : undefined\n}\n"],"names":["addFallbackSort","convertPayloadWhereToContentAPI","convertPayloadJoinsToContentAPI","payload","collectionSlug","joins","collectionConfig","config","collections","find","c","slug","undefined","result","joinPath","joinQueryValue","Object","entries","joinQuery","foundJoin","sanitizedJoins","sanitizedJoin","on","field","polymorphicJoins","collection","Array","isArray","logger","warn","offset","page","limit","sortWithFallback","sort","contentAPIJoin","collectionId","count","path","where","push","length"],"mappings":"AAIA,SAASA,eAAe,QAAQ,+BAA8B;AAC9D,SAASC,+BAA+B,QAAQ,aAAY;AAK5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDC,GACD,OAAO,SAASC,gCACdC,OAAgB,EAChBC,cAAsB,EACtBC,KAAoC;IAEpC,MAAMC,mBAAmBH,QAAQI,MAAM,CAACC,WAAW,CAACC,IAAI,CAAC,CAACC,IAAMA,EAAEC,IAAI,KAAKP;IAC3E,IAAI,CAACE,kBAAkB;QACrB,OAAOM;IACT;IACA,qDAAqD;IACrD,kEAAkE;IAClE,IAAIP,UAAU,SAAS,CAACA,OAAO;QAC7B,OAAOO;IACT;IAEA,MAAMC,SAA2B,EAAE;IAEnC,8CAA8C;IAC9C,KAAK,MAAM,CAACC,UAAUC,eAAe,IAAIC,OAAOC,OAAO,CAACZ,OAAQ;QAC9D,oDAAoD;QACpD,IAAIU,mBAAmB,OAAO;YAC5B;QACF;QAEA,4CAA4C;QAC5C,MAAMG,YAAYH,kBAAkB,CAAC;QAErC,kDAAkD;QAClD,gEAAgE;QAChE,IAAII;QAEJ,qDAAqD;QACrD,KAAK,MAAM,CAACf,gBAAgBgB,eAAe,IAAIJ,OAAOC,OAAO,CAACX,iBAAiBD,KAAK,EAAG;YACrF,KAAK,MAAMgB,iBAAiBD,eAAgB;gBAC1C,IAAIC,cAAcP,QAAQ,KAAKA,UAAU;oBACvCK,YAAY;wBACVf;wBACAkB,IAAID,cAAcE,KAAK,CAACD,EAAE;oBAC5B;oBACA;gBACF;YACF;YACA,IAAIH,WAAW;gBACb;YACF;QACF;QAEA,+BAA+B;QAC/B,IAAI,CAACA,WAAW;YACd,KAAK,MAAME,iBAAiBf,iBAAiBkB,gBAAgB,CAAE;gBAC7D,IAAIH,cAAcP,QAAQ,KAAKA,UAAU;oBACvC,gEAAgE;oBAChE,MAAMN,cAAca,cAAcE,KAAK,CAACE,UAAU;oBAClDN,YAAY;wBACVf,gBAAgBsB,MAAMC,OAAO,CAACnB,eAAeA,WAAW,CAAC,EAAE,GAAGA;wBAC9Dc,IAAID,cAAcE,KAAK,CAACD,EAAE;oBAC5B;oBACA;gBACF;YACF;QACF;QAEA,IAAI,CAACH,WAAW;YACdhB,QAAQyB,MAAM,CAACC,IAAI,CACjB,CAAC,WAAW,EAAEf,SAAS,sCAAsC,EAAER,iBAAiBK,IAAI,CAAC,CAAC,CAAC;YAEzF;QACF;QAEA,4EAA4E;QAC5E,IAAImB;QACJ,IAAIZ,UAAUa,IAAI,IAAIb,UAAUa,IAAI,GAAG,KAAKb,UAAUc,KAAK,EAAE;YAC3DF,SAAS,AAACZ,CAAAA,UAAUa,IAAI,GAAG,CAAA,IAAKb,UAAUc,KAAK;QACjD;QAEA,8CAA8C;QAC9C,MAAMC,mBAAmBjC,gBAAgBkB,UAAUgB,IAAI,EAAE/B,SAASgB,UAAUf,cAAc;QAE1F,MAAM+B,iBAAiC;YACrCC,cAAcjB,UAAUf,cAAc;YACtCiC,OAAOnB,UAAUmB,KAAK,IAAI;YAC1Bf,IAAIH,UAAUG,EAAE;YAChBgB,MAAMxB;YACN,GAAII,UAAUc,KAAK,KAAKpB,aAAa;gBAAEoB,OAAOd,UAAUc,KAAK;YAAC,CAAC;YAC/D,GAAIF,WAAWlB,aAAa;gBAAEkB;YAAO,CAAC;YACtC,GAAIG,oBAAoB;gBAAEC,MAAMD;YAAiB,CAAC;YAClD,GAAIf,UAAUqB,KAAK,IAAI;gBAAEA,OAAOtC,gCAAgCiB,UAAUqB,KAAK;YAAE,CAAC;QACpF;QAEA1B,OAAO2B,IAAI,CAACL;IACd;IAEA,OAAOtB,OAAO4B,MAAM,GAAG,IAAI5B,SAASD;AACtC"}
|
|
@@ -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;
|
|
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;IA8KnD,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"}
|
|
@@ -63,7 +63,11 @@ export class Strategy {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
if (!oauthToken) {
|
|
66
|
-
|
|
66
|
+
// Attempt refresh even when canSetHeaders=false (e.g., during RSC navigation).
|
|
67
|
+
// This allows authentication to succeed for the current request even when
|
|
68
|
+
// cookies cannot be updated. The cookie will be refreshed on the next
|
|
69
|
+
// full page load when canSetHeaders=true.
|
|
70
|
+
if (refreshToken) {
|
|
67
71
|
debugLogger.info({
|
|
68
72
|
msg: 'No access token found, but refresh token exists. Attempting to refresh...',
|
|
69
73
|
refreshToken
|
|
@@ -83,11 +87,20 @@ export class Strategy {
|
|
|
83
87
|
msg: 'Token refreshed. Verifying...',
|
|
84
88
|
verifyResult
|
|
85
89
|
});
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
// Only return response headers (to set cookies) when canSetHeaders is true.
|
|
91
|
+
// During RSC navigation, canSetHeaders=false because response streaming
|
|
92
|
+
// has already started and cookies cannot be modified.
|
|
93
|
+
if (canSetHeaders) {
|
|
94
|
+
if (verifyResult.responseHeaders) {
|
|
95
|
+
mergeHeaders(verifyResult.responseHeaders, refreshed.headers);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
responseHeaders: refreshed.headers,
|
|
99
|
+
user: verifyResult.user
|
|
100
|
+
};
|
|
88
101
|
}
|
|
102
|
+
// Authenticate this request without updating cookies
|
|
89
103
|
return {
|
|
90
|
-
responseHeaders: refreshed.headers,
|
|
91
104
|
user: verifyResult.user
|
|
92
105
|
};
|
|
93
106
|
} else {
|
|
@@ -97,11 +110,10 @@ export class Strategy {
|
|
|
97
110
|
refreshToken
|
|
98
111
|
});
|
|
99
112
|
}
|
|
100
|
-
} else {
|
|
101
|
-
return {
|
|
102
|
-
user: null
|
|
103
|
-
};
|
|
104
113
|
}
|
|
114
|
+
return {
|
|
115
|
+
user: null
|
|
116
|
+
};
|
|
105
117
|
}
|
|
106
118
|
let oauthTokenVerifyResult = null;
|
|
107
119
|
// First, try to verify token
|
|
@@ -136,7 +148,10 @@ export class Strategy {
|
|
|
136
148
|
});
|
|
137
149
|
}
|
|
138
150
|
}
|
|
139
|
-
|
|
151
|
+
// Handle expired access token with valid refresh token.
|
|
152
|
+
// Same pattern as above: refresh regardless of canSetHeaders to support RSC navigation,
|
|
153
|
+
// but only update cookies when canSetHeaders=true.
|
|
154
|
+
if (oauthTokenVerifyResult instanceof JWTValidationError && oauthTokenVerifyResult.code === 'EXPIRED' && refreshToken && !this.collectionOptions.usePayloadJWT) {
|
|
140
155
|
const refreshed = await refreshTokens({
|
|
141
156
|
payload,
|
|
142
157
|
refreshToken,
|
|
@@ -157,11 +172,17 @@ export class Strategy {
|
|
|
157
172
|
msg: 'Token refreshed. Verifying...',
|
|
158
173
|
verifyResult
|
|
159
174
|
});
|
|
160
|
-
if (
|
|
161
|
-
|
|
175
|
+
if (canSetHeaders) {
|
|
176
|
+
if (verifyResult.responseHeaders) {
|
|
177
|
+
mergeHeaders(verifyResult.responseHeaders, refreshed.headers);
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
responseHeaders: refreshed.headers,
|
|
181
|
+
user: verifyResult.user
|
|
182
|
+
};
|
|
162
183
|
}
|
|
184
|
+
// Authenticate this request without updating cookies
|
|
163
185
|
return {
|
|
164
|
-
responseHeaders: refreshed.headers,
|
|
165
186
|
user: verifyResult.user
|
|
166
187
|
};
|
|
167
188
|
} else {
|
|
@@ -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 { JWTValidationError, 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 JWTValidationError &&\n oauthTokenVerifyResult.code === 'EXPIRED' &&\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","JWTValidationError","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","code","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
|
+
{"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 { JWTValidationError, 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 // Attempt refresh even when canSetHeaders=false (e.g., during RSC navigation).\n // This allows authentication to succeed for the current request even when\n // cookies cannot be updated. The cookie will be refreshed on the next\n // full page load when canSetHeaders=true.\n if (refreshToken) {\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 // Only return response headers (to set cookies) when canSetHeaders is true.\n // During RSC navigation, canSetHeaders=false because response streaming\n // has already started and cookies cannot be modified.\n if (canSetHeaders) {\n if (verifyResult.responseHeaders) {\n mergeHeaders(verifyResult.responseHeaders, refreshed.headers)\n }\n return {\n responseHeaders: refreshed.headers,\n user: verifyResult.user,\n }\n }\n\n // Authenticate this request without updating cookies\n return {\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 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 // Handle expired access token with valid refresh token.\n // Same pattern as above: refresh regardless of canSetHeaders to support RSC navigation,\n // but only update cookies when canSetHeaders=true.\n if (\n oauthTokenVerifyResult instanceof JWTValidationError &&\n oauthTokenVerifyResult.code === 'EXPIRED' &&\n refreshToken &&\n !this.collectionOptions.usePayloadJWT\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 (canSetHeaders) {\n if (verifyResult.responseHeaders) {\n mergeHeaders(verifyResult.responseHeaders, refreshed.headers)\n }\n return {\n responseHeaders: refreshed.headers,\n user: verifyResult.user,\n }\n }\n\n // Authenticate this request without updating cookies\n return {\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","JWTValidationError","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","code","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;AAiBtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,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,
|
|
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;AAiBtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,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,CAgIpF"}
|
|
@@ -104,6 +104,13 @@ import { contentApiStorageAdapter } from '../storage-content-api/index.js';
|
|
|
104
104
|
// Build complete config with Figma platform defaults
|
|
105
105
|
const configWithFigmaDefaults = {
|
|
106
106
|
...config,
|
|
107
|
+
admin: {
|
|
108
|
+
// Auto-refresh tokens before expiry to prevent unexpected logouts.
|
|
109
|
+
// The project token (access token) expires in ~15 minutes, so the client
|
|
110
|
+
// will automatically refresh at ~14 minutes to keep the session alive.
|
|
111
|
+
autoRefresh: true,
|
|
112
|
+
...config.admin
|
|
113
|
+
},
|
|
107
114
|
custom: {
|
|
108
115
|
figma: config.figma || {}
|
|
109
116
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugin/build-config.ts"],"sourcesContent":["import type { Config, SanitizedConfig } from 'payload'\n\nimport { cloudStoragePlugin } from '@payloadcms/plugin-cloud-storage'\nimport { initClientUploads } from '@payloadcms/plugin-cloud-storage/utilities'\nimport { lexicalEditor } from '@payloadcms/richtext-lexical'\nimport { buildConfig as payloadBuildConfig } from 'payload'\n\nimport type { StorageClientConfig } from '../storage-content-api/index.js'\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'\nimport { createStorageClient } from '../storage-content-api/client.js'\nimport { getGenerateSignedURLHandler } from '../storage-content-api/client-uploads/generateSignedURL.js'\nimport { contentApiStorageAdapter } from '../storage-content-api/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 storage?: boolean\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 storage plugin if there are upload collections and storage is not disabled\n const uploadCollections = (config.collections || []).filter((c) => c.upload)\n let storagePlugin: ReturnType<typeof cloudStoragePlugin> | undefined\n\n if (uploadCollections.length > 0 && config.figma.storage !== false) {\n const storageConfig: StorageClientConfig = process.env.FIGMA_CONTENT_API_ACCESS_KEY\n ? { baseUrl: url, contentApiKey: process.env.FIGMA_CONTENT_API_ACCESS_KEY }\n : process.env.FIGMA_DEV_JWT === 'true'\n ? {\n auth: { mode: 'devJwt' },\n baseUrl: url,\n contentSystemId,\n }\n : {\n auth: { mode: 'tokenStore', tokenStore: getTokenStore() },\n baseUrl: url,\n contentSystemId,\n }\n\n const adapter = contentApiStorageAdapter(storageConfig)\n const storageClient = createStorageClient(storageConfig)\n\n const collectionsMap = uploadCollections.reduce(\n (acc, c) => {\n acc[c.slug] = { adapter, disableLocalStorage: true }\n return acc\n },\n {} as Record<string, { adapter: typeof adapter; disableLocalStorage: boolean }>,\n )\n\n initClientUploads({\n clientHandler: '@payloadcms/figma/client#ContentApiClientUploadHandler',\n collections: collectionsMap,\n config: config as unknown as Config,\n enabled: true,\n serverHandler: getGenerateSignedURLHandler({ client: storageClient }),\n serverHandlerPath: '/content-api-storage-signed-url',\n })\n\n storagePlugin = cloudStoragePlugin({ collections: collectionsMap })\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 ...(storagePlugin ? [storagePlugin] : []),\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":["cloudStoragePlugin","initClientUploads","lexicalEditor","buildConfig","payloadBuildConfig","getTokenStore","contentAPIAdapter","health","oAuth2Plugin","createStorageClient","getGenerateSignedURLHandler","contentApiStorageAdapter","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","uploadCollections","collections","filter","c","upload","storagePlugin","length","storage","storageConfig","baseUrl","contentApiKey","adapter","storageClient","collectionsMap","reduce","acc","slug","disableLocalStorage","clientHandler","enabled","serverHandler","client","serverHandlerPath","configWithFigmaDefaults","custom","editor","endpoints","secret","plugins","authorizationURLParams","response_mode","response_type","clientID","FIGMA_OAUTH_CLIENT_ID","clientSecret","FIGMA_OAUTH_CLIENT_SECRET","identityMetadata","scope","token","usernameField","debug","DEBUG","disabled"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/plugin/build-config.ts"],"sourcesContent":["import type { Config, SanitizedConfig } from 'payload'\n\nimport { cloudStoragePlugin } from '@payloadcms/plugin-cloud-storage'\nimport { initClientUploads } from '@payloadcms/plugin-cloud-storage/utilities'\nimport { lexicalEditor } from '@payloadcms/richtext-lexical'\nimport { buildConfig as payloadBuildConfig } from 'payload'\n\nimport type { StorageClientConfig } from '../storage-content-api/index.js'\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'\nimport { createStorageClient } from '../storage-content-api/client.js'\nimport { getGenerateSignedURLHandler } from '../storage-content-api/client-uploads/generateSignedURL.js'\nimport { contentApiStorageAdapter } from '../storage-content-api/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 storage?: boolean\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 storage plugin if there are upload collections and storage is not disabled\n const uploadCollections = (config.collections || []).filter((c) => c.upload)\n let storagePlugin: ReturnType<typeof cloudStoragePlugin> | undefined\n\n if (uploadCollections.length > 0 && config.figma.storage !== false) {\n const storageConfig: StorageClientConfig = process.env.FIGMA_CONTENT_API_ACCESS_KEY\n ? { baseUrl: url, contentApiKey: process.env.FIGMA_CONTENT_API_ACCESS_KEY }\n : process.env.FIGMA_DEV_JWT === 'true'\n ? {\n auth: { mode: 'devJwt' },\n baseUrl: url,\n contentSystemId,\n }\n : {\n auth: { mode: 'tokenStore', tokenStore: getTokenStore() },\n baseUrl: url,\n contentSystemId,\n }\n\n const adapter = contentApiStorageAdapter(storageConfig)\n const storageClient = createStorageClient(storageConfig)\n\n const collectionsMap = uploadCollections.reduce(\n (acc, c) => {\n acc[c.slug] = { adapter, disableLocalStorage: true }\n return acc\n },\n {} as Record<string, { adapter: typeof adapter; disableLocalStorage: boolean }>,\n )\n\n initClientUploads({\n clientHandler: '@payloadcms/figma/client#ContentApiClientUploadHandler',\n collections: collectionsMap,\n config: config as unknown as Config,\n enabled: true,\n serverHandler: getGenerateSignedURLHandler({ client: storageClient }),\n serverHandlerPath: '/content-api-storage-signed-url',\n })\n\n storagePlugin = cloudStoragePlugin({ collections: collectionsMap })\n }\n\n // Build complete config with Figma platform defaults\n const configWithFigmaDefaults: Config = {\n ...config,\n admin: {\n // Auto-refresh tokens before expiry to prevent unexpected logouts.\n // The project token (access token) expires in ~15 minutes, so the client\n // will automatically refresh at ~14 minutes to keep the session alive.\n autoRefresh: true,\n ...config.admin,\n },\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 ...(storagePlugin ? [storagePlugin] : []),\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":["cloudStoragePlugin","initClientUploads","lexicalEditor","buildConfig","payloadBuildConfig","getTokenStore","contentAPIAdapter","health","oAuth2Plugin","createStorageClient","getGenerateSignedURLHandler","contentApiStorageAdapter","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","uploadCollections","collections","filter","c","upload","storagePlugin","length","storage","storageConfig","baseUrl","contentApiKey","adapter","storageClient","collectionsMap","reduce","acc","slug","disableLocalStorage","clientHandler","enabled","serverHandler","client","serverHandlerPath","configWithFigmaDefaults","admin","autoRefresh","custom","editor","endpoints","secret","plugins","authorizationURLParams","response_mode","response_type","clientID","FIGMA_OAUTH_CLIENT_ID","clientSecret","FIGMA_OAUTH_CLIENT_SECRET","identityMetadata","scope","token","usernameField","debug","DEBUG","disabled"],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,KAAK,CAAA;AAE1B,MAAM,WAAW,IAAK,SAAQ,GAAG,CAAC,IAAI;IACpC,SAAS,EAAE,kBAAkB,CAAA;IAC7B,SAAS,EAAE,kBAAkB,CAAA;IAC7B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,UAAU,EAAE,kBAAkB,CAAA;IAC9B,OAAO,EAAE,kBAAkB,CAAA;IAI3B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AAEtC,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,cAAc,CAAA;AAE1D,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED;;;GAGG;AACH,MAAM,WAAW,WAAY,SAAQ,QAAQ;IAC3C,IAAI,EAAE,SAAS,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;GAGG;AACH,MAAM,WAAW,cAAe,SAAQ,QAAQ;IAC9C,IAAI,EAAE,QAAQ,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,UAAU,QAAQ;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,CAAA;CAC9B;AAED,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;AAE5D,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,iBAAiB,CAAA;AAExF,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,CAAA;AAE5C,MAAM,MAAM,cAAc,GAAG;IAC3B,iBAAiB,EAAE,OAAO,CAAA;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,QAAQ,EAAE,OAAO,CAAA;IACjB,sBAAsB,EAAE,OAAO,CAAA;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,WAAW,EAAE,IAAI,GAAG,MAAM,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,CAAA;AAEjD,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,WAAW,GAAG,mBAAmB,CAAA"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,KAAK,CAAA;AAE1B,MAAM,WAAW,IAAK,SAAQ,GAAG,CAAC,IAAI;IACpC,SAAS,EAAE,kBAAkB,CAAA;IAC7B,OAAO,EAAE,iBAAiB,CAAA;IAC1B,SAAS,EAAE,kBAAkB,CAAA;IAC7B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,UAAU,EAAE,kBAAkB,CAAA;IAC9B,OAAO,EAAE,kBAAkB,CAAA;IAI3B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AAEtC,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,cAAc,CAAA;AAE1D,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED;;;GAGG;AACH,MAAM,WAAW,WAAY,SAAQ,QAAQ;IAC3C,IAAI,EAAE,SAAS,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;GAGG;AACH,MAAM,WAAW,cAAe,SAAQ,QAAQ;IAC9C,IAAI,EAAE,QAAQ,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,UAAU,QAAQ;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,CAAA;CAC9B;AAED,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;AAE5D,MAAM,MAAM,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,iBAAiB,CAAA;AAExF,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,CAAA;AAE5C,MAAM,MAAM,cAAc,GAAG;IAC3B,iBAAiB,EAAE,OAAO,CAAA;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,QAAQ,EAAE,OAAO,CAAA;IACjB,sBAAsB,EAAE,OAAO,CAAA;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,WAAW,EAAE,IAAI,GAAG,MAAM,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,CAAA;AAEjD,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,WAAW,GAAG,mBAAmB,CAAA"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type arg from 'arg'\n\nexport interface Args extends arg.Spec {\n '--debug': BooleanConstructor\n '--force': BooleanConstructor\n '--help': BooleanConstructor\n '--list': BooleanConstructor\n '--logout': BooleanConstructor\n '--yes': BooleanConstructor\n\n // Aliases\n\n '-f': string\n '-h': string\n '-y': string\n}\n\nexport type CliArgs = arg.Result<Args>\n\nexport type ProjectTemplate = GitTemplate | PluginTemplate\n\nexport type ProjectExample = {\n name: string\n url: string\n}\n\n/**\n * Template that is cloned verbatim from a git repo\n * Performs .env manipulation based upon input\n */\nexport interface GitTemplate extends Template {\n type: 'starter'\n url: string\n}\n\n/**\n * Type specifically for the plugin template\n * No .env manipulation is done\n */\nexport interface PluginTemplate extends Template {\n type: 'plugin'\n url: string\n}\n\ninterface Template {\n description?: string\n name: string\n type: ProjectTemplate['type']\n}\n\nexport type PackageManager = 'bun' | 'npm' | 'pnpm' | 'yarn'\n\nexport type DbType = 'd1-sqlite' | 'mongodb' | 'postgres' | 'sqlite' | 'vercel-postgres'\n\nexport type DbDetails = {\n dbUri?: string\n type: DbType\n}\n\nexport type EditorType = 'lexical' | 'slate'\n\nexport type NextAppDetails = {\n hasTopLevelLayout: boolean\n isPayloadInstalled?: boolean\n isSrcDir: boolean\n isSupportedNextVersion: boolean\n nextAppDir?: string\n nextConfigPath?: string\n nextConfigType?: NextConfigType\n nextVersion: null | string\n}\n\nexport type NextConfigType = 'cjs' | 'esm' | 'ts'\n\nexport type StorageAdapterType = 'localDisk' | 'r2Storage' | 'vercelBlobStorage'\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type arg from 'arg'\n\nexport interface Args extends arg.Spec {\n '--debug': BooleanConstructor\n '--env': StringConstructor\n '--force': BooleanConstructor\n '--help': BooleanConstructor\n '--list': BooleanConstructor\n '--logout': BooleanConstructor\n '--yes': BooleanConstructor\n\n // Aliases\n\n '-f': string\n '-h': string\n '-y': string\n}\n\nexport type CliArgs = arg.Result<Args>\n\nexport type ProjectTemplate = GitTemplate | PluginTemplate\n\nexport type ProjectExample = {\n name: string\n url: string\n}\n\n/**\n * Template that is cloned verbatim from a git repo\n * Performs .env manipulation based upon input\n */\nexport interface GitTemplate extends Template {\n type: 'starter'\n url: string\n}\n\n/**\n * Type specifically for the plugin template\n * No .env manipulation is done\n */\nexport interface PluginTemplate extends Template {\n type: 'plugin'\n url: string\n}\n\ninterface Template {\n description?: string\n name: string\n type: ProjectTemplate['type']\n}\n\nexport type PackageManager = 'bun' | 'npm' | 'pnpm' | 'yarn'\n\nexport type DbType = 'd1-sqlite' | 'mongodb' | 'postgres' | 'sqlite' | 'vercel-postgres'\n\nexport type DbDetails = {\n dbUri?: string\n type: DbType\n}\n\nexport type EditorType = 'lexical' | 'slate'\n\nexport type NextAppDetails = {\n hasTopLevelLayout: boolean\n isPayloadInstalled?: boolean\n isSrcDir: boolean\n isSupportedNextVersion: boolean\n nextAppDir?: string\n nextConfigPath?: string\n nextConfigType?: NextConfigType\n nextVersion: null | string\n}\n\nexport type NextConfigType = 'cjs' | 'esm' | 'ts'\n\nexport type StorageAdapterType = 'localDisk' | 'r2Storage' | 'vercelBlobStorage'\n"],"names":[],"mappings":"AA2EA,WAAgF"}
|
|
@@ -16,15 +16,12 @@ export declare function getFileSize(filePath: string): Promise<number>;
|
|
|
16
16
|
*/
|
|
17
17
|
export declare function collectStaticAssets(projectPath: string): Promise<string[]>;
|
|
18
18
|
/**
|
|
19
|
-
* Create Lambda deployment zip
|
|
19
|
+
* Create Lambda deployment zip
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
* - Copies static files to standalone build
|
|
23
|
-
* - Creates lambda.zip from .next/standalone/
|
|
24
|
-
* - Places zip at project root
|
|
21
|
+
* Uses cross-platform Node.js implementation instead of shell script.
|
|
25
22
|
*
|
|
26
23
|
* @param projectPath - Path to project root
|
|
27
|
-
* @throws Error if
|
|
24
|
+
* @throws Error if build missing or zip creation fails
|
|
28
25
|
*/
|
|
29
26
|
export declare function createLambdaZip(projectPath: string): Promise<void>;
|
|
30
27
|
//# sourceMappingURL=asset-collection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset-collection.d.ts","sourceRoot":"","sources":["../../src/utils/asset-collection.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"asset-collection.d.ts","sourceRoot":"","sources":["../../src/utils/asset-collection.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGnE;AAgDD;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAiBhF;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAExE"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { exec } from 'child_process';
|
|
2
1
|
import fs from 'fs/promises';
|
|
3
2
|
import path from 'path';
|
|
4
|
-
import {
|
|
3
|
+
import { buildLambdaZip } from './build-lambda-zip.js';
|
|
5
4
|
import * as log from './log.js';
|
|
6
|
-
const execAsync = promisify(exec);
|
|
7
5
|
// Maximum file size for static assets (S3 limitation)
|
|
8
6
|
const MAX_ASSET_SIZE = 50 * 1024 * 1024 // 50MB
|
|
9
7
|
;
|
|
@@ -75,43 +73,21 @@ const MAX_ASSET_SIZE = 50 * 1024 * 1024 // 50MB
|
|
|
75
73
|
return [];
|
|
76
74
|
}
|
|
77
75
|
const files = await collectFiles(staticDir, projectPath);
|
|
78
|
-
//
|
|
79
|
-
return files.map((file)=>
|
|
76
|
+
// Normalize paths to forward slashes (cross-platform) and convert prefix
|
|
77
|
+
return files.map((file)=>{
|
|
78
|
+
const normalized = file.split(path.sep).join('/');
|
|
79
|
+
return normalized.replace(/^\.next\//, '_next/');
|
|
80
|
+
});
|
|
80
81
|
}
|
|
81
82
|
/**
|
|
82
|
-
* Create Lambda deployment zip
|
|
83
|
+
* Create Lambda deployment zip
|
|
83
84
|
*
|
|
84
|
-
*
|
|
85
|
-
* - Copies static files to standalone build
|
|
86
|
-
* - Creates lambda.zip from .next/standalone/
|
|
87
|
-
* - Places zip at project root
|
|
85
|
+
* Uses cross-platform Node.js implementation instead of shell script.
|
|
88
86
|
*
|
|
89
87
|
* @param projectPath - Path to project root
|
|
90
|
-
* @throws Error if
|
|
88
|
+
* @throws Error if build missing or zip creation fails
|
|
91
89
|
*/ export async function createLambdaZip(projectPath) {
|
|
92
|
-
|
|
93
|
-
// Check if script exists
|
|
94
|
-
try {
|
|
95
|
-
await fs.stat(scriptPath);
|
|
96
|
-
} catch {
|
|
97
|
-
throw new Error('build_for_lambda.sh not found. Run init command to set up project.');
|
|
98
|
-
}
|
|
99
|
-
// Execute script
|
|
100
|
-
try {
|
|
101
|
-
await execAsync('./build_for_lambda.sh', {
|
|
102
|
-
cwd: projectPath
|
|
103
|
-
});
|
|
104
|
-
} catch (error) {
|
|
105
|
-
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
106
|
-
throw new Error(`Failed to create Lambda zip: ${message}`);
|
|
107
|
-
}
|
|
108
|
-
// Verify zip was created
|
|
109
|
-
const zipPath = path.join(projectPath, 'lambda.zip');
|
|
110
|
-
try {
|
|
111
|
-
await fs.stat(zipPath);
|
|
112
|
-
} catch {
|
|
113
|
-
throw new Error('lambda.zip was not created by build_for_lambda.sh');
|
|
114
|
-
}
|
|
90
|
+
await buildLambdaZip(projectPath);
|
|
115
91
|
}
|
|
116
92
|
|
|
117
93
|
//# sourceMappingURL=asset-collection.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/asset-collection.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["../../src/utils/asset-collection.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\n\nimport { buildLambdaZip } from './build-lambda-zip.js'\nimport * as log from './log.js'\n\n// Maximum file size for static assets (S3 limitation)\nconst MAX_ASSET_SIZE = 50 * 1024 * 1024 // 50MB\n\n/**\n * Get file size in bytes\n *\n * @param filePath - Absolute path to file\n * @returns File size in bytes\n */\nexport async function getFileSize(filePath: string): Promise<number> {\n const stats = await fs.stat(filePath)\n return stats.size\n}\n\n/**\n * Recursively collect files from a directory\n *\n * Excludes files larger than 50MB (S3 limitation).\n * Warns user when files are excluded due to size.\n *\n * @param dir - Directory to scan\n * @param baseDir - Base directory for relative paths\n * @returns Array of relative file paths\n */\nasync function collectFiles(dir: string, baseDir: string): Promise<string[]> {\n const files: string[] = []\n\n try {\n const entries = await fs.readdir(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n\n if (entry.isDirectory()) {\n // Recursively collect from subdirectories\n const subFiles = await collectFiles(fullPath, baseDir)\n files.push(...subFiles)\n } else if (entry.isFile()) {\n // Check file size before adding\n const stats = await fs.stat(fullPath)\n if (stats.size <= MAX_ASSET_SIZE) {\n // Add relative path from base directory\n const relativePath = path.relative(baseDir, fullPath)\n files.push(relativePath)\n } else {\n // Warn user about skipped files\n const sizeMB = (stats.size / (1024 * 1024)).toFixed(2)\n const relativePath = path.relative(baseDir, fullPath)\n log.warning(`Skipping large asset: ${relativePath} (${sizeMB}MB exceeds 50MB limit)`)\n }\n }\n }\n } catch {\n // Directory doesn't exist or not accessible\n return []\n }\n\n return files\n}\n\n/**\n * Collect all static asset paths from .next/static\n *\n * Returns paths relative to project root, formatted for S3:\n * - `.next/static/chunks/main.js` → `_next/static/chunks/main.js`\n *\n * @param projectPath - Path to project root\n * @returns Array of static asset paths (using _next prefix)\n */\nexport async function collectStaticAssets(projectPath: string): Promise<string[]> {\n const staticDir = path.join(projectPath, '.next', 'static')\n\n try {\n await fs.stat(staticDir)\n } catch {\n // No static directory\n return []\n }\n\n const files = await collectFiles(staticDir, projectPath)\n\n // Normalize paths to forward slashes (cross-platform) and convert prefix\n return files.map((file) => {\n const normalized = file.split(path.sep).join('/')\n return normalized.replace(/^\\.next\\//, '_next/')\n })\n}\n\n/**\n * Create Lambda deployment zip\n *\n * Uses cross-platform Node.js implementation instead of shell script.\n *\n * @param projectPath - Path to project root\n * @throws Error if build missing or zip creation fails\n */\nexport async function createLambdaZip(projectPath: string): Promise<void> {\n await buildLambdaZip(projectPath)\n}\n"],"names":["fs","path","buildLambdaZip","log","MAX_ASSET_SIZE","getFileSize","filePath","stats","stat","size","collectFiles","dir","baseDir","files","entries","readdir","withFileTypes","entry","fullPath","join","name","isDirectory","subFiles","push","isFile","relativePath","relative","sizeMB","toFixed","warning","collectStaticAssets","projectPath","staticDir","map","file","normalized","split","sep","replace","createLambdaZip"],"mappings":"AAAA,OAAOA,QAAQ,cAAa;AAC5B,OAAOC,UAAU,OAAM;AAEvB,SAASC,cAAc,QAAQ,wBAAuB;AACtD,YAAYC,SAAS,WAAU;AAE/B,sDAAsD;AACtD,MAAMC,iBAAiB,KAAK,OAAO,KAAK,OAAO;;AAE/C;;;;;CAKC,GACD,OAAO,eAAeC,YAAYC,QAAgB;IAChD,MAAMC,QAAQ,MAAMP,GAAGQ,IAAI,CAACF;IAC5B,OAAOC,MAAME,IAAI;AACnB;AAEA;;;;;;;;;CASC,GACD,eAAeC,aAAaC,GAAW,EAAEC,OAAe;IACtD,MAAMC,QAAkB,EAAE;IAE1B,IAAI;QACF,MAAMC,UAAU,MAAMd,GAAGe,OAAO,CAACJ,KAAK;YAAEK,eAAe;QAAK;QAE5D,KAAK,MAAMC,SAASH,QAAS;YAC3B,MAAMI,WAAWjB,KAAKkB,IAAI,CAACR,KAAKM,MAAMG,IAAI;YAE1C,IAAIH,MAAMI,WAAW,IAAI;gBACvB,0CAA0C;gBAC1C,MAAMC,WAAW,MAAMZ,aAAaQ,UAAUN;gBAC9CC,MAAMU,IAAI,IAAID;YAChB,OAAO,IAAIL,MAAMO,MAAM,IAAI;gBACzB,gCAAgC;gBAChC,MAAMjB,QAAQ,MAAMP,GAAGQ,IAAI,CAACU;gBAC5B,IAAIX,MAAME,IAAI,IAAIL,gBAAgB;oBAChC,wCAAwC;oBACxC,MAAMqB,eAAexB,KAAKyB,QAAQ,CAACd,SAASM;oBAC5CL,MAAMU,IAAI,CAACE;gBACb,OAAO;oBACL,gCAAgC;oBAChC,MAAME,SAAS,AAACpB,CAAAA,MAAME,IAAI,GAAI,CAAA,OAAO,IAAG,CAAC,EAAGmB,OAAO,CAAC;oBACpD,MAAMH,eAAexB,KAAKyB,QAAQ,CAACd,SAASM;oBAC5Cf,IAAI0B,OAAO,CAAC,CAAC,sBAAsB,EAAEJ,aAAa,EAAE,EAAEE,OAAO,sBAAsB,CAAC;gBACtF;YACF;QACF;IACF,EAAE,OAAM;QACN,4CAA4C;QAC5C,OAAO,EAAE;IACX;IAEA,OAAOd;AACT;AAEA;;;;;;;;CAQC,GACD,OAAO,eAAeiB,oBAAoBC,WAAmB;IAC3D,MAAMC,YAAY/B,KAAKkB,IAAI,CAACY,aAAa,SAAS;IAElD,IAAI;QACF,MAAM/B,GAAGQ,IAAI,CAACwB;IAChB,EAAE,OAAM;QACN,sBAAsB;QACtB,OAAO,EAAE;IACX;IAEA,MAAMnB,QAAQ,MAAMH,aAAasB,WAAWD;IAE5C,yEAAyE;IACzE,OAAOlB,MAAMoB,GAAG,CAAC,CAACC;QAChB,MAAMC,aAAaD,KAAKE,KAAK,CAACnC,KAAKoC,GAAG,EAAElB,IAAI,CAAC;QAC7C,OAAOgB,WAAWG,OAAO,CAAC,aAAa;IACzC;AACF;AAEA;;;;;;;CAOC,GACD,OAAO,eAAeC,gBAAgBR,WAAmB;IACvD,MAAM7B,eAAe6B;AACvB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build Lambda deployment zip using pure Node.js
|
|
3
|
+
*
|
|
4
|
+
* Cross-platform replacement for build_for_lambda.sh:
|
|
5
|
+
* 1. Copies .next/static to .next/standalone/.next/static
|
|
6
|
+
* 2. Copies run.sh to .next/standalone/run.sh
|
|
7
|
+
* 3. Copies public/ to .next/standalone/public/ (if exists)
|
|
8
|
+
* 4. Creates lambda.zip from .next/standalone/
|
|
9
|
+
*
|
|
10
|
+
* @param projectPath - Path to project root
|
|
11
|
+
* @throws Error if standalone directory missing or zip creation fails
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildLambdaZip(projectPath: string): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=build-lambda-zip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-lambda-zip.d.ts","sourceRoot":"","sources":["../../src/utils/build-lambda-zip.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BvE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import archiver from 'archiver';
|
|
2
|
+
import { createWriteStream } from 'fs';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
/**
|
|
6
|
+
* Build Lambda deployment zip using pure Node.js
|
|
7
|
+
*
|
|
8
|
+
* Cross-platform replacement for build_for_lambda.sh:
|
|
9
|
+
* 1. Copies .next/static to .next/standalone/.next/static
|
|
10
|
+
* 2. Copies run.sh to .next/standalone/run.sh
|
|
11
|
+
* 3. Copies public/ to .next/standalone/public/ (if exists)
|
|
12
|
+
* 4. Creates lambda.zip from .next/standalone/
|
|
13
|
+
*
|
|
14
|
+
* @param projectPath - Path to project root
|
|
15
|
+
* @throws Error if standalone directory missing or zip creation fails
|
|
16
|
+
*/ export async function buildLambdaZip(projectPath) {
|
|
17
|
+
const standalonePath = path.join(projectPath, '.next', 'standalone');
|
|
18
|
+
const staticPath = path.join(projectPath, '.next', 'static');
|
|
19
|
+
const publicPath = path.join(projectPath, 'public');
|
|
20
|
+
const runShPath = path.join(projectPath, 'run.sh');
|
|
21
|
+
const zipPath = path.join(projectPath, 'lambda.zip');
|
|
22
|
+
if (!await isDirectory(standalonePath)) {
|
|
23
|
+
throw new Error('Standalone build not found at .next/standalone. ' + 'Ensure next.config.js has output: "standalone" and run build first.');
|
|
24
|
+
}
|
|
25
|
+
if (await isDirectory(staticPath)) {
|
|
26
|
+
const destStatic = path.join(standalonePath, '.next', 'static');
|
|
27
|
+
await copyDirectory(staticPath, destStatic);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
await fs.copyFile(runShPath, path.join(standalonePath, 'run.sh'));
|
|
31
|
+
} catch {
|
|
32
|
+
// run.sh may not exist in all setups
|
|
33
|
+
}
|
|
34
|
+
if (await isDirectory(publicPath)) {
|
|
35
|
+
const destPublic = path.join(standalonePath, 'public');
|
|
36
|
+
await copyDirectory(publicPath, destPublic);
|
|
37
|
+
}
|
|
38
|
+
await createZip(standalonePath, zipPath);
|
|
39
|
+
}
|
|
40
|
+
async function isDirectory(dirPath) {
|
|
41
|
+
try {
|
|
42
|
+
const stats = await fs.stat(dirPath);
|
|
43
|
+
return stats.isDirectory();
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function copyDirectory(src, dest) {
|
|
49
|
+
await fs.mkdir(dest, {
|
|
50
|
+
recursive: true
|
|
51
|
+
});
|
|
52
|
+
const entries = await fs.readdir(src, {
|
|
53
|
+
withFileTypes: true
|
|
54
|
+
});
|
|
55
|
+
for (const entry of entries){
|
|
56
|
+
const srcPath = path.join(src, entry.name);
|
|
57
|
+
const destPath = path.join(dest, entry.name);
|
|
58
|
+
if (entry.isDirectory()) {
|
|
59
|
+
await copyDirectory(srcPath, destPath);
|
|
60
|
+
} else {
|
|
61
|
+
await fs.copyFile(srcPath, destPath);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function createZip(sourceDir, zipPath) {
|
|
66
|
+
return new Promise((resolve, reject)=>{
|
|
67
|
+
const output = createWriteStream(zipPath);
|
|
68
|
+
const archive = archiver('zip', {
|
|
69
|
+
zlib: {
|
|
70
|
+
level: 9
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
output.on('close', ()=>resolve());
|
|
74
|
+
archive.on('error', (err)=>reject(err));
|
|
75
|
+
archive.pipe(output);
|
|
76
|
+
archive.directory(sourceDir, false);
|
|
77
|
+
void archive.finalize();
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//# sourceMappingURL=build-lambda-zip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/build-lambda-zip.ts"],"sourcesContent":["import archiver from 'archiver'\nimport { createWriteStream } from 'fs'\nimport fs from 'fs/promises'\nimport path from 'path'\n\n/**\n * Build Lambda deployment zip using pure Node.js\n *\n * Cross-platform replacement for build_for_lambda.sh:\n * 1. Copies .next/static to .next/standalone/.next/static\n * 2. Copies run.sh to .next/standalone/run.sh\n * 3. Copies public/ to .next/standalone/public/ (if exists)\n * 4. Creates lambda.zip from .next/standalone/\n *\n * @param projectPath - Path to project root\n * @throws Error if standalone directory missing or zip creation fails\n */\nexport async function buildLambdaZip(projectPath: string): Promise<void> {\n const standalonePath = path.join(projectPath, '.next', 'standalone')\n const staticPath = path.join(projectPath, '.next', 'static')\n const publicPath = path.join(projectPath, 'public')\n const runShPath = path.join(projectPath, 'run.sh')\n const zipPath = path.join(projectPath, 'lambda.zip')\n\n if (!(await isDirectory(standalonePath))) {\n throw new Error(\n 'Standalone build not found at .next/standalone. ' +\n 'Ensure next.config.js has output: \"standalone\" and run build first.',\n )\n }\n\n if (await isDirectory(staticPath)) {\n const destStatic = path.join(standalonePath, '.next', 'static')\n await copyDirectory(staticPath, destStatic)\n }\n\n try {\n await fs.copyFile(runShPath, path.join(standalonePath, 'run.sh'))\n } catch {\n // run.sh may not exist in all setups\n }\n\n if (await isDirectory(publicPath)) {\n const destPublic = path.join(standalonePath, 'public')\n await copyDirectory(publicPath, destPublic)\n }\n\n await createZip(standalonePath, zipPath)\n}\n\nasync function isDirectory(dirPath: string): Promise<boolean> {\n try {\n const stats = await fs.stat(dirPath)\n return stats.isDirectory()\n } catch {\n return false\n }\n}\n\nasync function copyDirectory(src: string, dest: string): Promise<void> {\n await fs.mkdir(dest, { recursive: true })\n const entries = await fs.readdir(src, { withFileTypes: true })\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name)\n const destPath = path.join(dest, entry.name)\n\n if (entry.isDirectory()) {\n await copyDirectory(srcPath, destPath)\n } else {\n await fs.copyFile(srcPath, destPath)\n }\n }\n}\n\nfunction createZip(sourceDir: string, zipPath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const output = createWriteStream(zipPath)\n const archive = archiver('zip', { zlib: { level: 9 } })\n\n output.on('close', () => resolve())\n archive.on('error', (err) => reject(err))\n\n archive.pipe(output)\n archive.directory(sourceDir, false)\n\n void archive.finalize()\n })\n}\n"],"names":["archiver","createWriteStream","fs","path","buildLambdaZip","projectPath","standalonePath","join","staticPath","publicPath","runShPath","zipPath","isDirectory","Error","destStatic","copyDirectory","copyFile","destPublic","createZip","dirPath","stats","stat","src","dest","mkdir","recursive","entries","readdir","withFileTypes","entry","srcPath","name","destPath","sourceDir","Promise","resolve","reject","output","archive","zlib","level","on","err","pipe","directory","finalize"],"mappings":"AAAA,OAAOA,cAAc,WAAU;AAC/B,SAASC,iBAAiB,QAAQ,KAAI;AACtC,OAAOC,QAAQ,cAAa;AAC5B,OAAOC,UAAU,OAAM;AAEvB;;;;;;;;;;;CAWC,GACD,OAAO,eAAeC,eAAeC,WAAmB;IACtD,MAAMC,iBAAiBH,KAAKI,IAAI,CAACF,aAAa,SAAS;IACvD,MAAMG,aAAaL,KAAKI,IAAI,CAACF,aAAa,SAAS;IACnD,MAAMI,aAAaN,KAAKI,IAAI,CAACF,aAAa;IAC1C,MAAMK,YAAYP,KAAKI,IAAI,CAACF,aAAa;IACzC,MAAMM,UAAUR,KAAKI,IAAI,CAACF,aAAa;IAEvC,IAAI,CAAE,MAAMO,YAAYN,iBAAkB;QACxC,MAAM,IAAIO,MACR,qDACE;IAEN;IAEA,IAAI,MAAMD,YAAYJ,aAAa;QACjC,MAAMM,aAAaX,KAAKI,IAAI,CAACD,gBAAgB,SAAS;QACtD,MAAMS,cAAcP,YAAYM;IAClC;IAEA,IAAI;QACF,MAAMZ,GAAGc,QAAQ,CAACN,WAAWP,KAAKI,IAAI,CAACD,gBAAgB;IACzD,EAAE,OAAM;IACN,qCAAqC;IACvC;IAEA,IAAI,MAAMM,YAAYH,aAAa;QACjC,MAAMQ,aAAad,KAAKI,IAAI,CAACD,gBAAgB;QAC7C,MAAMS,cAAcN,YAAYQ;IAClC;IAEA,MAAMC,UAAUZ,gBAAgBK;AAClC;AAEA,eAAeC,YAAYO,OAAe;IACxC,IAAI;QACF,MAAMC,QAAQ,MAAMlB,GAAGmB,IAAI,CAACF;QAC5B,OAAOC,MAAMR,WAAW;IAC1B,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,eAAeG,cAAcO,GAAW,EAAEC,IAAY;IACpD,MAAMrB,GAAGsB,KAAK,CAACD,MAAM;QAAEE,WAAW;IAAK;IACvC,MAAMC,UAAU,MAAMxB,GAAGyB,OAAO,CAACL,KAAK;QAAEM,eAAe;IAAK;IAE5D,KAAK,MAAMC,SAASH,QAAS;QAC3B,MAAMI,UAAU3B,KAAKI,IAAI,CAACe,KAAKO,MAAME,IAAI;QACzC,MAAMC,WAAW7B,KAAKI,IAAI,CAACgB,MAAMM,MAAME,IAAI;QAE3C,IAAIF,MAAMjB,WAAW,IAAI;YACvB,MAAMG,cAAce,SAASE;QAC/B,OAAO;YACL,MAAM9B,GAAGc,QAAQ,CAACc,SAASE;QAC7B;IACF;AACF;AAEA,SAASd,UAAUe,SAAiB,EAAEtB,OAAe;IACnD,OAAO,IAAIuB,QAAQ,CAACC,SAASC;QAC3B,MAAMC,SAASpC,kBAAkBU;QACjC,MAAM2B,UAAUtC,SAAS,OAAO;YAAEuC,MAAM;gBAAEC,OAAO;YAAE;QAAE;QAErDH,OAAOI,EAAE,CAAC,SAAS,IAAMN;QACzBG,QAAQG,EAAE,CAAC,SAAS,CAACC,MAAQN,OAAOM;QAEpCJ,QAAQK,IAAI,CAACN;QACbC,QAAQM,SAAS,CAACX,WAAW;QAE7B,KAAKK,QAAQO,QAAQ;IACvB;AACF"}
|
package/dist/utils/config.js
CHANGED
|
@@ -19,7 +19,7 @@ const GITIGNORE_FILENAME = '.gitignore';
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
// Parse existing entries
|
|
22
|
-
const existingLines = existingContent.split(
|
|
22
|
+
const existingLines = existingContent.split(/\r?\n/).filter((line)=>line.trim());
|
|
23
23
|
const existingSet = new Set(existingLines);
|
|
24
24
|
// Add new entries that don't exist
|
|
25
25
|
const newEntries = entries.filter((entry)=>!existingSet.has(entry));
|