@payloadcms/plugin-import-export 3.47.0-canary.2 → 3.47.0-canary.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ExportSaveButton/index.d.ts.map +1 -1
- package/dist/components/ExportSaveButton/index.js +21 -2
- package/dist/components/ExportSaveButton/index.js.map +1 -1
- package/dist/components/FieldsToExport/index.d.ts.map +1 -1
- package/dist/components/FieldsToExport/index.js +15 -13
- package/dist/components/FieldsToExport/index.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ExportSaveButton/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ExportSaveButton/index.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAwFpC,CAAA"}
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Button, SaveButton, Translation, useConfig, useForm, useTranslation } from '@payloadcms/ui';
|
|
3
|
+
import { Button, SaveButton, toast, Translation, useConfig, useForm, useFormModified, useTranslation } from '@payloadcms/ui';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
export const ExportSaveButton = ()=>{
|
|
6
6
|
const { t } = useTranslation();
|
|
7
7
|
const { config: { routes: { api }, serverURL } } = useConfig();
|
|
8
|
-
const { getData } = useForm();
|
|
8
|
+
const { getData, setModified } = useForm();
|
|
9
|
+
const modified = useFormModified();
|
|
9
10
|
const label = t('general:save');
|
|
10
11
|
const handleDownload = async ()=>{
|
|
12
|
+
let timeoutID = null;
|
|
13
|
+
let toastID = null;
|
|
11
14
|
try {
|
|
15
|
+
setModified(false) // Reset modified state
|
|
16
|
+
;
|
|
12
17
|
const data = getData();
|
|
18
|
+
// Set a timeout to show toast if the request takes longer than 200ms
|
|
19
|
+
timeoutID = setTimeout(()=>{
|
|
20
|
+
toastID = toast.success('Your export is being processed...');
|
|
21
|
+
}, 200);
|
|
13
22
|
const response = await fetch(`${serverURL}${api}/exports/download`, {
|
|
14
23
|
body: JSON.stringify({
|
|
15
24
|
data
|
|
@@ -20,6 +29,14 @@ export const ExportSaveButton = ()=>{
|
|
|
20
29
|
},
|
|
21
30
|
method: 'POST'
|
|
22
31
|
});
|
|
32
|
+
// Clear the timeout if fetch completes quickly
|
|
33
|
+
if (timeoutID) {
|
|
34
|
+
clearTimeout(timeoutID);
|
|
35
|
+
}
|
|
36
|
+
// Dismiss the toast if it was shown
|
|
37
|
+
if (toastID) {
|
|
38
|
+
toast.dismiss(toastID);
|
|
39
|
+
}
|
|
23
40
|
if (!response.ok) {
|
|
24
41
|
throw new Error('Failed to download file');
|
|
25
42
|
}
|
|
@@ -51,6 +68,7 @@ export const ExportSaveButton = ()=>{
|
|
|
51
68
|
URL.revokeObjectURL(url);
|
|
52
69
|
} catch (error) {
|
|
53
70
|
console.error('Error downloading file:', error);
|
|
71
|
+
toast.error('Error downloading file');
|
|
54
72
|
}
|
|
55
73
|
};
|
|
56
74
|
return /*#__PURE__*/ _jsxs(React.Fragment, {
|
|
@@ -59,6 +77,7 @@ export const ExportSaveButton = ()=>{
|
|
|
59
77
|
label: label
|
|
60
78
|
}),
|
|
61
79
|
/*#__PURE__*/ _jsx(Button, {
|
|
80
|
+
disabled: !modified,
|
|
62
81
|
onClick: handleDownload,
|
|
63
82
|
size: "medium",
|
|
64
83
|
type: "button",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ExportSaveButton/index.tsx"],"sourcesContent":["'use client'\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ExportSaveButton/index.tsx"],"sourcesContent":["'use client'\n\nimport {\n Button,\n SaveButton,\n toast,\n Translation,\n useConfig,\n useForm,\n useFormModified,\n useTranslation,\n} from '@payloadcms/ui'\nimport React from 'react'\n\nimport type {\n PluginImportExportTranslationKeys,\n PluginImportExportTranslations,\n} from '../../translations/index.js'\n\nexport const ExportSaveButton: React.FC = () => {\n const { t } = useTranslation<PluginImportExportTranslations, PluginImportExportTranslationKeys>()\n const {\n config: {\n routes: { api },\n serverURL,\n },\n } = useConfig()\n\n const { getData, setModified } = useForm()\n const modified = useFormModified()\n\n const label = t('general:save')\n\n const handleDownload = async () => {\n let timeoutID: null | ReturnType<typeof setTimeout> = null\n let toastID: null | number | string = null\n\n try {\n setModified(false) // Reset modified state\n const data = getData()\n\n // Set a timeout to show toast if the request takes longer than 200ms\n timeoutID = setTimeout(() => {\n toastID = toast.success('Your export is being processed...')\n }, 200)\n\n const response = await fetch(`${serverURL}${api}/exports/download`, {\n body: JSON.stringify({\n data,\n }),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n // Clear the timeout if fetch completes quickly\n if (timeoutID) {\n clearTimeout(timeoutID)\n }\n\n // Dismiss the toast if it was shown\n if (toastID) {\n toast.dismiss(toastID)\n }\n\n if (!response.ok) {\n throw new Error('Failed to download file')\n }\n\n const fileStream = response.body\n const reader = fileStream?.getReader()\n const decoder = new TextDecoder()\n let result = ''\n\n while (reader) {\n const { done, value } = await reader.read()\n if (done) {\n break\n }\n result += decoder.decode(value, { stream: true })\n }\n\n const blob = new Blob([result], { type: 'text/plain' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `${data.name}.${data.format}`\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n URL.revokeObjectURL(url)\n } catch (error) {\n console.error('Error downloading file:', error)\n toast.error('Error downloading file')\n }\n }\n\n return (\n <React.Fragment>\n <SaveButton label={label}></SaveButton>\n <Button disabled={!modified} onClick={handleDownload} size=\"medium\" type=\"button\">\n <Translation i18nKey=\"upload:download\" t={t} />\n </Button>\n </React.Fragment>\n )\n}\n"],"names":["Button","SaveButton","toast","Translation","useConfig","useForm","useFormModified","useTranslation","React","ExportSaveButton","t","config","routes","api","serverURL","getData","setModified","modified","label","handleDownload","timeoutID","toastID","data","setTimeout","success","response","fetch","body","JSON","stringify","credentials","headers","method","clearTimeout","dismiss","ok","Error","fileStream","reader","getReader","decoder","TextDecoder","result","done","value","read","decode","stream","blob","Blob","type","url","URL","createObjectURL","a","document","createElement","href","download","name","format","appendChild","click","removeChild","revokeObjectURL","error","console","Fragment","disabled","onClick","size","i18nKey"],"mappings":"AAAA;;AAEA,SACEA,MAAM,EACNC,UAAU,EACVC,KAAK,EACLC,WAAW,EACXC,SAAS,EACTC,OAAO,EACPC,eAAe,EACfC,cAAc,QACT,iBAAgB;AACvB,OAAOC,WAAW,QAAO;AAOzB,OAAO,MAAMC,mBAA6B;IACxC,MAAM,EAAEC,CAAC,EAAE,GAAGH;IACd,MAAM,EACJI,QAAQ,EACNC,QAAQ,EAAEC,GAAG,EAAE,EACfC,SAAS,EACV,EACF,GAAGV;IAEJ,MAAM,EAAEW,OAAO,EAAEC,WAAW,EAAE,GAAGX;IACjC,MAAMY,WAAWX;IAEjB,MAAMY,QAAQR,EAAE;IAEhB,MAAMS,iBAAiB;QACrB,IAAIC,YAAkD;QACtD,IAAIC,UAAkC;QAEtC,IAAI;YACFL,YAAY,OAAO,uBAAuB;;YAC1C,MAAMM,OAAOP;YAEb,qEAAqE;YACrEK,YAAYG,WAAW;gBACrBF,UAAUnB,MAAMsB,OAAO,CAAC;YAC1B,GAAG;YAEH,MAAMC,WAAW,MAAMC,MAAM,GAAGZ,YAAYD,IAAI,iBAAiB,CAAC,EAAE;gBAClEc,MAAMC,KAAKC,SAAS,CAAC;oBACnBP;gBACF;gBACAQ,aAAa;gBACbC,SAAS;oBACP,gBAAgB;gBAClB;gBACAC,QAAQ;YACV;YAEA,+CAA+C;YAC/C,IAAIZ,WAAW;gBACba,aAAab;YACf;YAEA,oCAAoC;YACpC,IAAIC,SAAS;gBACXnB,MAAMgC,OAAO,CAACb;YAChB;YAEA,IAAI,CAACI,SAASU,EAAE,EAAE;gBAChB,MAAM,IAAIC,MAAM;YAClB;YAEA,MAAMC,aAAaZ,SAASE,IAAI;YAChC,MAAMW,SAASD,YAAYE;YAC3B,MAAMC,UAAU,IAAIC;YACpB,IAAIC,SAAS;YAEb,MAAOJ,OAAQ;gBACb,MAAM,EAAEK,IAAI,EAAEC,KAAK,EAAE,GAAG,MAAMN,OAAOO,IAAI;gBACzC,IAAIF,MAAM;oBACR;gBACF;gBACAD,UAAUF,QAAQM,MAAM,CAACF,OAAO;oBAAEG,QAAQ;gBAAK;YACjD;YAEA,MAAMC,OAAO,IAAIC,KAAK;gBAACP;aAAO,EAAE;gBAAEQ,MAAM;YAAa;YACrD,MAAMC,MAAMC,IAAIC,eAAe,CAACL;YAChC,MAAMM,IAAIC,SAASC,aAAa,CAAC;YACjCF,EAAEG,IAAI,GAAGN;YACTG,EAAEI,QAAQ,GAAG,GAAGpC,KAAKqC,IAAI,CAAC,CAAC,EAAErC,KAAKsC,MAAM,EAAE;YAC1CL,SAAS5B,IAAI,CAACkC,WAAW,CAACP;YAC1BA,EAAEQ,KAAK;YACPP,SAAS5B,IAAI,CAACoC,WAAW,CAACT;YAC1BF,IAAIY,eAAe,CAACb;QACtB,EAAE,OAAOc,OAAO;YACdC,QAAQD,KAAK,CAAC,2BAA2BA;YACzC/D,MAAM+D,KAAK,CAAC;QACd;IACF;IAEA,qBACE,MAACzD,MAAM2D,QAAQ;;0BACb,KAAClE;gBAAWiB,OAAOA;;0BACnB,KAAClB;gBAAOoE,UAAU,CAACnD;gBAAUoD,SAASlD;gBAAgBmD,MAAK;gBAASpB,MAAK;0BACvE,cAAA,KAAC/C;oBAAYoE,SAAQ;oBAAkB7D,GAAGA;;;;;AAIlD,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FieldsToExport/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FieldsToExport/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AAkBzD,eAAO,MAAM,cAAc,EAAE,0BAoE5B,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { FieldLabel, ReactSelect, useConfig, useDocumentInfo, useField,
|
|
3
|
+
import { FieldLabel, ReactSelect, useConfig, useDocumentInfo, useField, useListQuery } from '@payloadcms/ui';
|
|
4
4
|
import React, { useEffect } from 'react';
|
|
5
5
|
import { useImportExport } from '../ImportExportProvider/index.js';
|
|
6
6
|
import { reduceFields } from './reduceFields.js';
|
|
@@ -13,7 +13,7 @@ export const FieldsToExport = (props)=>{
|
|
|
13
13
|
});
|
|
14
14
|
const { getEntityConfig } = useConfig();
|
|
15
15
|
const { collection } = useImportExport();
|
|
16
|
-
const {
|
|
16
|
+
const { query } = useListQuery();
|
|
17
17
|
const collectionConfig = getEntityConfig({
|
|
18
18
|
collectionSlug: collectionSlug ?? collection
|
|
19
19
|
});
|
|
@@ -24,19 +24,21 @@ export const FieldsToExport = (props)=>{
|
|
|
24
24
|
if (id || !collectionSlug) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
const queryColumns = query?.columns;
|
|
28
|
+
if (Array.isArray(queryColumns)) {
|
|
29
|
+
const cleanColumns = queryColumns.filter((col)=>typeof col === 'string' && !col.startsWith('-'));
|
|
30
|
+
// If columns are specified in the query, use them
|
|
31
|
+
setValue(cleanColumns);
|
|
32
|
+
} else {
|
|
33
|
+
// Fallback if no columns in query
|
|
34
|
+
setValue(collectionConfig?.admin?.defaultColumns ?? []);
|
|
35
|
+
}
|
|
33
36
|
}, [
|
|
34
|
-
getPreference,
|
|
35
|
-
collection,
|
|
36
|
-
setValue,
|
|
37
|
-
collectionSlug,
|
|
38
37
|
id,
|
|
39
|
-
|
|
38
|
+
collectionSlug,
|
|
39
|
+
query?.columns,
|
|
40
|
+
collectionConfig?.admin?.defaultColumns,
|
|
41
|
+
setValue
|
|
40
42
|
]);
|
|
41
43
|
const onChange = (options)=>{
|
|
42
44
|
if (!options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/FieldsToExport/index.tsx"],"sourcesContent":["'use client'\n\nimport type {
|
|
1
|
+
{"version":3,"sources":["../../../src/components/FieldsToExport/index.tsx"],"sourcesContent":["'use client'\n\nimport type { SelectFieldClientComponent } from 'payload'\nimport type { ReactNode } from 'react'\n\nimport {\n FieldLabel,\n ReactSelect,\n useConfig,\n useDocumentInfo,\n useField,\n useListQuery,\n} from '@payloadcms/ui'\nimport React, { useEffect } from 'react'\n\nimport { useImportExport } from '../ImportExportProvider/index.js'\nimport { reduceFields } from './reduceFields.js'\n\nconst baseClass = 'fields-to-export'\n\nexport const FieldsToExport: SelectFieldClientComponent = (props) => {\n const { id } = useDocumentInfo()\n const { setValue, value } = useField<string[]>()\n const { value: collectionSlug } = useField<string>({ path: 'collectionSlug' })\n const { getEntityConfig } = useConfig()\n const { collection } = useImportExport()\n const { query } = useListQuery()\n\n const collectionConfig = getEntityConfig({ collectionSlug: collectionSlug ?? collection })\n const fieldOptions = reduceFields({ fields: collectionConfig?.fields })\n\n useEffect(() => {\n if (id || !collectionSlug) {\n return\n }\n\n const queryColumns = query?.columns\n\n if (Array.isArray(queryColumns)) {\n const cleanColumns = queryColumns.filter(\n (col): col is string => typeof col === 'string' && !col.startsWith('-'),\n )\n // If columns are specified in the query, use them\n setValue(cleanColumns)\n } else {\n // Fallback if no columns in query\n setValue(collectionConfig?.admin?.defaultColumns ?? [])\n }\n }, [id, collectionSlug, query?.columns, collectionConfig?.admin?.defaultColumns, setValue])\n\n const onChange = (options: { id: string; label: ReactNode; value: string }[]) => {\n if (!options) {\n setValue([])\n return\n }\n\n const updatedValue = options.map((option) =>\n typeof option === 'object' ? option.value : option,\n )\n\n setValue(updatedValue)\n }\n\n return (\n <div className={baseClass}>\n <FieldLabel label={props.field.label} path={props.path} />\n <ReactSelect\n className={baseClass}\n disabled={props.readOnly}\n getOptionValue={(option) => String(option.value)}\n inputId={`field-${props.path.replace(/\\./g, '__')}`}\n isClearable={true}\n isMulti={true}\n isSortable={true}\n // @ts-expect-error react select option\n onChange={onChange}\n options={fieldOptions}\n value={\n Array.isArray(value)\n ? value.map((val) => {\n const match = fieldOptions.find((opt) => opt.value === val)\n return match ? { ...match, id: val } : { id: val, label: val, value: val }\n })\n : []\n }\n />\n </div>\n )\n}\n"],"names":["FieldLabel","ReactSelect","useConfig","useDocumentInfo","useField","useListQuery","React","useEffect","useImportExport","reduceFields","baseClass","FieldsToExport","props","id","setValue","value","collectionSlug","path","getEntityConfig","collection","query","collectionConfig","fieldOptions","fields","queryColumns","columns","Array","isArray","cleanColumns","filter","col","startsWith","admin","defaultColumns","onChange","options","updatedValue","map","option","div","className","label","field","disabled","readOnly","getOptionValue","String","inputId","replace","isClearable","isMulti","isSortable","val","match","find","opt"],"mappings":"AAAA;;AAKA,SACEA,UAAU,EACVC,WAAW,EACXC,SAAS,EACTC,eAAe,EACfC,QAAQ,EACRC,YAAY,QACP,iBAAgB;AACvB,OAAOC,SAASC,SAAS,QAAQ,QAAO;AAExC,SAASC,eAAe,QAAQ,mCAAkC;AAClE,SAASC,YAAY,QAAQ,oBAAmB;AAEhD,MAAMC,YAAY;AAElB,OAAO,MAAMC,iBAA6C,CAACC;IACzD,MAAM,EAAEC,EAAE,EAAE,GAAGV;IACf,MAAM,EAAEW,QAAQ,EAAEC,KAAK,EAAE,GAAGX;IAC5B,MAAM,EAAEW,OAAOC,cAAc,EAAE,GAAGZ,SAAiB;QAAEa,MAAM;IAAiB;IAC5E,MAAM,EAAEC,eAAe,EAAE,GAAGhB;IAC5B,MAAM,EAAEiB,UAAU,EAAE,GAAGX;IACvB,MAAM,EAAEY,KAAK,EAAE,GAAGf;IAElB,MAAMgB,mBAAmBH,gBAAgB;QAAEF,gBAAgBA,kBAAkBG;IAAW;IACxF,MAAMG,eAAeb,aAAa;QAAEc,QAAQF,kBAAkBE;IAAO;IAErEhB,UAAU;QACR,IAAIM,MAAM,CAACG,gBAAgB;YACzB;QACF;QAEA,MAAMQ,eAAeJ,OAAOK;QAE5B,IAAIC,MAAMC,OAAO,CAACH,eAAe;YAC/B,MAAMI,eAAeJ,aAAaK,MAAM,CACtC,CAACC,MAAuB,OAAOA,QAAQ,YAAY,CAACA,IAAIC,UAAU,CAAC;YAErE,kDAAkD;YAClDjB,SAASc;QACX,OAAO;YACL,kCAAkC;YAClCd,SAASO,kBAAkBW,OAAOC,kBAAkB,EAAE;QACxD;IACF,GAAG;QAACpB;QAAIG;QAAgBI,OAAOK;QAASJ,kBAAkBW,OAAOC;QAAgBnB;KAAS;IAE1F,MAAMoB,WAAW,CAACC;QAChB,IAAI,CAACA,SAAS;YACZrB,SAAS,EAAE;YACX;QACF;QAEA,MAAMsB,eAAeD,QAAQE,GAAG,CAAC,CAACC,SAChC,OAAOA,WAAW,WAAWA,OAAOvB,KAAK,GAAGuB;QAG9CxB,SAASsB;IACX;IAEA,qBACE,MAACG;QAAIC,WAAW9B;;0BACd,KAACV;gBAAWyC,OAAO7B,MAAM8B,KAAK,CAACD,KAAK;gBAAExB,MAAML,MAAMK,IAAI;;0BACtD,KAAChB;gBACCuC,WAAW9B;gBACXiC,UAAU/B,MAAMgC,QAAQ;gBACxBC,gBAAgB,CAACP,SAAWQ,OAAOR,OAAOvB,KAAK;gBAC/CgC,SAAS,CAAC,MAAM,EAAEnC,MAAMK,IAAI,CAAC+B,OAAO,CAAC,OAAO,OAAO;gBACnDC,aAAa;gBACbC,SAAS;gBACTC,YAAY;gBACZ,uCAAuC;gBACvCjB,UAAUA;gBACVC,SAASb;gBACTP,OACEW,MAAMC,OAAO,CAACZ,SACVA,MAAMsB,GAAG,CAAC,CAACe;oBACT,MAAMC,QAAQ/B,aAAagC,IAAI,CAAC,CAACC,MAAQA,IAAIxC,KAAK,KAAKqC;oBACvD,OAAOC,QAAQ;wBAAE,GAAGA,KAAK;wBAAExC,IAAIuC;oBAAI,IAAI;wBAAEvC,IAAIuC;wBAAKX,OAAOW;wBAAKrC,OAAOqC;oBAAI;gBAC3E,KACA,EAAE;;;;AAKhB,EAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/plugin-import-export",
|
|
3
|
-
"version": "3.47.0-canary.
|
|
3
|
+
"version": "3.47.0-canary.4",
|
|
4
4
|
"description": "Import-Export plugin for Payload",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"payload",
|
|
@@ -64,17 +64,17 @@
|
|
|
64
64
|
"csv-parse": "^5.6.0",
|
|
65
65
|
"csv-stringify": "^6.5.2",
|
|
66
66
|
"qs-esm": "7.0.2",
|
|
67
|
-
"@payloadcms/translations": "3.47.0-canary.
|
|
68
|
-
"@payloadcms/ui": "3.47.0-canary.
|
|
67
|
+
"@payloadcms/translations": "3.47.0-canary.4",
|
|
68
|
+
"@payloadcms/ui": "3.47.0-canary.4"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
+
"@payloadcms/ui": "3.47.0-canary.4",
|
|
71
72
|
"@payloadcms/eslint-config": "3.28.0",
|
|
72
|
-
"
|
|
73
|
-
"payload": "3.47.0-canary.2"
|
|
73
|
+
"payload": "3.47.0-canary.4"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"@payloadcms/ui": "3.47.0-canary.
|
|
77
|
-
"payload": "3.47.0-canary.
|
|
76
|
+
"@payloadcms/ui": "3.47.0-canary.4",
|
|
77
|
+
"payload": "3.47.0-canary.4"
|
|
78
78
|
},
|
|
79
79
|
"homepage:": "https://payloadcms.com",
|
|
80
80
|
"scripts": {
|