@payloadcms/plugin-stripe 3.91.0-internal.c1569dc → 4.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +2 -2
- package/dist/exports/client.d.ts +1 -1
- package/dist/exports/client.d.ts.map +1 -1
- package/dist/exports/client.js +1 -1
- package/dist/exports/client.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/routes/rest.js +1 -7
- package/dist/routes/rest.js.map +1 -1
- package/dist/ui/LinkToDoc/index.css +26 -0
- package/dist/ui/LinkToDoc/index.d.ts +5 -0
- package/dist/ui/LinkToDoc/index.d.ts.map +1 -0
- package/dist/ui/LinkToDoc/index.js +45 -0
- package/dist/ui/LinkToDoc/index.js.map +1 -0
- package/dist/utilities/deepen.d.ts +1 -1
- package/dist/webhooks/handleCreatedOrUpdated.d.ts.map +1 -1
- package/dist/webhooks/handleCreatedOrUpdated.js +8 -3
- package/dist/webhooks/handleCreatedOrUpdated.js.map +1 -1
- package/dist/webhooks/handleDeleted.d.ts.map +1 -1
- package/dist/webhooks/handleDeleted.js +3 -1
- package/dist/webhooks/handleDeleted.js.map +1 -1
- package/package.json +10 -10
- package/dist/index.spec.js +0 -115
- package/dist/index.spec.js.map +0 -1
- package/dist/routes/rest.spec.js +0 -282
- package/dist/routes/rest.spec.js.map +0 -1
- package/dist/ui/LinkToDoc.d.ts +0 -3
- package/dist/ui/LinkToDoc.d.ts.map +0 -1
- package/dist/ui/LinkToDoc.js +0 -48
- package/dist/ui/LinkToDoc.js.map +0 -1
- package/dist/utilities/deepen.spec.js +0 -110
- package/dist/utilities/deepen.spec.js.map +0 -1
package/LICENSE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2018-
|
|
3
|
+
Copyright (c) 2018-2026 Payload CMS, LLC <info@payloadcms.com>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
6
|
a copy of this software and associated documentation files (the
|
package/README.md
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
A plugin for [Payload](https://github.com/payloadcms/payload) to connect [Stripe](https://stripe.com) and Payload.
|
|
4
4
|
|
|
5
|
-
- [Source code](https://github.com/payloadcms/payload/tree/
|
|
5
|
+
- [Source code](https://github.com/payloadcms/payload/tree/main/packages/plugin-stripe)
|
|
6
6
|
- [Documentation](https://payloadcms.com/docs/plugins/stripe)
|
|
7
|
-
- [Documentation source](https://github.com/payloadcms/payload/tree/
|
|
7
|
+
- [Documentation source](https://github.com/payloadcms/payload/tree/main/docs/plugins/stripe.mdx)
|
package/dist/exports/client.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { LinkToDoc } from '../ui/LinkToDoc.js';
|
|
1
|
+
export { LinkToDoc } from '../ui/LinkToDoc/index.js';
|
|
2
2
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA"}
|
package/dist/exports/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["'use client'\n\nexport { LinkToDoc } from '../ui/LinkToDoc.js'\n"],"names":["LinkToDoc"],"mappings":"AAAA;AAEA,SAASA,SAAS,QAAQ,
|
|
1
|
+
{"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["'use client'\n\nexport { LinkToDoc } from '../ui/LinkToDoc/index.js'\n"],"names":["LinkToDoc"],"mappings":"AAAA;AAEA,SAASA,SAAS,QAAQ,2BAA0B"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { Config } from 'payload';
|
|
2
1
|
import type { StripePluginConfig } from './types.js';
|
|
3
2
|
export { stripeProxy } from './utilities/stripeProxy.js';
|
|
4
|
-
export declare const stripePlugin: (
|
|
3
|
+
export declare const stripePlugin: (options: StripePluginConfig) => import("payload").Plugin;
|
|
5
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAA+B,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAUjF,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAExD,eAAO,MAAM,YAAY,2DAoGvB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { definePlugin } from 'payload';
|
|
1
2
|
import { getFields } from './fields/getFields.js';
|
|
2
3
|
import { createNewInStripe } from './hooks/createNewInStripe.js';
|
|
3
4
|
import { deleteFromStripe } from './hooks/deleteFromStripe.js';
|
|
@@ -6,7 +7,9 @@ import { stripeREST } from './routes/rest.js';
|
|
|
6
7
|
import { stripeWebhooks } from './routes/webhooks.js';
|
|
7
8
|
import { sanitizeStripeRESTConfig } from './utilities/sanitizeStripeRESTConfig.js';
|
|
8
9
|
export { stripeProxy } from './utilities/stripeProxy.js';
|
|
9
|
-
export const stripePlugin = (
|
|
10
|
+
export const stripePlugin = definePlugin({
|
|
11
|
+
slug: '@payloadcms/plugin-stripe',
|
|
12
|
+
plugin: ({ config, options: incomingStripeConfig })=>{
|
|
10
13
|
const { collections } = config;
|
|
11
14
|
// set config defaults here
|
|
12
15
|
const pluginConfig = {
|
|
@@ -89,6 +92,7 @@ export const stripePlugin = (incomingStripeConfig)=>(config)=>{
|
|
|
89
92
|
}
|
|
90
93
|
config.endpoints = endpoints;
|
|
91
94
|
return config;
|
|
92
|
-
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
93
97
|
|
|
94
98
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport { definePlugin } from 'payload'\n\nimport type { SanitizedStripePluginConfig, StripePluginConfig } from './types.js'\n\nimport { getFields } from './fields/getFields.js'\nimport { createNewInStripe } from './hooks/createNewInStripe.js'\nimport { deleteFromStripe } from './hooks/deleteFromStripe.js'\nimport { syncExistingWithStripe } from './hooks/syncExistingWithStripe.js'\nimport { stripeREST } from './routes/rest.js'\nimport { stripeWebhooks } from './routes/webhooks.js'\nimport { sanitizeStripeRESTConfig } from './utilities/sanitizeStripeRESTConfig.js'\n\nexport { stripeProxy } from './utilities/stripeProxy.js'\n\nexport const stripePlugin = definePlugin<StripePluginConfig>({\n slug: '@payloadcms/plugin-stripe',\n plugin: ({ config, options: incomingStripeConfig }) => {\n const { collections } = config\n\n // set config defaults here\n const pluginConfig: SanitizedStripePluginConfig = {\n ...incomingStripeConfig,\n rest: sanitizeStripeRESTConfig({ rest: incomingStripeConfig?.rest }),\n sync: incomingStripeConfig?.sync || [],\n }\n\n // NOTE: env variables are never passed to the client, but we need to know if `stripeSecretKey` is a test key\n // unfortunately we must set the 'isTestKey' property on the config instead of using the following code:\n // const isTestKey = stripeConfig.stripeSecretKey?.startsWith('sk_test_');\n\n const endpoints: Endpoint[] = [\n ...(config?.endpoints || []),\n {\n handler: async (req) => {\n const res = await stripeWebhooks({\n config,\n pluginConfig,\n req,\n })\n\n return res\n },\n method: 'post',\n path: '/stripe/webhooks',\n },\n ]\n\n if (pluginConfig.rest) {\n endpoints.push({\n handler: async (req) => {\n const res = await stripeREST({\n pluginConfig,\n req,\n })\n\n return res\n },\n method: 'post' as Endpoint['method'],\n path: '/stripe/rest',\n })\n }\n\n for (const collection of collections!) {\n const { hooks: existingHooks } = collection\n\n const syncConfig = pluginConfig.sync?.find((sync) => sync.collection === collection.slug)\n\n if (!syncConfig) {\n continue\n }\n const fields = getFields({\n collection,\n pluginConfig,\n syncConfig,\n })\n collection.fields = fields\n\n if (!collection.hooks) {\n collection.hooks = {}\n }\n\n collection.hooks.afterDelete = [\n ...(existingHooks?.afterDelete || []),\n (args) =>\n deleteFromStripe({\n ...args,\n collection,\n pluginConfig,\n }),\n ]\n collection.hooks.beforeChange = [\n ...(existingHooks?.beforeChange || []),\n (args) =>\n syncExistingWithStripe({\n ...args,\n collection,\n pluginConfig,\n }),\n ]\n collection.hooks.beforeValidate = [\n ...(existingHooks?.beforeValidate || []),\n (args) =>\n createNewInStripe({\n ...args,\n collection,\n pluginConfig,\n }),\n ]\n }\n\n config.endpoints = endpoints\n\n return config\n },\n})\n"],"names":["definePlugin","getFields","createNewInStripe","deleteFromStripe","syncExistingWithStripe","stripeREST","stripeWebhooks","sanitizeStripeRESTConfig","stripeProxy","stripePlugin","slug","plugin","config","options","incomingStripeConfig","collections","pluginConfig","rest","sync","endpoints","handler","req","res","method","path","push","collection","hooks","existingHooks","syncConfig","find","fields","afterDelete","args","beforeChange","beforeValidate"],"mappings":"AAEA,SAASA,YAAY,QAAQ,UAAS;AAItC,SAASC,SAAS,QAAQ,wBAAuB;AACjD,SAASC,iBAAiB,QAAQ,+BAA8B;AAChE,SAASC,gBAAgB,QAAQ,8BAA6B;AAC9D,SAASC,sBAAsB,QAAQ,oCAAmC;AAC1E,SAASC,UAAU,QAAQ,mBAAkB;AAC7C,SAASC,cAAc,QAAQ,uBAAsB;AACrD,SAASC,wBAAwB,QAAQ,0CAAyC;AAElF,SAASC,WAAW,QAAQ,6BAA4B;AAExD,OAAO,MAAMC,eAAeT,aAAiC;IAC3DU,MAAM;IACNC,QAAQ,CAAC,EAAEC,MAAM,EAAEC,SAASC,oBAAoB,EAAE;QAChD,MAAM,EAAEC,WAAW,EAAE,GAAGH;QAExB,2BAA2B;QAC3B,MAAMI,eAA4C;YAChD,GAAGF,oBAAoB;YACvBG,MAAMV,yBAAyB;gBAAEU,MAAMH,sBAAsBG;YAAK;YAClEC,MAAMJ,sBAAsBI,QAAQ,EAAE;QACxC;QAEA,6GAA6G;QAC7G,wGAAwG;QACxG,0EAA0E;QAE1E,MAAMC,YAAwB;eACxBP,QAAQO,aAAa,EAAE;YAC3B;gBACEC,SAAS,OAAOC;oBACd,MAAMC,MAAM,MAAMhB,eAAe;wBAC/BM;wBACAI;wBACAK;oBACF;oBAEA,OAAOC;gBACT;gBACAC,QAAQ;gBACRC,MAAM;YACR;SACD;QAED,IAAIR,aAAaC,IAAI,EAAE;YACrBE,UAAUM,IAAI,CAAC;gBACbL,SAAS,OAAOC;oBACd,MAAMC,MAAM,MAAMjB,WAAW;wBAC3BW;wBACAK;oBACF;oBAEA,OAAOC;gBACT;gBACAC,QAAQ;gBACRC,MAAM;YACR;QACF;QAEA,KAAK,MAAME,cAAcX,YAAc;YACrC,MAAM,EAAEY,OAAOC,aAAa,EAAE,GAAGF;YAEjC,MAAMG,aAAab,aAAaE,IAAI,EAAEY,KAAK,CAACZ,OAASA,KAAKQ,UAAU,KAAKA,WAAWhB,IAAI;YAExF,IAAI,CAACmB,YAAY;gBACf;YACF;YACA,MAAME,SAAS9B,UAAU;gBACvByB;gBACAV;gBACAa;YACF;YACAH,WAAWK,MAAM,GAAGA;YAEpB,IAAI,CAACL,WAAWC,KAAK,EAAE;gBACrBD,WAAWC,KAAK,GAAG,CAAC;YACtB;YAEAD,WAAWC,KAAK,CAACK,WAAW,GAAG;mBACzBJ,eAAeI,eAAe,EAAE;gBACpC,CAACC,OACC9B,iBAAiB;wBACf,GAAG8B,IAAI;wBACPP;wBACAV;oBACF;aACH;YACDU,WAAWC,KAAK,CAACO,YAAY,GAAG;mBAC1BN,eAAeM,gBAAgB,EAAE;gBACrC,CAACD,OACC7B,uBAAuB;wBACrB,GAAG6B,IAAI;wBACPP;wBACAV;oBACF;aACH;YACDU,WAAWC,KAAK,CAACQ,cAAc,GAAG;mBAC5BP,eAAeO,kBAAkB,EAAE;gBACvC,CAACF,OACC/B,kBAAkB;wBAChB,GAAG+B,IAAI;wBACPP;wBACAV;oBACF;aACH;QACH;QAEAJ,OAAOO,SAAS,GAAGA;QAEnB,OAAOP;IACT;AACF,GAAE"}
|
package/dist/routes/rest.js
CHANGED
|
@@ -53,13 +53,7 @@ export const stripeREST = async (args)=>{
|
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
55
|
const { stripeArgs, stripeMethod } = req.data ?? {};
|
|
56
|
-
if (typeof stripeMethod !== 'string' || stripeMethod.trim().length === 0) {
|
|
57
|
-
return errorResponse({
|
|
58
|
-
message: 'Invalid request',
|
|
59
|
-
status: 400
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
if (!pluginConfig.rest.allowedMethods.includes(stripeMethod)) {
|
|
56
|
+
if (typeof stripeMethod !== 'string' || stripeMethod.trim().length === 0 || !pluginConfig.rest.allowedMethods.includes(stripeMethod)) {
|
|
63
57
|
return errorResponse({
|
|
64
58
|
message: 'Invalid request',
|
|
65
59
|
status: 400
|
package/dist/routes/rest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/routes/rest.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { addDataAndFileToRequest, canAccessAdmin, UnauthorizedError } from 'payload'\n\nimport type { SanitizedStripePluginConfig } from '../types.js'\n\nimport { stripeProxy } from '../utilities/stripeProxy.js'\n\nexport const stripeREST = async (args: {\n pluginConfig: SanitizedStripePluginConfig\n req: PayloadRequest\n}): Promise<Response> => {\n const { pluginConfig, req } = args\n\n try {\n await addDataAndFileToRequest(req)\n } catch (err) {\n return unexpectedErrorResponse({ err, req })\n }\n\n if (!req.user) {\n return errorResponse({ message: 'Unauthorized', status: 401 })\n }\n\n if (!pluginConfig.rest) {\n return unexpectedErrorResponse({\n err: new Error('Stripe REST handler called while disabled'),\n req,\n })\n }\n\n let hasAccess: boolean\n\n if (pluginConfig.rest.access) {\n try {\n hasAccess = await pluginConfig.rest.access({ req })\n } catch (err) {\n return unexpectedErrorResponse({ err, req })\n }\n } else {\n try {\n hasAccess = await hasAdminAccess({ req })\n } catch (err) {\n return unexpectedErrorResponse({ err, req })\n }\n }\n\n if (!hasAccess) {\n return errorResponse({ message: 'Forbidden', status: 403 })\n }\n\n const { stripeArgs, stripeMethod } = req.data ?? {}\n\n if (typeof stripeMethod !== 'string'
|
|
1
|
+
{"version":3,"sources":["../../src/routes/rest.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { addDataAndFileToRequest, canAccessAdmin, UnauthorizedError } from 'payload'\n\nimport type { SanitizedStripePluginConfig } from '../types.js'\n\nimport { stripeProxy } from '../utilities/stripeProxy.js'\n\nexport const stripeREST = async (args: {\n pluginConfig: SanitizedStripePluginConfig\n req: PayloadRequest\n}): Promise<Response> => {\n const { pluginConfig, req } = args\n\n try {\n await addDataAndFileToRequest(req)\n } catch (err) {\n return unexpectedErrorResponse({ err, req })\n }\n\n if (!req.user) {\n return errorResponse({ message: 'Unauthorized', status: 401 })\n }\n\n if (!pluginConfig.rest) {\n return unexpectedErrorResponse({\n err: new Error('Stripe REST handler called while disabled'),\n req,\n })\n }\n\n let hasAccess: boolean\n\n if (pluginConfig.rest.access) {\n try {\n hasAccess = await pluginConfig.rest.access({ req })\n } catch (err) {\n return unexpectedErrorResponse({ err, req })\n }\n } else {\n try {\n hasAccess = await hasAdminAccess({ req })\n } catch (err) {\n return unexpectedErrorResponse({ err, req })\n }\n }\n\n if (!hasAccess) {\n return errorResponse({ message: 'Forbidden', status: 403 })\n }\n\n const { stripeArgs, stripeMethod } = req.data ?? {}\n\n if (\n typeof stripeMethod !== 'string' ||\n stripeMethod.trim().length === 0 ||\n !pluginConfig.rest.allowedMethods.includes(stripeMethod)\n ) {\n return errorResponse({ message: 'Invalid request', status: 400 })\n }\n\n if (!Array.isArray(stripeArgs)) {\n return errorResponse({ message: 'Invalid request', status: 400 })\n }\n\n try {\n const responseJSON = await stripeProxy({\n stripeArgs,\n stripeMethod,\n stripeSecretKey: pluginConfig.stripeSecretKey,\n })\n\n return Response.json(responseJSON, { status: responseJSON.status })\n } catch (err) {\n return unexpectedErrorResponse({ err, req })\n }\n}\n\nconst hasAdminAccess = async ({ req }: { req: PayloadRequest }): Promise<boolean> => {\n try {\n await canAccessAdmin({ req })\n return true\n } catch (err) {\n if (err instanceof UnauthorizedError) {\n return false\n }\n\n throw err\n }\n}\n\nconst errorResponse = ({ message, status }: { message: string; status: number }): Response =>\n Response.json({ message }, { status })\n\nconst unexpectedErrorResponse = ({ err, req }: { err: unknown; req: PayloadRequest }): Response => {\n req.payload.logger.error({\n err,\n msg: 'An unexpected error occurred in the Stripe plugin REST handler.',\n })\n\n return errorResponse({ message: 'Internal server error', status: 500 })\n}\n"],"names":["addDataAndFileToRequest","canAccessAdmin","UnauthorizedError","stripeProxy","stripeREST","args","pluginConfig","req","err","unexpectedErrorResponse","user","errorResponse","message","status","rest","Error","hasAccess","access","hasAdminAccess","stripeArgs","stripeMethod","data","trim","length","allowedMethods","includes","Array","isArray","responseJSON","stripeSecretKey","Response","json","payload","logger","error","msg"],"mappings":"AAEA,SAASA,uBAAuB,EAAEC,cAAc,EAAEC,iBAAiB,QAAQ,UAAS;AAIpF,SAASC,WAAW,QAAQ,8BAA6B;AAEzD,OAAO,MAAMC,aAAa,OAAOC;IAI/B,MAAM,EAAEC,YAAY,EAAEC,GAAG,EAAE,GAAGF;IAE9B,IAAI;QACF,MAAML,wBAAwBO;IAChC,EAAE,OAAOC,KAAK;QACZ,OAAOC,wBAAwB;YAAED;YAAKD;QAAI;IAC5C;IAEA,IAAI,CAACA,IAAIG,IAAI,EAAE;QACb,OAAOC,cAAc;YAAEC,SAAS;YAAgBC,QAAQ;QAAI;IAC9D;IAEA,IAAI,CAACP,aAAaQ,IAAI,EAAE;QACtB,OAAOL,wBAAwB;YAC7BD,KAAK,IAAIO,MAAM;YACfR;QACF;IACF;IAEA,IAAIS;IAEJ,IAAIV,aAAaQ,IAAI,CAACG,MAAM,EAAE;QAC5B,IAAI;YACFD,YAAY,MAAMV,aAAaQ,IAAI,CAACG,MAAM,CAAC;gBAAEV;YAAI;QACnD,EAAE,OAAOC,KAAK;YACZ,OAAOC,wBAAwB;gBAAED;gBAAKD;YAAI;QAC5C;IACF,OAAO;QACL,IAAI;YACFS,YAAY,MAAME,eAAe;gBAAEX;YAAI;QACzC,EAAE,OAAOC,KAAK;YACZ,OAAOC,wBAAwB;gBAAED;gBAAKD;YAAI;QAC5C;IACF;IAEA,IAAI,CAACS,WAAW;QACd,OAAOL,cAAc;YAAEC,SAAS;YAAaC,QAAQ;QAAI;IAC3D;IAEA,MAAM,EAAEM,UAAU,EAAEC,YAAY,EAAE,GAAGb,IAAIc,IAAI,IAAI,CAAC;IAElD,IACE,OAAOD,iBAAiB,YACxBA,aAAaE,IAAI,GAAGC,MAAM,KAAK,KAC/B,CAACjB,aAAaQ,IAAI,CAACU,cAAc,CAACC,QAAQ,CAACL,eAC3C;QACA,OAAOT,cAAc;YAAEC,SAAS;YAAmBC,QAAQ;QAAI;IACjE;IAEA,IAAI,CAACa,MAAMC,OAAO,CAACR,aAAa;QAC9B,OAAOR,cAAc;YAAEC,SAAS;YAAmBC,QAAQ;QAAI;IACjE;IAEA,IAAI;QACF,MAAMe,eAAe,MAAMzB,YAAY;YACrCgB;YACAC;YACAS,iBAAiBvB,aAAauB,eAAe;QAC/C;QAEA,OAAOC,SAASC,IAAI,CAACH,cAAc;YAAEf,QAAQe,aAAaf,MAAM;QAAC;IACnE,EAAE,OAAOL,KAAK;QACZ,OAAOC,wBAAwB;YAAED;YAAKD;QAAI;IAC5C;AACF,EAAC;AAED,MAAMW,iBAAiB,OAAO,EAAEX,GAAG,EAA2B;IAC5D,IAAI;QACF,MAAMN,eAAe;YAAEM;QAAI;QAC3B,OAAO;IACT,EAAE,OAAOC,KAAK;QACZ,IAAIA,eAAeN,mBAAmB;YACpC,OAAO;QACT;QAEA,MAAMM;IACR;AACF;AAEA,MAAMG,gBAAgB,CAAC,EAAEC,OAAO,EAAEC,MAAM,EAAuC,GAC7EiB,SAASC,IAAI,CAAC;QAAEnB;IAAQ,GAAG;QAAEC;IAAO;AAEtC,MAAMJ,0BAA0B,CAAC,EAAED,GAAG,EAAED,GAAG,EAAyC;IAClFA,IAAIyB,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;QACvB1B;QACA2B,KAAK;IACP;IAEA,OAAOxB,cAAc;QAAEC,SAAS;QAAyBC,QAAQ;IAAI;AACvE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
@layer payload-default {
|
|
2
|
+
.link-to-doc {
|
|
3
|
+
margin-bottom: var(--spacing-field);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.link-to-doc__header {
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
width: fit-content;
|
|
10
|
+
gap: var(--spacer-1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.link-to-doc__url {
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
font-weight: 600;
|
|
16
|
+
text-overflow: ellipsis;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.link-to-doc__url a {
|
|
20
|
+
color: var(--color-text-secondary);
|
|
21
|
+
|
|
22
|
+
&:hover {
|
|
23
|
+
color: var(--color-text);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/LinkToDoc/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAGjD,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,aAAa,CAAA;AAIpB,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA6BlD,CAAA"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { CopyToClipboard, FieldLabel, useFormFields } from '@payloadcms/ui';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import './index.css';
|
|
6
|
+
const baseClass = 'link-to-doc';
|
|
7
|
+
export const LinkToDoc = (props)=>{
|
|
8
|
+
const { field: { admin: { custom = {} } = {} } } = props;
|
|
9
|
+
const { isTestKey, nameOfIDField, stripeResourceType } = custom;
|
|
10
|
+
const field = useFormFields(([fields])=>fields && fields?.[nameOfIDField] || null);
|
|
11
|
+
const { value: stripeID } = field || {};
|
|
12
|
+
if (!stripeID) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const stripeEnv = isTestKey ? 'test/' : '';
|
|
16
|
+
const href = `https://dashboard.stripe.com/${stripeEnv}${stripeResourceType}/${stripeID}`;
|
|
17
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
18
|
+
className: baseClass,
|
|
19
|
+
children: [
|
|
20
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
21
|
+
className: `${baseClass}__header`,
|
|
22
|
+
children: [
|
|
23
|
+
/*#__PURE__*/ _jsx(FieldLabel, {
|
|
24
|
+
htmlFor: baseClass,
|
|
25
|
+
label: "View in Stripe"
|
|
26
|
+
}),
|
|
27
|
+
/*#__PURE__*/ _jsx(CopyToClipboard, {
|
|
28
|
+
value: href
|
|
29
|
+
})
|
|
30
|
+
]
|
|
31
|
+
}),
|
|
32
|
+
/*#__PURE__*/ _jsx("div", {
|
|
33
|
+
className: `${baseClass}__url`,
|
|
34
|
+
children: /*#__PURE__*/ _jsx("a", {
|
|
35
|
+
href: href,
|
|
36
|
+
rel: "noopener noreferrer",
|
|
37
|
+
target: "_blank",
|
|
38
|
+
children: href
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
]
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/LinkToDoc/index.tsx"],"sourcesContent":["'use client'\nimport type { UIFieldClientProps } from 'payload'\n\nimport { CopyToClipboard, FieldLabel, useFormFields } from '@payloadcms/ui'\nimport React from 'react'\n\nimport './index.css'\n\nconst baseClass = 'link-to-doc'\n\nexport const LinkToDoc: React.FC<UIFieldClientProps> = (props) => {\n const {\n field: { admin: { custom = {} } = {} },\n } = props\n const { isTestKey, nameOfIDField, stripeResourceType } = custom\n\n const field = useFormFields(([fields]) => (fields && fields?.[nameOfIDField]) || null)\n const { value: stripeID } = field || {}\n\n if (!stripeID) {\n return null\n }\n\n const stripeEnv = isTestKey ? 'test/' : ''\n const href = `https://dashboard.stripe.com/${stripeEnv}${stripeResourceType}/${stripeID}`\n\n return (\n <div className={baseClass}>\n <div className={`${baseClass}__header`}>\n <FieldLabel htmlFor={baseClass} label=\"View in Stripe\" />\n <CopyToClipboard value={href} />\n </div>\n <div className={`${baseClass}__url`}>\n <a href={href} rel=\"noopener noreferrer\" target=\"_blank\">\n {href}\n </a>\n </div>\n </div>\n )\n}\n"],"names":["CopyToClipboard","FieldLabel","useFormFields","React","baseClass","LinkToDoc","props","field","admin","custom","isTestKey","nameOfIDField","stripeResourceType","fields","value","stripeID","stripeEnv","href","div","className","htmlFor","label","a","rel","target"],"mappings":"AAAA;;AAGA,SAASA,eAAe,EAAEC,UAAU,EAAEC,aAAa,QAAQ,iBAAgB;AAC3E,OAAOC,WAAW,QAAO;AAEzB,OAAO,cAAa;AAEpB,MAAMC,YAAY;AAElB,OAAO,MAAMC,YAA0C,CAACC;IACtD,MAAM,EACJC,OAAO,EAAEC,OAAO,EAAEC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,EACvC,GAAGH;IACJ,MAAM,EAAEI,SAAS,EAAEC,aAAa,EAAEC,kBAAkB,EAAE,GAAGH;IAEzD,MAAMF,QAAQL,cAAc,CAAC,CAACW,OAAO,GAAK,AAACA,UAAUA,QAAQ,CAACF,cAAc,IAAK;IACjF,MAAM,EAAEG,OAAOC,QAAQ,EAAE,GAAGR,SAAS,CAAC;IAEtC,IAAI,CAACQ,UAAU;QACb,OAAO;IACT;IAEA,MAAMC,YAAYN,YAAY,UAAU;IACxC,MAAMO,OAAO,CAAC,6BAA6B,EAAED,YAAYJ,mBAAmB,CAAC,EAAEG,UAAU;IAEzF,qBACE,MAACG;QAAIC,WAAWf;;0BACd,MAACc;gBAAIC,WAAW,GAAGf,UAAU,QAAQ,CAAC;;kCACpC,KAACH;wBAAWmB,SAAShB;wBAAWiB,OAAM;;kCACtC,KAACrB;wBAAgBc,OAAOG;;;;0BAE1B,KAACC;gBAAIC,WAAW,GAAGf,UAAU,KAAK,CAAC;0BACjC,cAAA,KAACkB;oBAAEL,MAAMA;oBAAMM,KAAI;oBAAsBC,QAAO;8BAC7CP;;;;;AAKX,EAAC"}
|
|
@@ -3,6 +3,6 @@ export declare const deepen: (obj: Record<string, any>) => Record<string, any>;
|
|
|
3
3
|
export declare const getSyncedFields: ({ data, fields, source, }: {
|
|
4
4
|
data: object;
|
|
5
5
|
fields: FieldSyncConfig[];
|
|
6
|
-
source:
|
|
6
|
+
source: 'payload' | 'stripe';
|
|
7
7
|
}) => Record<string, unknown>;
|
|
8
8
|
//# sourceMappingURL=deepen.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleCreatedOrUpdated.d.ts","sourceRoot":"","sources":["../../src/webhooks/handleCreatedOrUpdated.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAIpF,KAAK,sBAAsB,GAAG,CAC5B,IAAI,EAAE;IACJ,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,2BAA2B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;CACnD,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,KACpC,OAAO,CAAC,IAAI,CAAC,CAAA;AAElB,eAAO,MAAM,sBAAsB,EAAE,
|
|
1
|
+
{"version":3,"file":"handleCreatedOrUpdated.d.ts","sourceRoot":"","sources":["../../src/webhooks/handleCreatedOrUpdated.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAIpF,KAAK,sBAAsB,GAAG,CAC5B,IAAI,EAAE;IACJ,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,2BAA2B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;CACnD,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,KACpC,OAAO,CAAC,IAAI,CAAC,CAAA;AAElB,eAAO,MAAM,sBAAsB,EAAE,sBA0MpC,CAAA"}
|
|
@@ -28,6 +28,7 @@ export const handleCreatedOrUpdated = async (args)=>{
|
|
|
28
28
|
const payloadQuery = await payload.find({
|
|
29
29
|
collection: collectionSlug,
|
|
30
30
|
limit: 1,
|
|
31
|
+
overrideAccess: true,
|
|
31
32
|
pagination: false,
|
|
32
33
|
where: {
|
|
33
34
|
stripeID: {
|
|
@@ -59,6 +60,7 @@ export const handleCreatedOrUpdated = async (args)=>{
|
|
|
59
60
|
const authQuery = await payload.find({
|
|
60
61
|
collection: collectionSlug,
|
|
61
62
|
limit: 1,
|
|
63
|
+
overrideAccess: true,
|
|
62
64
|
pagination: false,
|
|
63
65
|
where: {
|
|
64
66
|
email: {
|
|
@@ -76,7 +78,8 @@ export const handleCreatedOrUpdated = async (args)=>{
|
|
|
76
78
|
await payload.update({
|
|
77
79
|
id: authDoc.id,
|
|
78
80
|
collection: collectionSlug,
|
|
79
|
-
data: syncedData
|
|
81
|
+
data: syncedData,
|
|
82
|
+
overrideAccess: true
|
|
80
83
|
});
|
|
81
84
|
if (logs) {
|
|
82
85
|
payload.logger.info(`✅ Successfully updated '${collectionSlug}' document in Payload with ID: '${authDoc.id}.'`);
|
|
@@ -114,7 +117,8 @@ export const handleCreatedOrUpdated = async (args)=>{
|
|
|
114
117
|
password,
|
|
115
118
|
passwordConfirm: password
|
|
116
119
|
},
|
|
117
|
-
disableVerificationEmail: isAuthCollection ? true : undefined
|
|
120
|
+
disableVerificationEmail: isAuthCollection ? true : undefined,
|
|
121
|
+
overrideAccess: true
|
|
118
122
|
});
|
|
119
123
|
if (logs) {
|
|
120
124
|
payload.logger.info(`✅ Successfully created new '${collectionSlug}' document in Payload with Stripe ID: '${stripeID}'.`);
|
|
@@ -134,7 +138,8 @@ export const handleCreatedOrUpdated = async (args)=>{
|
|
|
134
138
|
await payload.update({
|
|
135
139
|
id: foundDoc.id,
|
|
136
140
|
collection: collectionSlug,
|
|
137
|
-
data: syncedData
|
|
141
|
+
data: syncedData,
|
|
142
|
+
overrideAccess: true
|
|
138
143
|
});
|
|
139
144
|
if (logs) {
|
|
140
145
|
payload.logger.info(`✅ Successfully updated '${collectionSlug}' document in Payload from Stripe ID: '${stripeID}'.`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/webhooks/handleCreatedOrUpdated.ts"],"sourcesContent":["import { v4 as uuid } from 'uuid'\n\nimport type { SanitizedStripePluginConfig, StripeWebhookHandler } from '../types.js'\n\nimport { deepen, getSyncedFields } from '../utilities/deepen.js'\n\ntype HandleCreatedOrUpdated = (\n args: {\n resourceType: string\n syncConfig: SanitizedStripePluginConfig['sync'][0]\n } & Parameters<StripeWebhookHandler>[0],\n) => Promise<void>\n\nexport const handleCreatedOrUpdated: HandleCreatedOrUpdated = async (args) => {\n const { config: payloadConfig, event, payload, pluginConfig, resourceType, syncConfig } = args\n\n const { logs } = pluginConfig || {}\n\n const stripeDoc: any = event?.data?.object || {}\n\n const { id: stripeID, object: eventObject } = stripeDoc\n\n // NOTE: the Stripe API does not nest fields, everything is an object at the top level\n // if the event object and resource type don't match, this change was not top-level\n const isNestedChange = eventObject !== resourceType\n\n // let stripeID = docID;\n // if (isNestedChange) {\n // const parentResource = stripeDoc[resourceType];\n // stripeID = parentResource;\n // }\n\n if (isNestedChange) {\n if (logs) {\n payload.logger.info(\n `- This change occurred on a nested field of ${resourceType}. Nested fields are not yet supported in auto-sync but can be manually setup.`,\n )\n }\n }\n\n if (!isNestedChange) {\n if (logs) {\n payload.logger.info(\n `- A new document was created or updated in Stripe, now syncing to Payload...`,\n )\n }\n\n const collectionSlug = syncConfig?.collection\n\n const isAuthCollection = Boolean(\n payloadConfig?.collections?.find((collection) => collection.slug === collectionSlug)?.auth,\n )\n\n // First, search for an existing document in Payload\n const payloadQuery = await payload.find({\n collection: collectionSlug,\n limit: 1,\n pagination: false,\n where: {\n stripeID: {\n equals: stripeID,\n },\n },\n })\n\n const foundDoc = payloadQuery.docs[0] as any\n\n // combine all properties of the Stripe doc and match their respective fields within the document\n let syncedData = getSyncedFields({\n data: stripeDoc,\n fields: syncConfig.fields,\n source: 'stripe',\n })\n\n syncedData = deepen({\n ...syncedData,\n skipSync: true,\n stripeID,\n })\n\n if (!foundDoc) {\n if (logs) {\n payload.logger.info(\n `- No existing '${collectionSlug}' document found with Stripe ID: '${stripeID}', creating new...`,\n )\n }\n\n // auth docs must use unique emails\n let authDoc = null\n\n if (isAuthCollection) {\n try {\n if (stripeDoc?.email) {\n const authQuery = await payload.find({\n collection: collectionSlug,\n limit: 1,\n pagination: false,\n where: {\n email: {\n equals: stripeDoc.email,\n },\n },\n })\n\n authDoc = authQuery.docs[0] as any\n\n if (authDoc) {\n if (logs) {\n payload.logger.info(\n `- Account already exists with e-mail: ${stripeDoc.email}, updating now...`,\n )\n }\n\n // account exists by email, so update it instead\n try {\n await payload.update({\n id: authDoc.id,\n collection: collectionSlug,\n data: syncedData,\n })\n\n if (logs) {\n payload.logger.info(\n `✅ Successfully updated '${collectionSlug}' document in Payload with ID: '${authDoc.id}.'`,\n )\n }\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : err\n if (logs) {\n payload.logger.error(\n `- Error updating existing '${collectionSlug}' document: ${msg}`,\n )\n }\n }\n }\n } else {\n if (logs) {\n payload.logger.error(\n `No email was provided from Stripe, cannot create new '${collectionSlug}' document.`,\n )\n }\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : error\n if (logs) {\n payload.logger.error(`Error looking up '${collectionSlug}' document in Payload: ${msg}`)\n }\n }\n }\n\n if (!isAuthCollection || (isAuthCollection && !authDoc)) {\n try {\n if (logs) {\n payload.logger.info(\n `- Creating new '${collectionSlug}' document in Payload with Stripe ID: '${stripeID}'.`,\n )\n }\n\n // generate a strong, unique password for the new user\n const password: string = uuid()\n\n await payload.create({\n collection: collectionSlug,\n data: {\n ...syncedData,\n password,\n passwordConfirm: password,\n },\n disableVerificationEmail: isAuthCollection ? true : undefined,\n })\n\n if (logs) {\n payload.logger.info(\n `✅ Successfully created new '${collectionSlug}' document in Payload with Stripe ID: '${stripeID}'.`,\n )\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : error\n if (logs) {\n payload.logger.error(`Error creating new document in Payload: ${msg}`)\n }\n }\n }\n } else {\n if (logs) {\n payload.logger.info(\n `- Existing '${collectionSlug}' document found in Payload with Stripe ID: '${stripeID}', updating now...`,\n )\n }\n\n try {\n await payload.update({\n id: foundDoc.id,\n collection: collectionSlug,\n data: syncedData,\n })\n\n if (logs) {\n payload.logger.info(\n `✅ Successfully updated '${collectionSlug}' document in Payload from Stripe ID: '${stripeID}'.`,\n )\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : error\n if (logs) {\n payload.logger.error(`Error updating '${collectionSlug}' document in Payload: ${msg}`)\n }\n }\n }\n }\n}\n"],"names":["v4","uuid","deepen","getSyncedFields","handleCreatedOrUpdated","args","config","payloadConfig","event","payload","pluginConfig","resourceType","syncConfig","logs","stripeDoc","data","object","id","stripeID","eventObject","isNestedChange","logger","info","collectionSlug","collection","isAuthCollection","Boolean","collections","find","slug","auth","payloadQuery","limit","pagination","where","equals","foundDoc","docs","syncedData","fields","source","skipSync","authDoc","email","authQuery","update","err","msg","Error","message","error","password","create","passwordConfirm","disableVerificationEmail","undefined"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/webhooks/handleCreatedOrUpdated.ts"],"sourcesContent":["import { v4 as uuid } from 'uuid'\n\nimport type { SanitizedStripePluginConfig, StripeWebhookHandler } from '../types.js'\n\nimport { deepen, getSyncedFields } from '../utilities/deepen.js'\n\ntype HandleCreatedOrUpdated = (\n args: {\n resourceType: string\n syncConfig: SanitizedStripePluginConfig['sync'][0]\n } & Parameters<StripeWebhookHandler>[0],\n) => Promise<void>\n\nexport const handleCreatedOrUpdated: HandleCreatedOrUpdated = async (args) => {\n const { config: payloadConfig, event, payload, pluginConfig, resourceType, syncConfig } = args\n\n const { logs } = pluginConfig || {}\n\n const stripeDoc: any = event?.data?.object || {}\n\n const { id: stripeID, object: eventObject } = stripeDoc\n\n // NOTE: the Stripe API does not nest fields, everything is an object at the top level\n // if the event object and resource type don't match, this change was not top-level\n const isNestedChange = eventObject !== resourceType\n\n // let stripeID = docID;\n // if (isNestedChange) {\n // const parentResource = stripeDoc[resourceType];\n // stripeID = parentResource;\n // }\n\n if (isNestedChange) {\n if (logs) {\n payload.logger.info(\n `- This change occurred on a nested field of ${resourceType}. Nested fields are not yet supported in auto-sync but can be manually setup.`,\n )\n }\n }\n\n if (!isNestedChange) {\n if (logs) {\n payload.logger.info(\n `- A new document was created or updated in Stripe, now syncing to Payload...`,\n )\n }\n\n const collectionSlug = syncConfig?.collection\n\n const isAuthCollection = Boolean(\n payloadConfig?.collections?.find((collection) => collection.slug === collectionSlug)?.auth,\n )\n\n // First, search for an existing document in Payload\n const payloadQuery = await payload.find({\n collection: collectionSlug,\n limit: 1,\n overrideAccess: true,\n pagination: false,\n where: {\n stripeID: {\n equals: stripeID,\n },\n },\n })\n\n const foundDoc = payloadQuery.docs[0] as any\n\n // combine all properties of the Stripe doc and match their respective fields within the document\n let syncedData = getSyncedFields({\n data: stripeDoc,\n fields: syncConfig.fields,\n source: 'stripe',\n })\n\n syncedData = deepen({\n ...syncedData,\n skipSync: true,\n stripeID,\n })\n\n if (!foundDoc) {\n if (logs) {\n payload.logger.info(\n `- No existing '${collectionSlug}' document found with Stripe ID: '${stripeID}', creating new...`,\n )\n }\n\n // auth docs must use unique emails\n let authDoc = null\n\n if (isAuthCollection) {\n try {\n if (stripeDoc?.email) {\n const authQuery = await payload.find({\n collection: collectionSlug,\n limit: 1,\n overrideAccess: true,\n pagination: false,\n where: {\n email: {\n equals: stripeDoc.email,\n },\n },\n })\n\n authDoc = authQuery.docs[0] as any\n\n if (authDoc) {\n if (logs) {\n payload.logger.info(\n `- Account already exists with e-mail: ${stripeDoc.email}, updating now...`,\n )\n }\n\n // account exists by email, so update it instead\n try {\n await payload.update({\n id: authDoc.id,\n collection: collectionSlug,\n data: syncedData,\n overrideAccess: true,\n })\n\n if (logs) {\n payload.logger.info(\n `✅ Successfully updated '${collectionSlug}' document in Payload with ID: '${authDoc.id}.'`,\n )\n }\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : err\n if (logs) {\n payload.logger.error(\n `- Error updating existing '${collectionSlug}' document: ${msg}`,\n )\n }\n }\n }\n } else {\n if (logs) {\n payload.logger.error(\n `No email was provided from Stripe, cannot create new '${collectionSlug}' document.`,\n )\n }\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : error\n if (logs) {\n payload.logger.error(`Error looking up '${collectionSlug}' document in Payload: ${msg}`)\n }\n }\n }\n\n if (!isAuthCollection || (isAuthCollection && !authDoc)) {\n try {\n if (logs) {\n payload.logger.info(\n `- Creating new '${collectionSlug}' document in Payload with Stripe ID: '${stripeID}'.`,\n )\n }\n\n // generate a strong, unique password for the new user\n const password: string = uuid()\n\n await payload.create({\n collection: collectionSlug,\n data: {\n ...syncedData,\n password,\n passwordConfirm: password,\n },\n disableVerificationEmail: isAuthCollection ? true : undefined,\n overrideAccess: true,\n })\n\n if (logs) {\n payload.logger.info(\n `✅ Successfully created new '${collectionSlug}' document in Payload with Stripe ID: '${stripeID}'.`,\n )\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : error\n if (logs) {\n payload.logger.error(`Error creating new document in Payload: ${msg}`)\n }\n }\n }\n } else {\n if (logs) {\n payload.logger.info(\n `- Existing '${collectionSlug}' document found in Payload with Stripe ID: '${stripeID}', updating now...`,\n )\n }\n\n try {\n await payload.update({\n id: foundDoc.id,\n collection: collectionSlug,\n data: syncedData,\n overrideAccess: true,\n })\n\n if (logs) {\n payload.logger.info(\n `✅ Successfully updated '${collectionSlug}' document in Payload from Stripe ID: '${stripeID}'.`,\n )\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : error\n if (logs) {\n payload.logger.error(`Error updating '${collectionSlug}' document in Payload: ${msg}`)\n }\n }\n }\n }\n}\n"],"names":["v4","uuid","deepen","getSyncedFields","handleCreatedOrUpdated","args","config","payloadConfig","event","payload","pluginConfig","resourceType","syncConfig","logs","stripeDoc","data","object","id","stripeID","eventObject","isNestedChange","logger","info","collectionSlug","collection","isAuthCollection","Boolean","collections","find","slug","auth","payloadQuery","limit","overrideAccess","pagination","where","equals","foundDoc","docs","syncedData","fields","source","skipSync","authDoc","email","authQuery","update","err","msg","Error","message","error","password","create","passwordConfirm","disableVerificationEmail","undefined"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleDeleted.d.ts","sourceRoot":"","sources":["../../src/webhooks/handleDeleted.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAEpF,KAAK,aAAa,GAAG,CACnB,IAAI,EAAE;IACJ,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,2BAA2B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;CACnD,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,KACpC,OAAO,CAAC,IAAI,CAAC,CAAA;AAElB,eAAO,MAAM,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"handleDeleted.d.ts","sourceRoot":"","sources":["../../src/webhooks/handleDeleted.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAEpF,KAAK,aAAa,GAAG,CACnB,IAAI,EAAE;IACJ,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,2BAA2B,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;CACnD,GAAG,UAAU,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,KACpC,OAAO,CAAC,IAAI,CAAC,CAAA;AAElB,eAAO,MAAM,aAAa,EAAE,aAuF3B,CAAA"}
|
|
@@ -18,6 +18,7 @@ export const handleDeleted = async (args)=>{
|
|
|
18
18
|
const payloadQuery = await payload.find({
|
|
19
19
|
collection: collectionSlug,
|
|
20
20
|
limit: 1,
|
|
21
|
+
overrideAccess: true,
|
|
21
22
|
pagination: false,
|
|
22
23
|
where: {
|
|
23
24
|
stripeID: {
|
|
@@ -39,7 +40,8 @@ export const handleDeleted = async (args)=>{
|
|
|
39
40
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
40
41
|
payload.delete({
|
|
41
42
|
id: foundDoc.id,
|
|
42
|
-
collection: collectionSlug
|
|
43
|
+
collection: collectionSlug,
|
|
44
|
+
overrideAccess: true
|
|
43
45
|
});
|
|
44
46
|
// NOTE: the `afterDelete` hook will trigger, which will attempt to delete the document from Stripe and safely error out
|
|
45
47
|
// There is no known way of preventing this from happening. In other hooks we use the `skipSync` field, but here the document is already deleted.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/webhooks/handleDeleted.ts"],"sourcesContent":["import type { SanitizedStripePluginConfig, StripeWebhookHandler } from '../types.js'\n\ntype HandleDeleted = (\n args: {\n resourceType: string\n syncConfig: SanitizedStripePluginConfig['sync'][0]\n } & Parameters<StripeWebhookHandler>[0],\n) => Promise<void>\n\nexport const handleDeleted: HandleDeleted = async (args) => {\n const { event, payload, pluginConfig, resourceType, syncConfig } = args\n\n const { logs } = pluginConfig || {}\n\n const collectionSlug = syncConfig?.collection\n\n const {\n id: stripeID,\n object: eventObject, // use this to determine if this is a nested field\n }: any = event?.data?.object || {}\n\n // if the event object and resource type don't match, this deletion was not top-level\n const isNestedDelete = eventObject !== resourceType\n\n if (isNestedDelete) {\n if (logs) {\n payload.logger.info(\n `- This deletion occurred on a nested field of ${resourceType}. Nested fields are not yet supported.`,\n )\n }\n }\n\n if (!isNestedDelete) {\n if (logs) {\n payload.logger.info(\n `- A '${resourceType}' resource was deleted in Stripe, now deleting '${collectionSlug}' document in Payload with Stripe ID: '${stripeID}'...`,\n )\n }\n\n try {\n const payloadQuery = await payload.find({\n collection: collectionSlug,\n limit: 1,\n pagination: false,\n where: {\n stripeID: {\n equals: stripeID,\n },\n },\n })\n\n const foundDoc = payloadQuery.docs[0] as any\n\n if (!foundDoc) {\n if (logs) {\n payload.logger.info(\n `- Nothing to delete, no existing document found with Stripe ID: '${stripeID}'.`,\n )\n }\n }\n\n if (foundDoc) {\n if (logs) {\n payload.logger.info(`- Deleting Payload document with ID: '${foundDoc.id}'...`)\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n payload.delete({\n id: foundDoc.id,\n collection: collectionSlug,\n })\n\n // NOTE: the `afterDelete` hook will trigger, which will attempt to delete the document from Stripe and safely error out\n // There is no known way of preventing this from happening. In other hooks we use the `skipSync` field, but here the document is already deleted.\n if (logs) {\n payload.logger.info(\n `- ✅ Successfully deleted Payload document with ID: '${foundDoc.id}'.`,\n )\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : error\n if (logs) {\n payload.logger.error(`Error deleting document: ${msg}`)\n }\n }\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : error\n if (logs) {\n payload.logger.error(`Error deleting document: ${msg}`)\n }\n }\n }\n}\n"],"names":["handleDeleted","args","event","payload","pluginConfig","resourceType","syncConfig","logs","collectionSlug","collection","id","stripeID","object","eventObject","data","isNestedDelete","logger","info","payloadQuery","find","limit","pagination","where","equals","foundDoc","docs","delete","error","msg","Error","message"],"mappings":"AASA,OAAO,MAAMA,gBAA+B,OAAOC;IACjD,MAAM,EAAEC,KAAK,EAAEC,OAAO,EAAEC,YAAY,EAAEC,YAAY,EAAEC,UAAU,EAAE,GAAGL;IAEnE,MAAM,EAAEM,IAAI,EAAE,GAAGH,gBAAgB,CAAC;IAElC,MAAMI,iBAAiBF,YAAYG;IAEnC,MAAM,EACJC,IAAIC,QAAQ,EACZC,QAAQC,WAAW,EACpB,GAAQX,OAAOY,MAAMF,UAAU,CAAC;IAEjC,qFAAqF;IACrF,MAAMG,iBAAiBF,gBAAgBR;IAEvC,IAAIU,gBAAgB;QAClB,IAAIR,MAAM;YACRJ,QAAQa,MAAM,CAACC,IAAI,CACjB,CAAC,8CAA8C,EAAEZ,aAAa,sCAAsC,CAAC;QAEzG;IACF;IAEA,IAAI,CAACU,gBAAgB;QACnB,IAAIR,MAAM;YACRJ,QAAQa,MAAM,CAACC,IAAI,CACjB,CAAC,KAAK,EAAEZ,aAAa,gDAAgD,EAAEG,eAAe,uCAAuC,EAAEG,SAAS,IAAI,CAAC;QAEjJ;QAEA,IAAI;YACF,MAAMO,eAAe,MAAMf,QAAQgB,IAAI,CAAC;gBACtCV,YAAYD;gBACZY,OAAO;gBACPC,YAAY;gBACZC,OAAO;
|
|
1
|
+
{"version":3,"sources":["../../src/webhooks/handleDeleted.ts"],"sourcesContent":["import type { SanitizedStripePluginConfig, StripeWebhookHandler } from '../types.js'\n\ntype HandleDeleted = (\n args: {\n resourceType: string\n syncConfig: SanitizedStripePluginConfig['sync'][0]\n } & Parameters<StripeWebhookHandler>[0],\n) => Promise<void>\n\nexport const handleDeleted: HandleDeleted = async (args) => {\n const { event, payload, pluginConfig, resourceType, syncConfig } = args\n\n const { logs } = pluginConfig || {}\n\n const collectionSlug = syncConfig?.collection\n\n const {\n id: stripeID,\n object: eventObject, // use this to determine if this is a nested field\n }: any = event?.data?.object || {}\n\n // if the event object and resource type don't match, this deletion was not top-level\n const isNestedDelete = eventObject !== resourceType\n\n if (isNestedDelete) {\n if (logs) {\n payload.logger.info(\n `- This deletion occurred on a nested field of ${resourceType}. Nested fields are not yet supported.`,\n )\n }\n }\n\n if (!isNestedDelete) {\n if (logs) {\n payload.logger.info(\n `- A '${resourceType}' resource was deleted in Stripe, now deleting '${collectionSlug}' document in Payload with Stripe ID: '${stripeID}'...`,\n )\n }\n\n try {\n const payloadQuery = await payload.find({\n collection: collectionSlug,\n limit: 1,\n overrideAccess: true,\n pagination: false,\n where: {\n stripeID: {\n equals: stripeID,\n },\n },\n })\n\n const foundDoc = payloadQuery.docs[0] as any\n\n if (!foundDoc) {\n if (logs) {\n payload.logger.info(\n `- Nothing to delete, no existing document found with Stripe ID: '${stripeID}'.`,\n )\n }\n }\n\n if (foundDoc) {\n if (logs) {\n payload.logger.info(`- Deleting Payload document with ID: '${foundDoc.id}'...`)\n }\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n payload.delete({\n id: foundDoc.id,\n collection: collectionSlug,\n overrideAccess: true,\n })\n\n // NOTE: the `afterDelete` hook will trigger, which will attempt to delete the document from Stripe and safely error out\n // There is no known way of preventing this from happening. In other hooks we use the `skipSync` field, but here the document is already deleted.\n if (logs) {\n payload.logger.info(\n `- ✅ Successfully deleted Payload document with ID: '${foundDoc.id}'.`,\n )\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : error\n if (logs) {\n payload.logger.error(`Error deleting document: ${msg}`)\n }\n }\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : error\n if (logs) {\n payload.logger.error(`Error deleting document: ${msg}`)\n }\n }\n }\n}\n"],"names":["handleDeleted","args","event","payload","pluginConfig","resourceType","syncConfig","logs","collectionSlug","collection","id","stripeID","object","eventObject","data","isNestedDelete","logger","info","payloadQuery","find","limit","overrideAccess","pagination","where","equals","foundDoc","docs","delete","error","msg","Error","message"],"mappings":"AASA,OAAO,MAAMA,gBAA+B,OAAOC;IACjD,MAAM,EAAEC,KAAK,EAAEC,OAAO,EAAEC,YAAY,EAAEC,YAAY,EAAEC,UAAU,EAAE,GAAGL;IAEnE,MAAM,EAAEM,IAAI,EAAE,GAAGH,gBAAgB,CAAC;IAElC,MAAMI,iBAAiBF,YAAYG;IAEnC,MAAM,EACJC,IAAIC,QAAQ,EACZC,QAAQC,WAAW,EACpB,GAAQX,OAAOY,MAAMF,UAAU,CAAC;IAEjC,qFAAqF;IACrF,MAAMG,iBAAiBF,gBAAgBR;IAEvC,IAAIU,gBAAgB;QAClB,IAAIR,MAAM;YACRJ,QAAQa,MAAM,CAACC,IAAI,CACjB,CAAC,8CAA8C,EAAEZ,aAAa,sCAAsC,CAAC;QAEzG;IACF;IAEA,IAAI,CAACU,gBAAgB;QACnB,IAAIR,MAAM;YACRJ,QAAQa,MAAM,CAACC,IAAI,CACjB,CAAC,KAAK,EAAEZ,aAAa,gDAAgD,EAAEG,eAAe,uCAAuC,EAAEG,SAAS,IAAI,CAAC;QAEjJ;QAEA,IAAI;YACF,MAAMO,eAAe,MAAMf,QAAQgB,IAAI,CAAC;gBACtCV,YAAYD;gBACZY,OAAO;gBACPC,gBAAgB;gBAChBC,YAAY;gBACZC,OAAO;oBACLZ,UAAU;wBACRa,QAAQb;oBACV;gBACF;YACF;YAEA,MAAMc,WAAWP,aAAaQ,IAAI,CAAC,EAAE;YAErC,IAAI,CAACD,UAAU;gBACb,IAAIlB,MAAM;oBACRJ,QAAQa,MAAM,CAACC,IAAI,CACjB,CAAC,iEAAiE,EAAEN,SAAS,EAAE,CAAC;gBAEpF;YACF;YAEA,IAAIc,UAAU;gBACZ,IAAIlB,MAAM;oBACRJ,QAAQa,MAAM,CAACC,IAAI,CAAC,CAAC,sCAAsC,EAAEQ,SAASf,EAAE,CAAC,IAAI,CAAC;gBAChF;gBAEA,IAAI;oBACF,mEAAmE;oBACnEP,QAAQwB,MAAM,CAAC;wBACbjB,IAAIe,SAASf,EAAE;wBACfD,YAAYD;wBACZa,gBAAgB;oBAClB;oBAEA,wHAAwH;oBACxH,iJAAiJ;oBACjJ,IAAId,MAAM;wBACRJ,QAAQa,MAAM,CAACC,IAAI,CACjB,CAAC,oDAAoD,EAAEQ,SAASf,EAAE,CAAC,EAAE,CAAC;oBAE1E;gBACF,EAAE,OAAOkB,OAAgB;oBACvB,MAAMC,MAAMD,iBAAiBE,QAAQF,MAAMG,OAAO,GAAGH;oBACrD,IAAIrB,MAAM;wBACRJ,QAAQa,MAAM,CAACY,KAAK,CAAC,CAAC,yBAAyB,EAAEC,KAAK;oBACxD;gBACF;YACF;QACF,EAAE,OAAOD,OAAgB;YACvB,MAAMC,MAAMD,iBAAiBE,QAAQF,MAAMG,OAAO,GAAGH;YACrD,IAAIrB,MAAM;gBACRJ,QAAQa,MAAM,CAACY,KAAK,CAAC,CAAC,yBAAyB,EAAEC,KAAK;YACxD;QACF;IACF;AACF,EAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/plugin-stripe",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-beta.0",
|
|
4
4
|
"description": "Stripe plugin for Payload",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"payload",
|
|
@@ -54,20 +54,20 @@
|
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"lodash.get": "^4.4.2",
|
|
56
56
|
"stripe": "^10.2.0",
|
|
57
|
-
"uuid": "
|
|
58
|
-
"@payloadcms/translations": "
|
|
59
|
-
"@payloadcms/ui": "
|
|
57
|
+
"uuid": "14.0.0",
|
|
58
|
+
"@payloadcms/translations": "4.0.0-beta.0",
|
|
59
|
+
"@payloadcms/ui": "4.0.0-beta.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@types/lodash.get": "^4.4.7",
|
|
63
|
-
"@types/react": "19.
|
|
64
|
-
"@types/react-dom": "19.
|
|
63
|
+
"@types/react": "19.3.0",
|
|
64
|
+
"@types/react-dom": "19.3.0",
|
|
65
65
|
"@payloadcms/eslint-config": "3.28.0",
|
|
66
|
-
"@payloadcms/next": "
|
|
67
|
-
"payload": "
|
|
66
|
+
"@payloadcms/next": "4.0.0-beta.0",
|
|
67
|
+
"payload": "4.0.0-beta.0"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
|
-
"payload": "
|
|
70
|
+
"payload": "4.0.0-beta.0"
|
|
71
71
|
},
|
|
72
72
|
"publishConfig": {
|
|
73
73
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
|
|
80
80
|
"build:types": "tsc --emitDeclarationOnly --outDir dist",
|
|
81
81
|
"clean": "rimraf -g {dist,*.tsbuildinfo}",
|
|
82
|
-
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
|
|
82
|
+
"copyfiles": "copyfiles -u 1 -e \"**/*.spec.*\" \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
|
|
83
83
|
"lint": "eslint .",
|
|
84
84
|
"lint:fix": "eslint . --fix"
|
|
85
85
|
}
|
package/dist/index.spec.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
const mocks = vi.hoisted(()=>({
|
|
3
|
-
stripeREST: vi.fn()
|
|
4
|
-
}));
|
|
5
|
-
vi.mock('./routes/rest.js', ()=>({
|
|
6
|
-
stripeREST: mocks.stripeREST
|
|
7
|
-
}));
|
|
8
|
-
import { stripePlugin } from './index.js';
|
|
9
|
-
const createBaseConfig = ()=>({
|
|
10
|
-
collections: []
|
|
11
|
-
});
|
|
12
|
-
describe('stripePlugin REST endpoint registration', ()=>{
|
|
13
|
-
beforeEach(()=>{
|
|
14
|
-
vi.clearAllMocks();
|
|
15
|
-
mocks.stripeREST.mockResolvedValue(Response.json({}, {
|
|
16
|
-
status: 405
|
|
17
|
-
}));
|
|
18
|
-
});
|
|
19
|
-
// Mutation caught: restoring the legacy `rest: true` configuration without an explicit allowlist.
|
|
20
|
-
it('should reject the legacy true configuration', ()=>{
|
|
21
|
-
expect(()=>stripePlugin({
|
|
22
|
-
// @ts-expect-error -- `true` is intentionally rejected in every supported release line.
|
|
23
|
-
rest: true,
|
|
24
|
-
stripeSecretKey: 'sk_test_example'
|
|
25
|
-
})(createBaseConfig())).toThrow('non-empty allowedMethods');
|
|
26
|
-
expect(mocks.stripeREST).not.toHaveBeenCalled();
|
|
27
|
-
});
|
|
28
|
-
// Mutation caught: only registering the endpoint for the legacy boolean form.
|
|
29
|
-
it('should register an object-configured endpoint with its exact allowlist', async ()=>{
|
|
30
|
-
const transformedConfig = stripePlugin({
|
|
31
|
-
rest: {
|
|
32
|
-
allowedMethods: [
|
|
33
|
-
'customers.list'
|
|
34
|
-
]
|
|
35
|
-
},
|
|
36
|
-
stripeSecretKey: 'sk_test_example'
|
|
37
|
-
})(createBaseConfig());
|
|
38
|
-
const endpoint = transformedConfig.endpoints?.find(({ path })=>path === '/stripe/rest');
|
|
39
|
-
const req = {};
|
|
40
|
-
await endpoint?.handler(req);
|
|
41
|
-
expect(endpoint).toMatchObject({
|
|
42
|
-
method: 'post',
|
|
43
|
-
path: '/stripe/rest'
|
|
44
|
-
});
|
|
45
|
-
expect(mocks.stripeREST).toHaveBeenCalledWith({
|
|
46
|
-
pluginConfig: expect.objectContaining({
|
|
47
|
-
rest: {
|
|
48
|
-
allowedMethods: [
|
|
49
|
-
'customers.list'
|
|
50
|
-
]
|
|
51
|
-
}
|
|
52
|
-
}),
|
|
53
|
-
req
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
// Mutation caught: registering the REST endpoint when its configuration is omitted.
|
|
57
|
-
it('should not register the REST endpoint when the option is absent', ()=>{
|
|
58
|
-
const transformedConfig = stripePlugin({
|
|
59
|
-
stripeSecretKey: 'sk_test_example'
|
|
60
|
-
})(createBaseConfig());
|
|
61
|
-
expect(transformedConfig.endpoints?.filter(({ path })=>path === '/stripe/rest')).toEqual([]);
|
|
62
|
-
});
|
|
63
|
-
// Mutation caught: removing fail-closed runtime handling for untyped configurations.
|
|
64
|
-
it('should treat false from an untyped configuration as disabled', ()=>{
|
|
65
|
-
const transformedConfig = stripePlugin({
|
|
66
|
-
// @ts-expect-error -- omission is the supported way to disable the endpoint.
|
|
67
|
-
rest: false,
|
|
68
|
-
stripeSecretKey: 'sk_test_example'
|
|
69
|
-
})(createBaseConfig());
|
|
70
|
-
expect(transformedConfig.endpoints?.filter(({ path })=>path === '/stripe/rest')).toEqual([]);
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
describe('stripePlugin managed fields', ()=>{
|
|
74
|
-
it('should prevent API writes to Stripe-managed fields', ()=>{
|
|
75
|
-
const transformedConfig = stripePlugin({
|
|
76
|
-
stripeSecretKey: 'sk_test_example',
|
|
77
|
-
sync: [
|
|
78
|
-
{
|
|
79
|
-
collection: 'products',
|
|
80
|
-
fields: [],
|
|
81
|
-
stripeResourceType: 'products',
|
|
82
|
-
stripeResourceTypeSingular: 'product'
|
|
83
|
-
}
|
|
84
|
-
]
|
|
85
|
-
})({
|
|
86
|
-
collections: [
|
|
87
|
-
{
|
|
88
|
-
fields: [],
|
|
89
|
-
slug: 'products'
|
|
90
|
-
}
|
|
91
|
-
]
|
|
92
|
-
});
|
|
93
|
-
const fields = transformedConfig.collections?.[0]?.fields ?? [];
|
|
94
|
-
const stripeIDField = fields.find((field)=>'name' in field && field.name === 'stripeID');
|
|
95
|
-
const skipSyncField = fields.find((field)=>'name' in field && field.name === 'skipSync');
|
|
96
|
-
expect(stripeIDField).toMatchObject({
|
|
97
|
-
access: {
|
|
98
|
-
create: expect.any(Function),
|
|
99
|
-
update: expect.any(Function)
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
expect(skipSyncField).toMatchObject({
|
|
103
|
-
access: {
|
|
104
|
-
create: expect.any(Function),
|
|
105
|
-
update: expect.any(Function)
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
expect(stripeIDField?.access?.create?.({})).toBe(false);
|
|
109
|
-
expect(stripeIDField?.access?.update?.({})).toBe(false);
|
|
110
|
-
expect(skipSyncField?.access?.create?.({})).toBe(false);
|
|
111
|
-
expect(skipSyncField?.access?.update?.({})).toBe(false);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
//# sourceMappingURL=index.spec.js.map
|
package/dist/index.spec.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.spec.ts"],"sourcesContent":["import type { Config } from 'payload'\n\nimport { beforeEach, describe, expect, it, vi } from 'vitest'\n\nconst mocks = vi.hoisted(() => ({\n stripeREST: vi.fn(),\n}))\n\nvi.mock('./routes/rest.js', () => ({\n stripeREST: mocks.stripeREST,\n}))\n\nimport { stripePlugin } from './index.js'\n\nconst createBaseConfig = (): Config => ({ collections: [] })\n\ndescribe('stripePlugin REST endpoint registration', () => {\n beforeEach(() => {\n vi.clearAllMocks()\n mocks.stripeREST.mockResolvedValue(Response.json({}, { status: 405 }))\n })\n\n // Mutation caught: restoring the legacy `rest: true` configuration without an explicit allowlist.\n it('should reject the legacy true configuration', () => {\n expect(() =>\n stripePlugin({\n // @ts-expect-error -- `true` is intentionally rejected in every supported release line.\n rest: true,\n stripeSecretKey: 'sk_test_example',\n })(createBaseConfig()),\n ).toThrow('non-empty allowedMethods')\n\n expect(mocks.stripeREST).not.toHaveBeenCalled()\n })\n\n // Mutation caught: only registering the endpoint for the legacy boolean form.\n it('should register an object-configured endpoint with its exact allowlist', async () => {\n const transformedConfig = stripePlugin({\n rest: { allowedMethods: ['customers.list'] },\n stripeSecretKey: 'sk_test_example',\n })(createBaseConfig())\n const endpoint = transformedConfig.endpoints?.find(({ path }) => path === '/stripe/rest')\n const req = {} as Parameters<NonNullable<typeof endpoint>['handler']>[0]\n\n await endpoint?.handler(req)\n\n expect(endpoint).toMatchObject({ method: 'post', path: '/stripe/rest' })\n expect(mocks.stripeREST).toHaveBeenCalledWith({\n pluginConfig: expect.objectContaining({\n rest: { allowedMethods: ['customers.list'] },\n }),\n req,\n })\n })\n\n // Mutation caught: registering the REST endpoint when its configuration is omitted.\n it('should not register the REST endpoint when the option is absent', () => {\n const transformedConfig = stripePlugin({\n stripeSecretKey: 'sk_test_example',\n })(createBaseConfig())\n\n expect(transformedConfig.endpoints?.filter(({ path }) => path === '/stripe/rest')).toEqual([])\n })\n\n // Mutation caught: removing fail-closed runtime handling for untyped configurations.\n it('should treat false from an untyped configuration as disabled', () => {\n const transformedConfig = stripePlugin({\n // @ts-expect-error -- omission is the supported way to disable the endpoint.\n rest: false,\n stripeSecretKey: 'sk_test_example',\n })(createBaseConfig())\n\n expect(transformedConfig.endpoints?.filter(({ path }) => path === '/stripe/rest')).toEqual([])\n })\n})\n\ndescribe('stripePlugin managed fields', () => {\n it('should prevent API writes to Stripe-managed fields', () => {\n const transformedConfig = stripePlugin({\n stripeSecretKey: 'sk_test_example',\n sync: [\n {\n collection: 'products',\n fields: [],\n stripeResourceType: 'products',\n stripeResourceTypeSingular: 'product',\n },\n ],\n })({\n collections: [\n {\n fields: [],\n slug: 'products',\n },\n ],\n })\n const fields = transformedConfig.collections?.[0]?.fields ?? []\n const stripeIDField = fields.find((field) => 'name' in field && field.name === 'stripeID')\n const skipSyncField = fields.find((field) => 'name' in field && field.name === 'skipSync')\n\n expect(stripeIDField).toMatchObject({\n access: { create: expect.any(Function), update: expect.any(Function) },\n })\n expect(skipSyncField).toMatchObject({\n access: { create: expect.any(Function), update: expect.any(Function) },\n })\n expect(stripeIDField?.access?.create?.({} as never)).toBe(false)\n expect(stripeIDField?.access?.update?.({} as never)).toBe(false)\n expect(skipSyncField?.access?.create?.({} as never)).toBe(false)\n expect(skipSyncField?.access?.update?.({} as never)).toBe(false)\n })\n})\n"],"names":["beforeEach","describe","expect","it","vi","mocks","hoisted","stripeREST","fn","mock","stripePlugin","createBaseConfig","collections","clearAllMocks","mockResolvedValue","Response","json","status","rest","stripeSecretKey","toThrow","not","toHaveBeenCalled","transformedConfig","allowedMethods","endpoint","endpoints","find","path","req","handler","toMatchObject","method","toHaveBeenCalledWith","pluginConfig","objectContaining","filter","toEqual","sync","collection","fields","stripeResourceType","stripeResourceTypeSingular","slug","stripeIDField","field","name","skipSyncField","access","create","any","Function","update","toBe"],"mappings":"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"}
|
package/dist/routes/rest.spec.js
DELETED
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
import { UnauthorizedError } from 'payload';
|
|
2
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
const mocks = vi.hoisted(()=>({
|
|
4
|
-
addDataAndFileToRequest: vi.fn(),
|
|
5
|
-
canAccessAdmin: vi.fn(),
|
|
6
|
-
stripeProxy: vi.fn()
|
|
7
|
-
}));
|
|
8
|
-
vi.mock('payload', async (importOriginal)=>{
|
|
9
|
-
const payload = await importOriginal();
|
|
10
|
-
return {
|
|
11
|
-
...payload,
|
|
12
|
-
addDataAndFileToRequest: mocks.addDataAndFileToRequest,
|
|
13
|
-
canAccessAdmin: mocks.canAccessAdmin
|
|
14
|
-
};
|
|
15
|
-
});
|
|
16
|
-
vi.mock('../utilities/stripeProxy.js', ()=>({
|
|
17
|
-
stripeProxy: mocks.stripeProxy
|
|
18
|
-
}));
|
|
19
|
-
import { stripeREST } from './rest.js';
|
|
20
|
-
const loggerError = vi.fn();
|
|
21
|
-
const createPluginConfig = ({ access } = {})=>({
|
|
22
|
-
rest: access === undefined ? {
|
|
23
|
-
allowedMethods: [
|
|
24
|
-
'subscriptions.list'
|
|
25
|
-
]
|
|
26
|
-
} : {
|
|
27
|
-
access,
|
|
28
|
-
allowedMethods: [
|
|
29
|
-
'subscriptions.list'
|
|
30
|
-
]
|
|
31
|
-
},
|
|
32
|
-
stripeSecretKey: 'sk_test_example',
|
|
33
|
-
sync: []
|
|
34
|
-
});
|
|
35
|
-
const createRequest = ({ stripeArgs = [], stripeMethod = 'subscriptions.list', user = {
|
|
36
|
-
collection: 'users',
|
|
37
|
-
id: 'user-1'
|
|
38
|
-
} } = {})=>({
|
|
39
|
-
data: {
|
|
40
|
-
stripeArgs,
|
|
41
|
-
stripeMethod
|
|
42
|
-
},
|
|
43
|
-
payload: {
|
|
44
|
-
logger: {
|
|
45
|
-
error: loggerError
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
user
|
|
49
|
-
});
|
|
50
|
-
describe('stripeREST', ()=>{
|
|
51
|
-
beforeEach(()=>{
|
|
52
|
-
vi.clearAllMocks();
|
|
53
|
-
mocks.addDataAndFileToRequest.mockResolvedValue(undefined);
|
|
54
|
-
mocks.canAccessAdmin.mockResolvedValue(undefined);
|
|
55
|
-
mocks.stripeProxy.mockResolvedValue({
|
|
56
|
-
data: {
|
|
57
|
-
id: 'sub_123'
|
|
58
|
-
},
|
|
59
|
-
status: 200
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
// Mutation caught: replacing the anonymous guard with a generic failure or forwarding anonymous requests.
|
|
63
|
-
it('should return 401 for an anonymous request without invoking Stripe', async ()=>{
|
|
64
|
-
const req = createRequest({
|
|
65
|
-
user: null
|
|
66
|
-
});
|
|
67
|
-
const response = await stripeREST({
|
|
68
|
-
pluginConfig: createPluginConfig(),
|
|
69
|
-
req
|
|
70
|
-
});
|
|
71
|
-
expect(response.status).toBe(401);
|
|
72
|
-
expect(mocks.canAccessAdmin).not.toHaveBeenCalled();
|
|
73
|
-
expect(mocks.stripeProxy).not.toHaveBeenCalled();
|
|
74
|
-
});
|
|
75
|
-
// Mutation caught: omitting the default admin access check for an authenticated request.
|
|
76
|
-
it('should return 403 when default admin access denies the user', async ()=>{
|
|
77
|
-
mocks.canAccessAdmin.mockRejectedValue(new UnauthorizedError());
|
|
78
|
-
const req = createRequest();
|
|
79
|
-
const response = await stripeREST({
|
|
80
|
-
pluginConfig: createPluginConfig(),
|
|
81
|
-
req
|
|
82
|
-
});
|
|
83
|
-
expect(response.status).toBe(403);
|
|
84
|
-
expect(mocks.stripeProxy).not.toHaveBeenCalled();
|
|
85
|
-
});
|
|
86
|
-
// Mutation caught: rejecting every configured method or bypassing the default admin authorization on success.
|
|
87
|
-
it('should invoke an exactly listed method for an authenticated admin user', async ()=>{
|
|
88
|
-
const req = createRequest({
|
|
89
|
-
stripeArgs: [
|
|
90
|
-
{
|
|
91
|
-
limit: 10
|
|
92
|
-
}
|
|
93
|
-
]
|
|
94
|
-
});
|
|
95
|
-
const response = await stripeREST({
|
|
96
|
-
pluginConfig: createPluginConfig(),
|
|
97
|
-
req
|
|
98
|
-
});
|
|
99
|
-
expect(response.status).toBe(200);
|
|
100
|
-
expect(mocks.canAccessAdmin).toHaveBeenCalledWith({
|
|
101
|
-
req
|
|
102
|
-
});
|
|
103
|
-
expect(mocks.stripeProxy).toHaveBeenCalledWith({
|
|
104
|
-
stripeArgs: [
|
|
105
|
-
{
|
|
106
|
-
limit: 10
|
|
107
|
-
}
|
|
108
|
-
],
|
|
109
|
-
stripeMethod: 'subscriptions.list',
|
|
110
|
-
stripeSecretKey: 'sk_test_example'
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
// Mutation caught: always running the default admin check instead of a configured custom access callback.
|
|
114
|
-
it('should use a custom access callback instead of the default admin check', async ()=>{
|
|
115
|
-
const access = vi.fn(async ()=>true);
|
|
116
|
-
const req = createRequest();
|
|
117
|
-
const response = await stripeREST({
|
|
118
|
-
pluginConfig: createPluginConfig({
|
|
119
|
-
access
|
|
120
|
-
}),
|
|
121
|
-
req
|
|
122
|
-
});
|
|
123
|
-
expect(response.status).toBe(200);
|
|
124
|
-
expect(access).toHaveBeenCalledWith({
|
|
125
|
-
req
|
|
126
|
-
});
|
|
127
|
-
expect(mocks.canAccessAdmin).not.toHaveBeenCalled();
|
|
128
|
-
expect(mocks.stripeProxy).toHaveBeenCalledTimes(1);
|
|
129
|
-
});
|
|
130
|
-
// Mutation caught: ignoring a false result from a custom access callback.
|
|
131
|
-
it('should return 403 when custom access denies the authenticated user', async ()=>{
|
|
132
|
-
const access = vi.fn(async ()=>false);
|
|
133
|
-
const req = createRequest();
|
|
134
|
-
const response = await stripeREST({
|
|
135
|
-
pluginConfig: createPluginConfig({
|
|
136
|
-
access
|
|
137
|
-
}),
|
|
138
|
-
req
|
|
139
|
-
});
|
|
140
|
-
expect(response.status).toBe(403);
|
|
141
|
-
expect(mocks.stripeProxy).not.toHaveBeenCalled();
|
|
142
|
-
});
|
|
143
|
-
// Mutation caught: forwarding an unlisted Stripe method to the proxy instead of rejecting it locally.
|
|
144
|
-
it('should return a generic invalid-request response for an unlisted method without invoking Stripe', async ()=>{
|
|
145
|
-
const req = createRequest({
|
|
146
|
-
stripeMethod: 'customers.list'
|
|
147
|
-
});
|
|
148
|
-
const response = await stripeREST({
|
|
149
|
-
pluginConfig: createPluginConfig(),
|
|
150
|
-
req
|
|
151
|
-
});
|
|
152
|
-
expect(response.status).toBe(400);
|
|
153
|
-
expect(await response.json()).toEqual({
|
|
154
|
-
message: 'Invalid request'
|
|
155
|
-
});
|
|
156
|
-
expect(mocks.stripeProxy).not.toHaveBeenCalled();
|
|
157
|
-
});
|
|
158
|
-
// Mutation caught: treating an empty allowlist as a wildcard.
|
|
159
|
-
it('should return a generic invalid-request response for an empty allowlist', async ()=>{
|
|
160
|
-
const req = createRequest();
|
|
161
|
-
const pluginConfig = {
|
|
162
|
-
...createPluginConfig(),
|
|
163
|
-
rest: {
|
|
164
|
-
allowedMethods: []
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
const response = await stripeREST({
|
|
168
|
-
pluginConfig,
|
|
169
|
-
req
|
|
170
|
-
});
|
|
171
|
-
expect(response.status).toBe(400);
|
|
172
|
-
expect(await response.json()).toEqual({
|
|
173
|
-
message: 'Invalid request'
|
|
174
|
-
});
|
|
175
|
-
expect(mocks.stripeProxy).not.toHaveBeenCalled();
|
|
176
|
-
});
|
|
177
|
-
it.each([
|
|
178
|
-
[
|
|
179
|
-
''
|
|
180
|
-
],
|
|
181
|
-
[
|
|
182
|
-
' '
|
|
183
|
-
],
|
|
184
|
-
[
|
|
185
|
-
123
|
|
186
|
-
],
|
|
187
|
-
[
|
|
188
|
-
null
|
|
189
|
-
]
|
|
190
|
-
])(// Mutation caught: passing malformed method input through to Stripe.
|
|
191
|
-
'should return 400 for malformed method %s without invoking Stripe', async (stripeMethod)=>{
|
|
192
|
-
const req = createRequest({
|
|
193
|
-
stripeMethod
|
|
194
|
-
});
|
|
195
|
-
const response = await stripeREST({
|
|
196
|
-
pluginConfig: createPluginConfig(),
|
|
197
|
-
req
|
|
198
|
-
});
|
|
199
|
-
expect(response.status).toBe(400);
|
|
200
|
-
expect(mocks.stripeProxy).not.toHaveBeenCalled();
|
|
201
|
-
});
|
|
202
|
-
// Mutation caught: forwarding non-array Stripe arguments to the Stripe proxy.
|
|
203
|
-
it('should return 400 for non-array Stripe arguments without invoking Stripe', async ()=>{
|
|
204
|
-
const req = createRequest({
|
|
205
|
-
stripeArgs: {
|
|
206
|
-
limit: 10
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
const response = await stripeREST({
|
|
210
|
-
pluginConfig: createPluginConfig(),
|
|
211
|
-
req
|
|
212
|
-
});
|
|
213
|
-
expect(response.status).toBe(400);
|
|
214
|
-
expect(await response.json()).toEqual({
|
|
215
|
-
message: 'Invalid request'
|
|
216
|
-
});
|
|
217
|
-
expect(mocks.stripeProxy).not.toHaveBeenCalled();
|
|
218
|
-
});
|
|
219
|
-
// Mutation caught: leaking request parser errors through the HTTP response.
|
|
220
|
-
it('should return a generic structured 500 when request parsing fails', async ()=>{
|
|
221
|
-
const parserError = new Error('sensitive parser detail');
|
|
222
|
-
const req = createRequest();
|
|
223
|
-
mocks.addDataAndFileToRequest.mockRejectedValue(parserError);
|
|
224
|
-
const response = await stripeREST({
|
|
225
|
-
pluginConfig: createPluginConfig(),
|
|
226
|
-
req
|
|
227
|
-
});
|
|
228
|
-
expect(response.status).toBe(500);
|
|
229
|
-
expect(await response.json()).toEqual({
|
|
230
|
-
message: 'Internal server error'
|
|
231
|
-
});
|
|
232
|
-
expect(loggerError).toHaveBeenCalledWith({
|
|
233
|
-
err: parserError,
|
|
234
|
-
msg: 'An unexpected error occurred in the Stripe plugin REST handler.'
|
|
235
|
-
});
|
|
236
|
-
expect(mocks.stripeProxy).not.toHaveBeenCalled();
|
|
237
|
-
});
|
|
238
|
-
// Mutation caught: leaking a custom access callback exception or continuing to Stripe.
|
|
239
|
-
it('should return a generic structured 500 when custom access throws', async ()=>{
|
|
240
|
-
const accessError = new Error('sensitive custom access detail');
|
|
241
|
-
const access = vi.fn(async ()=>{
|
|
242
|
-
throw accessError;
|
|
243
|
-
});
|
|
244
|
-
const req = createRequest();
|
|
245
|
-
const response = await stripeREST({
|
|
246
|
-
pluginConfig: createPluginConfig({
|
|
247
|
-
access
|
|
248
|
-
}),
|
|
249
|
-
req
|
|
250
|
-
});
|
|
251
|
-
expect(response.status).toBe(500);
|
|
252
|
-
expect(await response.json()).toEqual({
|
|
253
|
-
message: 'Internal server error'
|
|
254
|
-
});
|
|
255
|
-
expect(loggerError).toHaveBeenCalledWith({
|
|
256
|
-
err: accessError,
|
|
257
|
-
msg: 'An unexpected error occurred in the Stripe plugin REST handler.'
|
|
258
|
-
});
|
|
259
|
-
expect(mocks.stripeProxy).not.toHaveBeenCalled();
|
|
260
|
-
});
|
|
261
|
-
// Mutation caught: treating an unexpected default admin access exception as a 403 or leaking it.
|
|
262
|
-
it('should return a generic structured 500 when default admin access throws unexpectedly', async ()=>{
|
|
263
|
-
const accessError = new Error('sensitive admin access detail');
|
|
264
|
-
const req = createRequest();
|
|
265
|
-
mocks.canAccessAdmin.mockRejectedValue(accessError);
|
|
266
|
-
const response = await stripeREST({
|
|
267
|
-
pluginConfig: createPluginConfig(),
|
|
268
|
-
req
|
|
269
|
-
});
|
|
270
|
-
expect(response.status).toBe(500);
|
|
271
|
-
expect(await response.json()).toEqual({
|
|
272
|
-
message: 'Internal server error'
|
|
273
|
-
});
|
|
274
|
-
expect(loggerError).toHaveBeenCalledWith({
|
|
275
|
-
err: accessError,
|
|
276
|
-
msg: 'An unexpected error occurred in the Stripe plugin REST handler.'
|
|
277
|
-
});
|
|
278
|
-
expect(mocks.stripeProxy).not.toHaveBeenCalled();
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
//# sourceMappingURL=rest.spec.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/routes/rest.spec.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { UnauthorizedError } from 'payload'\nimport { beforeEach, describe, expect, it, vi } from 'vitest'\n\nimport type { SanitizedStripePluginConfig } from '../types.js'\n\nconst mocks = vi.hoisted(() => ({\n addDataAndFileToRequest: vi.fn(),\n canAccessAdmin: vi.fn(),\n stripeProxy: vi.fn(),\n}))\n\nvi.mock('payload', async (importOriginal) => {\n const payload = await importOriginal<typeof import('payload')>()\n\n return {\n ...payload,\n addDataAndFileToRequest: mocks.addDataAndFileToRequest,\n canAccessAdmin: mocks.canAccessAdmin,\n }\n})\n\nvi.mock('../utilities/stripeProxy.js', () => ({\n stripeProxy: mocks.stripeProxy,\n}))\n\nimport { stripeREST } from './rest.js'\n\nconst loggerError = vi.fn()\n\nconst createPluginConfig = ({\n access,\n}: {\n access?: ({ req }: { req: PayloadRequest }) => boolean | Promise<boolean>\n} = {}): SanitizedStripePluginConfig => ({\n rest:\n access === undefined\n ? { allowedMethods: ['subscriptions.list'] }\n : { access, allowedMethods: ['subscriptions.list'] },\n stripeSecretKey: 'sk_test_example',\n sync: [],\n})\n\nconst createRequest = ({\n stripeArgs = [],\n stripeMethod = 'subscriptions.list',\n user = { collection: 'users', id: 'user-1' },\n}: {\n stripeArgs?: unknown\n stripeMethod?: unknown\n user?: null | { collection: string; id: string }\n} = {}): PayloadRequest =>\n ({\n data: { stripeArgs, stripeMethod },\n payload: {\n logger: { error: loggerError },\n },\n user,\n }) as unknown as PayloadRequest\n\ndescribe('stripeREST', () => {\n beforeEach(() => {\n vi.clearAllMocks()\n mocks.addDataAndFileToRequest.mockResolvedValue(undefined)\n mocks.canAccessAdmin.mockResolvedValue(undefined)\n mocks.stripeProxy.mockResolvedValue({ data: { id: 'sub_123' }, status: 200 })\n })\n\n // Mutation caught: replacing the anonymous guard with a generic failure or forwarding anonymous requests.\n it('should return 401 for an anonymous request without invoking Stripe', async () => {\n const req = createRequest({ user: null })\n\n const response = await stripeREST({ pluginConfig: createPluginConfig(), req })\n\n expect(response.status).toBe(401)\n expect(mocks.canAccessAdmin).not.toHaveBeenCalled()\n expect(mocks.stripeProxy).not.toHaveBeenCalled()\n })\n\n // Mutation caught: omitting the default admin access check for an authenticated request.\n it('should return 403 when default admin access denies the user', async () => {\n mocks.canAccessAdmin.mockRejectedValue(new UnauthorizedError())\n const req = createRequest()\n\n const response = await stripeREST({ pluginConfig: createPluginConfig(), req })\n\n expect(response.status).toBe(403)\n expect(mocks.stripeProxy).not.toHaveBeenCalled()\n })\n\n // Mutation caught: rejecting every configured method or bypassing the default admin authorization on success.\n it('should invoke an exactly listed method for an authenticated admin user', async () => {\n const req = createRequest({ stripeArgs: [{ limit: 10 }] })\n\n const response = await stripeREST({ pluginConfig: createPluginConfig(), req })\n\n expect(response.status).toBe(200)\n expect(mocks.canAccessAdmin).toHaveBeenCalledWith({ req })\n expect(mocks.stripeProxy).toHaveBeenCalledWith({\n stripeArgs: [{ limit: 10 }],\n stripeMethod: 'subscriptions.list',\n stripeSecretKey: 'sk_test_example',\n })\n })\n\n // Mutation caught: always running the default admin check instead of a configured custom access callback.\n it('should use a custom access callback instead of the default admin check', async () => {\n const access = vi.fn(async () => true)\n const req = createRequest()\n\n const response = await stripeREST({ pluginConfig: createPluginConfig({ access }), req })\n\n expect(response.status).toBe(200)\n expect(access).toHaveBeenCalledWith({ req })\n expect(mocks.canAccessAdmin).not.toHaveBeenCalled()\n expect(mocks.stripeProxy).toHaveBeenCalledTimes(1)\n })\n\n // Mutation caught: ignoring a false result from a custom access callback.\n it('should return 403 when custom access denies the authenticated user', async () => {\n const access = vi.fn(async () => false)\n const req = createRequest()\n\n const response = await stripeREST({ pluginConfig: createPluginConfig({ access }), req })\n\n expect(response.status).toBe(403)\n expect(mocks.stripeProxy).not.toHaveBeenCalled()\n })\n\n // Mutation caught: forwarding an unlisted Stripe method to the proxy instead of rejecting it locally.\n it('should return a generic invalid-request response for an unlisted method without invoking Stripe', async () => {\n const req = createRequest({ stripeMethod: 'customers.list' })\n\n const response = await stripeREST({ pluginConfig: createPluginConfig(), req })\n\n expect(response.status).toBe(400)\n expect(await response.json()).toEqual({ message: 'Invalid request' })\n expect(mocks.stripeProxy).not.toHaveBeenCalled()\n })\n\n // Mutation caught: treating an empty allowlist as a wildcard.\n it('should return a generic invalid-request response for an empty allowlist', async () => {\n const req = createRequest()\n const pluginConfig = {\n ...createPluginConfig(),\n rest: { allowedMethods: [] },\n }\n\n const response = await stripeREST({ pluginConfig, req })\n\n expect(response.status).toBe(400)\n expect(await response.json()).toEqual({ message: 'Invalid request' })\n expect(mocks.stripeProxy).not.toHaveBeenCalled()\n })\n\n it.each([[''], [' '], [123], [null]])(\n // Mutation caught: passing malformed method input through to Stripe.\n 'should return 400 for malformed method %s without invoking Stripe',\n async (stripeMethod) => {\n const req = createRequest({ stripeMethod })\n\n const response = await stripeREST({ pluginConfig: createPluginConfig(), req })\n\n expect(response.status).toBe(400)\n expect(mocks.stripeProxy).not.toHaveBeenCalled()\n },\n )\n\n // Mutation caught: forwarding non-array Stripe arguments to the Stripe proxy.\n it('should return 400 for non-array Stripe arguments without invoking Stripe', async () => {\n const req = createRequest({ stripeArgs: { limit: 10 } })\n\n const response = await stripeREST({ pluginConfig: createPluginConfig(), req })\n\n expect(response.status).toBe(400)\n expect(await response.json()).toEqual({ message: 'Invalid request' })\n expect(mocks.stripeProxy).not.toHaveBeenCalled()\n })\n\n // Mutation caught: leaking request parser errors through the HTTP response.\n it('should return a generic structured 500 when request parsing fails', async () => {\n const parserError = new Error('sensitive parser detail')\n const req = createRequest()\n\n mocks.addDataAndFileToRequest.mockRejectedValue(parserError)\n\n const response = await stripeREST({ pluginConfig: createPluginConfig(), req })\n\n expect(response.status).toBe(500)\n expect(await response.json()).toEqual({ message: 'Internal server error' })\n expect(loggerError).toHaveBeenCalledWith({\n err: parserError,\n msg: 'An unexpected error occurred in the Stripe plugin REST handler.',\n })\n expect(mocks.stripeProxy).not.toHaveBeenCalled()\n })\n\n // Mutation caught: leaking a custom access callback exception or continuing to Stripe.\n it('should return a generic structured 500 when custom access throws', async () => {\n const accessError = new Error('sensitive custom access detail')\n const access = vi.fn(async () => {\n throw accessError\n })\n const req = createRequest()\n\n const response = await stripeREST({ pluginConfig: createPluginConfig({ access }), req })\n\n expect(response.status).toBe(500)\n expect(await response.json()).toEqual({ message: 'Internal server error' })\n expect(loggerError).toHaveBeenCalledWith({\n err: accessError,\n msg: 'An unexpected error occurred in the Stripe plugin REST handler.',\n })\n expect(mocks.stripeProxy).not.toHaveBeenCalled()\n })\n\n // Mutation caught: treating an unexpected default admin access exception as a 403 or leaking it.\n it('should return a generic structured 500 when default admin access throws unexpectedly', async () => {\n const accessError = new Error('sensitive admin access detail')\n const req = createRequest()\n\n mocks.canAccessAdmin.mockRejectedValue(accessError)\n\n const response = await stripeREST({ pluginConfig: createPluginConfig(), req })\n\n expect(response.status).toBe(500)\n expect(await response.json()).toEqual({ message: 'Internal server error' })\n expect(loggerError).toHaveBeenCalledWith({\n err: accessError,\n msg: 'An unexpected error occurred in the Stripe plugin REST handler.',\n })\n expect(mocks.stripeProxy).not.toHaveBeenCalled()\n })\n})\n"],"names":["UnauthorizedError","beforeEach","describe","expect","it","vi","mocks","hoisted","addDataAndFileToRequest","fn","canAccessAdmin","stripeProxy","mock","importOriginal","payload","stripeREST","loggerError","createPluginConfig","access","rest","undefined","allowedMethods","stripeSecretKey","sync","createRequest","stripeArgs","stripeMethod","user","collection","id","data","logger","error","clearAllMocks","mockResolvedValue","status","req","response","pluginConfig","toBe","not","toHaveBeenCalled","mockRejectedValue","limit","toHaveBeenCalledWith","toHaveBeenCalledTimes","json","toEqual","message","each","parserError","Error","err","msg","accessError"],"mappings":"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"}
|
package/dist/ui/LinkToDoc.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"LinkToDoc.d.ts","sourceRoot":"","sources":["../../src/ui/LinkToDoc.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAKrD,eAAO,MAAM,SAAS,EAAE,sBA0CvB,CAAA"}
|
package/dist/ui/LinkToDoc.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { CopyToClipboard, useFormFields } from '@payloadcms/ui';
|
|
4
|
-
import React from 'react';
|
|
5
|
-
export const LinkToDoc = (props)=>{
|
|
6
|
-
const { field: { admin: { custom = {} } = {} } } = props;
|
|
7
|
-
const { isTestKey, nameOfIDField, stripeResourceType } = custom;
|
|
8
|
-
const field = useFormFields(([fields])=>fields && fields?.[nameOfIDField] || null);
|
|
9
|
-
const { value: stripeID } = field || {};
|
|
10
|
-
const stripeEnv = isTestKey ? 'test/' : '';
|
|
11
|
-
const href = `https://dashboard.stripe.com/${stripeEnv}${stripeResourceType}/${stripeID}`;
|
|
12
|
-
if (stripeID) {
|
|
13
|
-
return /*#__PURE__*/ _jsxs("div", {
|
|
14
|
-
children: [
|
|
15
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
16
|
-
children: [
|
|
17
|
-
/*#__PURE__*/ _jsx("span", {
|
|
18
|
-
className: "label",
|
|
19
|
-
style: {
|
|
20
|
-
color: '#9A9A9A'
|
|
21
|
-
},
|
|
22
|
-
children: "View in Stripe"
|
|
23
|
-
}),
|
|
24
|
-
/*#__PURE__*/ _jsx(CopyToClipboard, {
|
|
25
|
-
value: href
|
|
26
|
-
})
|
|
27
|
-
]
|
|
28
|
-
}),
|
|
29
|
-
/*#__PURE__*/ _jsx("div", {
|
|
30
|
-
style: {
|
|
31
|
-
fontWeight: '600',
|
|
32
|
-
overflow: 'hidden',
|
|
33
|
-
textOverflow: 'ellipsis'
|
|
34
|
-
},
|
|
35
|
-
children: /*#__PURE__*/ _jsx("a", {
|
|
36
|
-
href: href,
|
|
37
|
-
rel: "noreferrer noopener",
|
|
38
|
-
target: "_blank",
|
|
39
|
-
children: href
|
|
40
|
-
})
|
|
41
|
-
})
|
|
42
|
-
]
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
return null;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
//# sourceMappingURL=LinkToDoc.js.map
|
package/dist/ui/LinkToDoc.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ui/LinkToDoc.tsx"],"sourcesContent":["'use client'\nimport type { UIFieldClientComponent } from 'payload'\n\nimport { CopyToClipboard, useFormFields } from '@payloadcms/ui'\nimport React from 'react'\n\nexport const LinkToDoc: UIFieldClientComponent = (props) => {\n const {\n field: { admin: { custom = {} } = {} },\n } = props\n const { isTestKey, nameOfIDField, stripeResourceType } = custom\n\n const field = useFormFields(([fields]) => (fields && fields?.[nameOfIDField]) || null)\n const { value: stripeID } = field || {}\n\n const stripeEnv = isTestKey ? 'test/' : ''\n const href = `https://dashboard.stripe.com/${stripeEnv}${stripeResourceType}/${stripeID}`\n\n if (stripeID) {\n return (\n <div>\n <div>\n <span\n className=\"label\"\n style={{\n color: '#9A9A9A',\n }}\n >\n View in Stripe\n </span>\n <CopyToClipboard value={href} />\n </div>\n <div\n style={{\n fontWeight: '600',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n <a href={href} rel=\"noreferrer noopener\" target=\"_blank\">\n {href}\n </a>\n </div>\n </div>\n )\n }\n\n return null\n}\n"],"names":["CopyToClipboard","useFormFields","React","LinkToDoc","props","field","admin","custom","isTestKey","nameOfIDField","stripeResourceType","fields","value","stripeID","stripeEnv","href","div","span","className","style","color","fontWeight","overflow","textOverflow","a","rel","target"],"mappings":"AAAA;;AAGA,SAASA,eAAe,EAAEC,aAAa,QAAQ,iBAAgB;AAC/D,OAAOC,WAAW,QAAO;AAEzB,OAAO,MAAMC,YAAoC,CAACC;IAChD,MAAM,EACJC,OAAO,EAAEC,OAAO,EAAEC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,EACvC,GAAGH;IACJ,MAAM,EAAEI,SAAS,EAAEC,aAAa,EAAEC,kBAAkB,EAAE,GAAGH;IAEzD,MAAMF,QAAQJ,cAAc,CAAC,CAACU,OAAO,GAAK,AAACA,UAAUA,QAAQ,CAACF,cAAc,IAAK;IACjF,MAAM,EAAEG,OAAOC,QAAQ,EAAE,GAAGR,SAAS,CAAC;IAEtC,MAAMS,YAAYN,YAAY,UAAU;IACxC,MAAMO,OAAO,CAAC,6BAA6B,EAAED,YAAYJ,mBAAmB,CAAC,EAAEG,UAAU;IAEzF,IAAIA,UAAU;QACZ,qBACE,MAACG;;8BACC,MAACA;;sCACC,KAACC;4BACCC,WAAU;4BACVC,OAAO;gCACLC,OAAO;4BACT;sCACD;;sCAGD,KAACpB;4BAAgBY,OAAOG;;;;8BAE1B,KAACC;oBACCG,OAAO;wBACLE,YAAY;wBACZC,UAAU;wBACVC,cAAc;oBAChB;8BAEA,cAAA,KAACC;wBAAET,MAAMA;wBAAMU,KAAI;wBAAsBC,QAAO;kCAC7CX;;;;;IAKX;IAEA,OAAO;AACT,EAAC"}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { deepen, getSyncedFields } from './deepen.js';
|
|
3
|
-
describe('Stripe field mappings', ()=>{
|
|
4
|
-
it('should build constrained mappings from owned values', ()=>{
|
|
5
|
-
const marker = 'constrainedStripeMapping';
|
|
6
|
-
const inheritedSource = 'constrainedStripeSource';
|
|
7
|
-
const originalDescriptor = Object.getOwnPropertyDescriptor(Object.prototype, marker);
|
|
8
|
-
let inheritedGetterCalls = 0;
|
|
9
|
-
let processStateChanged = false;
|
|
10
|
-
let nestedMapping;
|
|
11
|
-
let syncedMapping;
|
|
12
|
-
let webhookMapping;
|
|
13
|
-
try {
|
|
14
|
-
expect(()=>deepen({
|
|
15
|
-
[`__proto__.${marker}`]: 'value'
|
|
16
|
-
})).toThrow('Invalid field path.');
|
|
17
|
-
nestedMapping = deepen(Object.assign(Object.create({
|
|
18
|
-
'ignored.value': 'inherited'
|
|
19
|
-
}), {
|
|
20
|
-
[`constructor.prototype.${marker}`]: 'local',
|
|
21
|
-
'profile.displayName': 'Ada'
|
|
22
|
-
}));
|
|
23
|
-
const data = Object.create({
|
|
24
|
-
get [inheritedSource] () {
|
|
25
|
-
inheritedGetterCalls += 1;
|
|
26
|
-
return 'inherited';
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
data.displayName = 'Ada';
|
|
30
|
-
syncedMapping = getSyncedFields({
|
|
31
|
-
data,
|
|
32
|
-
fields: [
|
|
33
|
-
{
|
|
34
|
-
fieldPath: inheritedSource,
|
|
35
|
-
stripeProperty: 'metadata.inherited'
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
fieldPath: 'constructor',
|
|
39
|
-
stripeProperty: 'constructor'
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
fieldPath: 'displayName',
|
|
43
|
-
stripeProperty: `constructor.prototype.${marker}`
|
|
44
|
-
}
|
|
45
|
-
],
|
|
46
|
-
source: 'payload'
|
|
47
|
-
});
|
|
48
|
-
const stripeData = Object.create({
|
|
49
|
-
get [inheritedSource] () {
|
|
50
|
-
inheritedGetterCalls += 1;
|
|
51
|
-
return 'inherited';
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
stripeData.name = 'Ada';
|
|
55
|
-
webhookMapping = getSyncedFields({
|
|
56
|
-
data: stripeData,
|
|
57
|
-
fields: [
|
|
58
|
-
{
|
|
59
|
-
fieldPath: 'profile.inherited',
|
|
60
|
-
stripeProperty: inheritedSource
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
fieldPath: 'profile.displayName',
|
|
64
|
-
stripeProperty: 'name'
|
|
65
|
-
}
|
|
66
|
-
],
|
|
67
|
-
source: 'stripe'
|
|
68
|
-
});
|
|
69
|
-
processStateChanged = Object.hasOwn(Object.prototype, marker);
|
|
70
|
-
} finally{
|
|
71
|
-
if (originalDescriptor) {
|
|
72
|
-
Object.defineProperty(Object.prototype, marker, originalDescriptor);
|
|
73
|
-
} else {
|
|
74
|
-
delete Object.prototype[marker];
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
expect(processStateChanged).toBe(false);
|
|
78
|
-
expect(inheritedGetterCalls).toBe(0);
|
|
79
|
-
expect(Object.getOwnPropertyDescriptor(Object.prototype, marker)).toEqual(originalDescriptor);
|
|
80
|
-
expect(nestedMapping).toEqual({
|
|
81
|
-
constructor: {
|
|
82
|
-
prototype: {
|
|
83
|
-
[marker]: 'local'
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
profile: {
|
|
87
|
-
displayName: 'Ada'
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
expect(Object.hasOwn(nestedMapping, 'ignored')).toBe(false);
|
|
91
|
-
expect(syncedMapping).toEqual({
|
|
92
|
-
constructor: {
|
|
93
|
-
prototype: {
|
|
94
|
-
[marker]: 'Ada'
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
metadata: {
|
|
98
|
-
inherited: undefined
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
expect(webhookMapping).toEqual({
|
|
102
|
-
profile: {
|
|
103
|
-
displayName: 'Ada',
|
|
104
|
-
inherited: undefined
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
//# sourceMappingURL=deepen.spec.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/deepen.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { deepen, getSyncedFields } from './deepen.js'\n\ndescribe('Stripe field mappings', () => {\n it('should build constrained mappings from owned values', () => {\n const marker = 'constrainedStripeMapping'\n const inheritedSource = 'constrainedStripeSource'\n const originalDescriptor = Object.getOwnPropertyDescriptor(Object.prototype, marker)\n let inheritedGetterCalls = 0\n let processStateChanged = false\n let nestedMapping: Record<string, unknown> | undefined\n let syncedMapping: Record<string, unknown> | undefined\n let webhookMapping: Record<string, unknown> | undefined\n\n try {\n expect(() => deepen({ [`__proto__.${marker}`]: 'value' })).toThrow('Invalid field path.')\n\n nestedMapping = deepen(\n Object.assign(Object.create({ 'ignored.value': 'inherited' }), {\n [`constructor.prototype.${marker}`]: 'local',\n 'profile.displayName': 'Ada',\n }),\n )\n\n const data = Object.create({\n get [inheritedSource]() {\n inheritedGetterCalls += 1\n return 'inherited'\n },\n }) as Record<string, unknown>\n data.displayName = 'Ada'\n\n syncedMapping = getSyncedFields({\n data,\n fields: [\n { fieldPath: inheritedSource, stripeProperty: 'metadata.inherited' },\n { fieldPath: 'constructor', stripeProperty: 'constructor' },\n {\n fieldPath: 'displayName',\n stripeProperty: `constructor.prototype.${marker}`,\n },\n ],\n source: 'payload',\n })\n\n const stripeData = Object.create({\n get [inheritedSource]() {\n inheritedGetterCalls += 1\n return 'inherited'\n },\n }) as Record<string, unknown>\n stripeData.name = 'Ada'\n\n webhookMapping = getSyncedFields({\n data: stripeData,\n fields: [\n { fieldPath: 'profile.inherited', stripeProperty: inheritedSource },\n { fieldPath: 'profile.displayName', stripeProperty: 'name' },\n ],\n source: 'stripe',\n })\n processStateChanged = Object.hasOwn(Object.prototype, marker)\n } finally {\n if (originalDescriptor) {\n Object.defineProperty(Object.prototype, marker, originalDescriptor)\n } else {\n delete (Object.prototype as Record<string, unknown>)[marker]\n }\n }\n\n expect(processStateChanged).toBe(false)\n expect(inheritedGetterCalls).toBe(0)\n expect(Object.getOwnPropertyDescriptor(Object.prototype, marker)).toEqual(originalDescriptor)\n expect(nestedMapping).toEqual({\n constructor: {\n prototype: {\n [marker]: 'local',\n },\n },\n profile: {\n displayName: 'Ada',\n },\n })\n expect(Object.hasOwn(nestedMapping as object, 'ignored')).toBe(false)\n expect(syncedMapping).toEqual({\n constructor: {\n prototype: {\n [marker]: 'Ada',\n },\n },\n metadata: {\n inherited: undefined,\n },\n })\n expect(webhookMapping).toEqual({\n profile: {\n displayName: 'Ada',\n inherited: undefined,\n },\n })\n })\n})\n"],"names":["describe","expect","it","deepen","getSyncedFields","marker","inheritedSource","originalDescriptor","Object","getOwnPropertyDescriptor","prototype","inheritedGetterCalls","processStateChanged","nestedMapping","syncedMapping","webhookMapping","toThrow","assign","create","data","displayName","fields","fieldPath","stripeProperty","source","stripeData","name","hasOwn","defineProperty","toBe","toEqual","profile","metadata","inherited","undefined"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,MAAM,EAAEC,eAAe,QAAQ,cAAa;AAErDJ,SAAS,yBAAyB;IAChCE,GAAG,uDAAuD;QACxD,MAAMG,SAAS;QACf,MAAMC,kBAAkB;QACxB,MAAMC,qBAAqBC,OAAOC,wBAAwB,CAACD,OAAOE,SAAS,EAAEL;QAC7E,IAAIM,uBAAuB;QAC3B,IAAIC,sBAAsB;QAC1B,IAAIC;QACJ,IAAIC;QACJ,IAAIC;QAEJ,IAAI;YACFd,OAAO,IAAME,OAAO;oBAAE,CAAC,CAAC,UAAU,EAAEE,QAAQ,CAAC,EAAE;gBAAQ,IAAIW,OAAO,CAAC;YAEnEH,gBAAgBV,OACdK,OAAOS,MAAM,CAACT,OAAOU,MAAM,CAAC;gBAAE,iBAAiB;YAAY,IAAI;gBAC7D,CAAC,CAAC,sBAAsB,EAAEb,QAAQ,CAAC,EAAE;gBACrC,uBAAuB;YACzB;YAGF,MAAMc,OAAOX,OAAOU,MAAM,CAAC;gBACzB,IAAI,CAACZ,gBAAgB,IAAG;oBACtBK,wBAAwB;oBACxB,OAAO;gBACT;YACF;YACAQ,KAAKC,WAAW,GAAG;YAEnBN,gBAAgBV,gBAAgB;gBAC9Be;gBACAE,QAAQ;oBACN;wBAAEC,WAAWhB;wBAAiBiB,gBAAgB;oBAAqB;oBACnE;wBAAED,WAAW;wBAAeC,gBAAgB;oBAAc;oBAC1D;wBACED,WAAW;wBACXC,gBAAgB,CAAC,sBAAsB,EAAElB,QAAQ;oBACnD;iBACD;gBACDmB,QAAQ;YACV;YAEA,MAAMC,aAAajB,OAAOU,MAAM,CAAC;gBAC/B,IAAI,CAACZ,gBAAgB,IAAG;oBACtBK,wBAAwB;oBACxB,OAAO;gBACT;YACF;YACAc,WAAWC,IAAI,GAAG;YAElBX,iBAAiBX,gBAAgB;gBAC/Be,MAAMM;gBACNJ,QAAQ;oBACN;wBAAEC,WAAW;wBAAqBC,gBAAgBjB;oBAAgB;oBAClE;wBAAEgB,WAAW;wBAAuBC,gBAAgB;oBAAO;iBAC5D;gBACDC,QAAQ;YACV;YACAZ,sBAAsBJ,OAAOmB,MAAM,CAACnB,OAAOE,SAAS,EAAEL;QACxD,SAAU;YACR,IAAIE,oBAAoB;gBACtBC,OAAOoB,cAAc,CAACpB,OAAOE,SAAS,EAAEL,QAAQE;YAClD,OAAO;gBACL,OAAO,AAACC,OAAOE,SAAS,AAA4B,CAACL,OAAO;YAC9D;QACF;QAEAJ,OAAOW,qBAAqBiB,IAAI,CAAC;QACjC5B,OAAOU,sBAAsBkB,IAAI,CAAC;QAClC5B,OAAOO,OAAOC,wBAAwB,CAACD,OAAOE,SAAS,EAAEL,SAASyB,OAAO,CAACvB;QAC1EN,OAAOY,eAAeiB,OAAO,CAAC;YAC5B,aAAa;gBACXpB,WAAW;oBACT,CAACL,OAAO,EAAE;gBACZ;YACF;YACA0B,SAAS;gBACPX,aAAa;YACf;QACF;QACAnB,OAAOO,OAAOmB,MAAM,CAACd,eAAyB,YAAYgB,IAAI,CAAC;QAC/D5B,OAAOa,eAAegB,OAAO,CAAC;YAC5B,aAAa;gBACXpB,WAAW;oBACT,CAACL,OAAO,EAAE;gBACZ;YACF;YACA2B,UAAU;gBACRC,WAAWC;YACb;QACF;QACAjC,OAAOc,gBAAgBe,OAAO,CAAC;YAC7BC,SAAS;gBACPX,aAAa;gBACba,WAAWC;YACb;QACF;IACF;AACF"}
|