payload-smart-cache 1.0.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/README.md +216 -0
- package/dist/client/PublishButton.d.ts +2 -0
- package/dist/client/PublishButton.d.ts.map +1 -0
- package/dist/client/PublishButton.js +34 -0
- package/dist/client/PublishButton.js.map +1 -0
- package/dist/client/requests.d.ts +12 -0
- package/dist/client/requests.d.ts.map +1 -0
- package/dist/client/requests.js +58 -0
- package/dist/client/requests.js.map +1 -0
- package/dist/collections.d.ts +26 -0
- package/dist/collections.d.ts.map +1 -0
- package/dist/collections.js +30 -0
- package/dist/collections.js.map +1 -0
- package/dist/const.d.ts +13 -0
- package/dist/const.d.ts.map +1 -0
- package/dist/const.js +19 -0
- package/dist/const.js.map +1 -0
- package/dist/endpoints/check.d.ts +3 -0
- package/dist/endpoints/check.d.ts.map +1 -0
- package/dist/endpoints/check.js +19 -0
- package/dist/endpoints/check.js.map +1 -0
- package/dist/endpoints/publish.d.ts +4 -0
- package/dist/endpoints/publish.d.ts.map +1 -0
- package/dist/endpoints/publish.js +68 -0
- package/dist/endpoints/publish.js.map +1 -0
- package/dist/exports/rsc.d.ts +2 -0
- package/dist/exports/rsc.d.ts.map +1 -0
- package/dist/exports/rsc.js +5 -0
- package/dist/exports/rsc.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/server/request.d.ts +3 -0
- package/dist/server/request.d.ts.map +1 -0
- package/dist/server/request.js +9 -0
- package/dist/server/request.js.map +1 -0
- package/dist/server/revalidate.d.ts +3 -0
- package/dist/server/revalidate.d.ts.map +1 -0
- package/dist/server/revalidate.js +9 -0
- package/dist/server/revalidate.js.map +1 -0
- package/dist/server/track-changes.d.ts +10 -0
- package/dist/server/track-changes.d.ts.map +1 -0
- package/dist/server/track-changes.js +59 -0
- package/dist/server/track-changes.js.map +1 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/CollectionChanges.d.ts +8 -0
- package/dist/utils/CollectionChanges.d.ts.map +1 -0
- package/dist/utils/CollectionChanges.js +20 -0
- package/dist/utils/CollectionChanges.js.map +1 -0
- package/dist/utils/dependency-graph.d.ts +34 -0
- package/dist/utils/dependency-graph.d.ts.map +1 -0
- package/dist/utils/dependency-graph.js +101 -0
- package/dist/utils/dependency-graph.js.map +1 -0
- package/package.json +91 -0
package/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# payload-smart-cache
|
|
2
|
+
|
|
3
|
+
**payload-smart-cache** manages cache invalidation for your Payload CMS collections.
|
|
4
|
+
|
|
5
|
+
1. Automatically tracks changes to your collections (create, update, delete).
|
|
6
|
+
2. Queues changes for publishing and invalidates cache tags when ready.
|
|
7
|
+
|
|
8
|
+
**Features**
|
|
9
|
+
|
|
10
|
+
- Automatic change tracking for configured collections
|
|
11
|
+
- Publish queue to batch cache invalidations
|
|
12
|
+
- Dependency-aware cache invalidation across related collections
|
|
13
|
+
- Next.js cache tag revalidation integration
|
|
14
|
+
- Publish button in admin panel for manual publishing
|
|
15
|
+
- Configurable operations per collection (create, update, delete)
|
|
16
|
+
|
|
17
|
+
## Getting Started
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# pnpm
|
|
21
|
+
pnpm add payload-smart-cache
|
|
22
|
+
# yarn
|
|
23
|
+
yarn add payload-smart-cache
|
|
24
|
+
# npm
|
|
25
|
+
npm install payload-smart-cache
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 1) Configure Payload
|
|
29
|
+
|
|
30
|
+
Add the plugin to your `payload.config.ts`:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { buildConfig } from "payload";
|
|
34
|
+
import { smartCachPlugin } from "payload-smart-cache";
|
|
35
|
+
|
|
36
|
+
export default buildConfig({
|
|
37
|
+
collections: [Posts, Categories, Users],
|
|
38
|
+
plugins: [
|
|
39
|
+
smartCachPlugin({
|
|
40
|
+
collections: {
|
|
41
|
+
posts: ["create", "update", "delete"],
|
|
42
|
+
categories: ["create", "update"],
|
|
43
|
+
// users: false, // Disable tracking for users
|
|
44
|
+
},
|
|
45
|
+
publishHandler: async (changes) => {
|
|
46
|
+
// Optional: Custom handler for published changes
|
|
47
|
+
console.log("Published changes:", changes);
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2) Use the Publish Button
|
|
55
|
+
|
|
56
|
+
The plugin automatically adds a **Publish** button to your admin panel header. Click it to process all queued changes and invalidate cache tags.
|
|
57
|
+
|
|
58
|
+
### 3) Programmatic Publishing
|
|
59
|
+
|
|
60
|
+
You can also trigger publishing programmatically:
|
|
61
|
+
|
|
62
|
+
**Node.js:**
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import config from "@payload-config";
|
|
66
|
+
import { getPayload } from "payload";
|
|
67
|
+
|
|
68
|
+
const payload = await getPayload({ config });
|
|
69
|
+
const response = await fetch(`${process.env.PAYLOAD_API_URL}/cache-plugin/publish`, {
|
|
70
|
+
method: "POST",
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Edge runtime:**
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
const response = await fetch(`${process.env.PAYLOAD_API_URL}/cache-plugin/publish`, {
|
|
78
|
+
method: "POST",
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Plugin Options
|
|
83
|
+
|
|
84
|
+
The `smartCachPlugin` accepts the following configuration:
|
|
85
|
+
|
|
86
|
+
| Option | Default | Description |
|
|
87
|
+
| ----------------- | -------------------------- | --------------------------------------------------------------------------- |
|
|
88
|
+
| `collections` | All collections tracked | Per-collection configuration for which operations to track |
|
|
89
|
+
| `publishHandler` | - | Optional callback function called after changes are published |
|
|
90
|
+
|
|
91
|
+
### Collection Configuration
|
|
92
|
+
|
|
93
|
+
You can configure tracking per collection:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
smartCachPlugin({
|
|
97
|
+
collections: {
|
|
98
|
+
// Track all operations (create, update, delete)
|
|
99
|
+
posts: ["create", "update", "delete"],
|
|
100
|
+
|
|
101
|
+
// Track only updates
|
|
102
|
+
categories: ["update"],
|
|
103
|
+
|
|
104
|
+
// Disable tracking completely
|
|
105
|
+
users: false,
|
|
106
|
+
|
|
107
|
+
// Use default operations (create, update, delete)
|
|
108
|
+
// If not specified, defaults to all operations
|
|
109
|
+
},
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## How It Works
|
|
114
|
+
|
|
115
|
+
1. **Change Tracking**: When documents are created, updated, or deleted, the plugin automatically adds them to a publish queue.
|
|
116
|
+
|
|
117
|
+
2. **Dependency Resolution**: When publishing, the plugin analyzes relationships between collections and invalidates cache tags for dependent documents.
|
|
118
|
+
|
|
119
|
+
3. **Cache Invalidation**: Uses Next.js `revalidateTag` to invalidate cache tags for affected collections.
|
|
120
|
+
|
|
121
|
+
4. **Publish Queue**: Changes are queued until you explicitly publish them, allowing you to batch invalidations.
|
|
122
|
+
|
|
123
|
+
## Example Usage
|
|
124
|
+
|
|
125
|
+
Here's a complete example showing how to integrate payload-smart-cache:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
// payload.config.ts
|
|
129
|
+
import { buildConfig } from "payload";
|
|
130
|
+
import { smartCachPlugin } from "payload-smart-cache";
|
|
131
|
+
|
|
132
|
+
import { Posts } from "./collections/Posts";
|
|
133
|
+
import { Categories } from "./collections/Categories";
|
|
134
|
+
|
|
135
|
+
export default buildConfig({
|
|
136
|
+
collections: [Posts, Categories],
|
|
137
|
+
plugins: [
|
|
138
|
+
smartCachPlugin({
|
|
139
|
+
collections: {
|
|
140
|
+
posts: ["create", "update", "delete"],
|
|
141
|
+
categories: ["update"], // Only track updates for categories
|
|
142
|
+
},
|
|
143
|
+
publishHandler: async (changes) => {
|
|
144
|
+
// Optional: Send webhook, update external cache, etc.
|
|
145
|
+
await fetch("https://api.example.com/webhook", {
|
|
146
|
+
method: "POST",
|
|
147
|
+
body: JSON.stringify(changes),
|
|
148
|
+
});
|
|
149
|
+
},
|
|
150
|
+
}),
|
|
151
|
+
],
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// app/api/revalidate/route.ts
|
|
157
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
158
|
+
import config from "@payload-config";
|
|
159
|
+
import { getPayload } from "payload";
|
|
160
|
+
|
|
161
|
+
export async function POST(request: NextRequest) {
|
|
162
|
+
const payload = await getPayload({ config });
|
|
163
|
+
|
|
164
|
+
const response = await fetch(
|
|
165
|
+
`${process.env.PAYLOAD_API_URL}/cache-plugin/publish`,
|
|
166
|
+
{
|
|
167
|
+
method: "POST",
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
if (!response.ok) {
|
|
172
|
+
return NextResponse.json(
|
|
173
|
+
{ error: "Failed to publish changes" },
|
|
174
|
+
{ status: 500 }
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return NextResponse.json({ success: true });
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## API Endpoints
|
|
183
|
+
|
|
184
|
+
The plugin provides two endpoints:
|
|
185
|
+
|
|
186
|
+
### POST `/cache-plugin/publish`
|
|
187
|
+
|
|
188
|
+
Publishes all queued changes and invalidates cache tags.
|
|
189
|
+
|
|
190
|
+
**Response:**
|
|
191
|
+
- `200 OK` - Changes published successfully
|
|
192
|
+
- `200 OK` with message "No changes to publish" - Queue is empty
|
|
193
|
+
|
|
194
|
+
### GET `/cache-plugin/check`
|
|
195
|
+
|
|
196
|
+
Checks the status of the publish queue.
|
|
197
|
+
|
|
198
|
+
## Development
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Install dependencies
|
|
202
|
+
pnpm install
|
|
203
|
+
|
|
204
|
+
# Start development server
|
|
205
|
+
pnpm dev
|
|
206
|
+
|
|
207
|
+
# Build the plugin
|
|
208
|
+
pnpm build
|
|
209
|
+
|
|
210
|
+
# Run tests
|
|
211
|
+
pnpm test
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PublishButton.d.ts","sourceRoot":"","sources":["../../src/client/PublishButton.tsx"],"names":[],"mappings":"AAOA,wBAAgB,aAAa,mDAiD5B"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as m } from "react/jsx-runtime";
|
|
3
|
+
import { useConfig as d, useDocumentEvents as p, Button as b, toast as i } from "@payloadcms/ui";
|
|
4
|
+
import { useState as u, useEffect as c } from "react";
|
|
5
|
+
import { checkChanges as C, publishChanges as P } from "./requests.js";
|
|
6
|
+
function B() {
|
|
7
|
+
const { config: o } = d(), { mostRecentUpdate: r } = p(), t = o.serverURL + o.routes.api, [h, s] = u(!1), [l, n] = u(!1);
|
|
8
|
+
c(() => {
|
|
9
|
+
C(t).then((e) => {
|
|
10
|
+
if (!e.success) return s(!0);
|
|
11
|
+
s(e.hasChanges);
|
|
12
|
+
}).catch(() => s(!0));
|
|
13
|
+
}, [t]), c(() => {
|
|
14
|
+
r && s(!0);
|
|
15
|
+
}, [r]);
|
|
16
|
+
const f = async () => {
|
|
17
|
+
n(!0);
|
|
18
|
+
const e = i.loading("Publishing changes..."), { success: g, message: a } = await P(t);
|
|
19
|
+
if (!g) {
|
|
20
|
+
i.error(a, {
|
|
21
|
+
id: e
|
|
22
|
+
}), n(!1);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
i.success(a, {
|
|
26
|
+
id: e
|
|
27
|
+
}), s(!1), n(!1);
|
|
28
|
+
};
|
|
29
|
+
return h ? /* @__PURE__ */ m(b, { disabled: l, onClick: f, children: "Publish Changes" }) : null;
|
|
30
|
+
}
|
|
31
|
+
export {
|
|
32
|
+
B as PublishButton
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=PublishButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PublishButton.js","sources":["../../src/client/PublishButton.tsx"],"sourcesContent":["'use client';\n\nimport { Button, toast, useConfig, useDocumentEvents } from '@payloadcms/ui';\nimport { useEffect, useState } from 'react';\n\nimport { checkChanges, publishChanges } from './requests';\n\nexport function PublishButton() {\n const { config } = useConfig();\n const { mostRecentUpdate } = useDocumentEvents();\n\n const apiUrl = config.serverURL + config.routes.api;\n\n const [hasChanges, setHasChanges] = useState(false);\n const [isPublishing, setIsPublishing] = useState(false);\n\n useEffect(() => {\n checkChanges(apiUrl)\n .then((result) => {\n if (!result.success) return setHasChanges(true);\n setHasChanges(result.hasChanges);\n })\n .catch(() => setHasChanges(true));\n }, [apiUrl]);\n\n useEffect(() => {\n if (!mostRecentUpdate) return;\n setHasChanges(true);\n }, [mostRecentUpdate]);\n\n const handlePublish = async () => {\n setIsPublishing(true);\n const toastId = toast.loading('Publishing changes...');\n const { success, message } = await publishChanges(apiUrl);\n\n if (!success) {\n toast.error(message, {\n id: toastId,\n });\n setIsPublishing(false);\n return;\n }\n toast.success(message, {\n id: toastId,\n });\n setHasChanges(false);\n setIsPublishing(false);\n };\n\n if (!hasChanges) return null;\n\n return (\n <Button disabled={isPublishing} onClick={handlePublish}>\n Publish Changes\n </Button>\n );\n}\n"],"names":["PublishButton","config","useConfig","mostRecentUpdate","useDocumentEvents","apiUrl","hasChanges","setHasChanges","useState","isPublishing","setIsPublishing","useEffect","checkChanges","result","handlePublish","toastId","toast","success","message","publishChanges","Button"],"mappings":";;;;;AAOO,SAASA,IAAgB;AAC9B,QAAM,EAAE,QAAAC,EAAA,IAAWC,EAAA,GACb,EAAE,kBAAAC,EAAA,IAAqBC,EAAA,GAEvBC,IAASJ,EAAO,YAAYA,EAAO,OAAO,KAE1C,CAACK,GAAYC,CAAa,IAAIC,EAAS,EAAK,GAC5C,CAACC,GAAcC,CAAe,IAAIF,EAAS,EAAK;AAEtD,EAAAG,EAAU,MAAM;AACd,IAAAC,EAAaP,CAAM,EAChB,KAAK,CAACQ,MAAW;AAChB,UAAI,CAACA,EAAO,QAAS,QAAON,EAAc,EAAI;AAC9C,MAAAA,EAAcM,EAAO,UAAU;AAAA,IACjC,CAAC,EACA,MAAM,MAAMN,EAAc,EAAI,CAAC;AAAA,EACpC,GAAG,CAACF,CAAM,CAAC,GAEXM,EAAU,MAAM;AACd,IAAKR,KACLI,EAAc,EAAI;AAAA,EACpB,GAAG,CAACJ,CAAgB,CAAC;AAErB,QAAMW,IAAgB,YAAY;AAChC,IAAAJ,EAAgB,EAAI;AACpB,UAAMK,IAAUC,EAAM,QAAQ,uBAAuB,GAC/C,EAAE,SAAAC,GAAS,SAAAC,EAAA,IAAY,MAAMC,EAAed,CAAM;AAExD,QAAI,CAACY,GAAS;AACZ,MAAAD,EAAM,MAAME,GAAS;AAAA,QACnB,IAAIH;AAAA,MAAA,CACL,GACDL,EAAgB,EAAK;AACrB;AAAA,IACF;AACA,IAAAM,EAAM,QAAQE,GAAS;AAAA,MACrB,IAAIH;AAAA,IAAA,CACL,GACDR,EAAc,EAAK,GACnBG,EAAgB,EAAK;AAAA,EACvB;AAEA,SAAKJ,sBAGFc,GAAA,EAAO,UAAUX,GAAc,SAASK,GAAe,UAAA,mBAExD,IALsB;AAO1B;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const publishChanges: (apiUrl: string) => Promise<{
|
|
2
|
+
success: boolean;
|
|
3
|
+
message: string;
|
|
4
|
+
}>;
|
|
5
|
+
export declare const checkChanges: (apiUrl: string) => Promise<{
|
|
6
|
+
success: true;
|
|
7
|
+
hasChanges: boolean;
|
|
8
|
+
} | {
|
|
9
|
+
success: false;
|
|
10
|
+
error: string;
|
|
11
|
+
}>;
|
|
12
|
+
//# sourceMappingURL=requests.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requests.d.ts","sourceRoot":"","sources":["../../src/client/requests.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,WACjB,MAAM,KACb,OAAO,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CA4BA,CAAC;AAEF,eAAO,MAAM,YAAY,WACf,MAAM,KACb,OAAO,CACN;IACE,OAAO,EAAE,IAAI,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;CACrB,GACD;IACE,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAyCJ,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import a from "zod";
|
|
2
|
+
import { ENDPOINT_CONFIG as r } from "../const.js";
|
|
3
|
+
const g = async (o) => {
|
|
4
|
+
try {
|
|
5
|
+
const s = o + r.publish.path, e = await fetch(s, {
|
|
6
|
+
method: r.publish.method
|
|
7
|
+
});
|
|
8
|
+
if (!e.ok) {
|
|
9
|
+
const { success: t, data: c } = a.object({
|
|
10
|
+
message: a.string()
|
|
11
|
+
}).safeParse(await e.json());
|
|
12
|
+
throw new Error(t ? c.message : "Failed to publish changes");
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
success: !0,
|
|
16
|
+
message: "Changes published successfully!"
|
|
17
|
+
};
|
|
18
|
+
} catch (s) {
|
|
19
|
+
return console.error(s), {
|
|
20
|
+
success: !1,
|
|
21
|
+
message: s instanceof Error ? s.message : "Failed to publish changes"
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}, l = async (o) => {
|
|
25
|
+
try {
|
|
26
|
+
const s = o + r.check.path, e = await fetch(s, {
|
|
27
|
+
method: r.check.method,
|
|
28
|
+
headers: {
|
|
29
|
+
"Content-Type": "application/json"
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
if (!e.ok) {
|
|
33
|
+
const { success: n, data: h } = a.object({
|
|
34
|
+
message: a.string()
|
|
35
|
+
}).safeParse(await e.json());
|
|
36
|
+
throw new Error(n ? h.message : "Failed to check changes");
|
|
37
|
+
}
|
|
38
|
+
const { success: t, data: c } = a.object({
|
|
39
|
+
hasChanges: a.boolean()
|
|
40
|
+
}).safeParse(await e.json());
|
|
41
|
+
if (!t)
|
|
42
|
+
throw new Error("Failed to check changes");
|
|
43
|
+
return {
|
|
44
|
+
success: !0,
|
|
45
|
+
hasChanges: c.hasChanges
|
|
46
|
+
};
|
|
47
|
+
} catch (s) {
|
|
48
|
+
return console.error(s), {
|
|
49
|
+
success: !1,
|
|
50
|
+
error: s instanceof Error ? s.message : "Unknown error"
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
export {
|
|
55
|
+
l as checkChanges,
|
|
56
|
+
g as publishChanges
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=requests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requests.js","sources":["../../src/client/requests.ts"],"sourcesContent":["import z from 'zod';\n\nimport { ENDPOINT_CONFIG } from '../const';\n\nexport const publishChanges = async (\n apiUrl: string,\n): Promise<{\n success: boolean;\n message: string;\n}> => {\n try {\n const endpointUrl = apiUrl + ENDPOINT_CONFIG.publish.path;\n const response = await fetch(endpointUrl, {\n method: ENDPOINT_CONFIG.publish.method,\n });\n if (!response.ok) {\n const { success, data } = z\n .object({\n message: z.string(),\n })\n .safeParse(await response.json());\n\n throw new Error(success ? data.message : 'Failed to publish changes');\n }\n return {\n success: true,\n message: 'Changes published successfully!',\n };\n } catch (_error) {\n console.error(_error);\n const message =\n _error instanceof Error ? _error.message : 'Failed to publish changes';\n return {\n success: false,\n message: message,\n };\n }\n};\n\nexport const checkChanges = async (\n apiUrl: string,\n): Promise<\n | {\n success: true;\n hasChanges: boolean;\n }\n | {\n success: false;\n error: string;\n }\n> => {\n try {\n const endpointUrl = apiUrl + ENDPOINT_CONFIG.check.path;\n const response = await fetch(endpointUrl, {\n method: ENDPOINT_CONFIG.check.method,\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n if (!response.ok) {\n const { success, data } = z\n .object({\n message: z.string(),\n })\n .safeParse(await response.json());\n\n throw new Error(success ? data.message : 'Failed to check changes');\n }\n\n const { success, data } = z\n .object({\n hasChanges: z.boolean(),\n })\n .safeParse(await response.json());\n\n if (!success) {\n throw new Error('Failed to check changes');\n }\n\n return {\n success: true,\n hasChanges: data.hasChanges,\n };\n } catch (_error) {\n console.error(_error);\n return {\n success: false,\n error: _error instanceof Error ? _error.message : 'Unknown error',\n };\n }\n};\n"],"names":["publishChanges","apiUrl","endpointUrl","ENDPOINT_CONFIG","response","success","data","z","_error","checkChanges"],"mappings":";;AAIO,MAAMA,IAAiB,OAC5BC,MAII;AACJ,MAAI;AACF,UAAMC,IAAcD,IAASE,EAAgB,QAAQ,MAC/CC,IAAW,MAAM,MAAMF,GAAa;AAAA,MACxC,QAAQC,EAAgB,QAAQ;AAAA,IAAA,CACjC;AACD,QAAI,CAACC,EAAS,IAAI;AAChB,YAAM,EAAE,SAAAC,GAAS,MAAAC,MAASC,EACvB,OAAO;AAAA,QACN,SAASA,EAAE,OAAA;AAAA,MAAO,CACnB,EACA,UAAU,MAAMH,EAAS,MAAM;AAElC,YAAM,IAAI,MAAMC,IAAUC,EAAK,UAAU,2BAA2B;AAAA,IACtE;AACA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,IAAA;AAAA,EAEb,SAASE,GAAQ;AACf,mBAAQ,MAAMA,CAAM,GAGb;AAAA,MACL,SAAS;AAAA,MACT,SAHAA,aAAkB,QAAQA,EAAO,UAAU;AAAA,IAG3C;AAAA,EAEJ;AACF,GAEaC,IAAe,OAC1BR,MAUG;AACH,MAAI;AACF,UAAMC,IAAcD,IAASE,EAAgB,MAAM,MAC7CC,IAAW,MAAM,MAAMF,GAAa;AAAA,MACxC,QAAQC,EAAgB,MAAM;AAAA,MAC9B,SAAS;AAAA,QACP,gBAAgB;AAAA,MAAA;AAAA,IAClB,CACD;AACD,QAAI,CAACC,EAAS,IAAI;AAChB,YAAM,EAAE,SAAAC,GAAS,MAAAC,EAAAA,IAASC,EACvB,OAAO;AAAA,QACN,SAASA,EAAE,OAAA;AAAA,MAAO,CACnB,EACA,UAAU,MAAMH,EAAS,MAAM;AAElC,YAAM,IAAI,MAAMC,IAAUC,EAAK,UAAU,yBAAyB;AAAA,IACpE;AAEA,UAAM,EAAE,SAAAD,GAAS,MAAAC,MAASC,EACvB,OAAO;AAAA,MACN,YAAYA,EAAE,QAAA;AAAA,IAAQ,CACvB,EACA,UAAU,MAAMH,EAAS,MAAM;AAElC,QAAI,CAACC;AACH,YAAM,IAAI,MAAM,yBAAyB;AAG3C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,YAAYC,EAAK;AAAA,IAAA;AAAA,EAErB,SAASE,GAAQ;AACf,mBAAQ,MAAMA,CAAM,GACb;AAAA,MACL,SAAS;AAAA,MACT,OAAOA,aAAkB,QAAQA,EAAO,UAAU;AAAA,IAAA;AAAA,EAEtD;AACF;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const PublishQueue: {
|
|
2
|
+
slug: string;
|
|
3
|
+
admin: {
|
|
4
|
+
hidden: true;
|
|
5
|
+
};
|
|
6
|
+
access: {
|
|
7
|
+
read: ({ req }: import('payload').AccessArgs<any>) => boolean;
|
|
8
|
+
create: ({ req }: import('payload').AccessArgs<any>) => boolean;
|
|
9
|
+
update: ({ req }: import('payload').AccessArgs<any>) => boolean;
|
|
10
|
+
delete: ({ req }: import('payload').AccessArgs<any>) => boolean;
|
|
11
|
+
};
|
|
12
|
+
fields: ({
|
|
13
|
+
name: string;
|
|
14
|
+
type: "text";
|
|
15
|
+
required: true;
|
|
16
|
+
admin?: undefined;
|
|
17
|
+
} | {
|
|
18
|
+
name: string;
|
|
19
|
+
type: "text";
|
|
20
|
+
admin: {
|
|
21
|
+
description: string;
|
|
22
|
+
};
|
|
23
|
+
required?: undefined;
|
|
24
|
+
})[];
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=collections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../src/collections.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;CAyBG,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const t = {
|
|
2
|
+
slug: "publish-queue",
|
|
3
|
+
admin: {
|
|
4
|
+
hidden: !0
|
|
5
|
+
},
|
|
6
|
+
access: {
|
|
7
|
+
read: ({ req: e }) => !!e.user,
|
|
8
|
+
create: ({ req: e }) => !!e.user,
|
|
9
|
+
update: ({ req: e }) => !!e.user,
|
|
10
|
+
delete: ({ req: e }) => !!e.user
|
|
11
|
+
},
|
|
12
|
+
fields: [
|
|
13
|
+
{
|
|
14
|
+
name: "entityType",
|
|
15
|
+
type: "text",
|
|
16
|
+
required: !0
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: "entityId",
|
|
20
|
+
type: "text",
|
|
21
|
+
admin: {
|
|
22
|
+
description: "ID of the changed entity"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
};
|
|
27
|
+
export {
|
|
28
|
+
t as PublishQueue
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=collections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections.js","sources":["../src/collections.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload';\n\nexport const PublishQueue = {\n slug: 'publish-queue',\n admin: {\n hidden: true,\n },\n access: {\n read: ({ req }) => Boolean(req.user),\n create: ({ req }) => Boolean(req.user),\n update: ({ req }) => Boolean(req.user),\n delete: ({ req }) => Boolean(req.user),\n },\n fields: [\n {\n name: 'entityType',\n type: 'text',\n required: true,\n },\n {\n name: 'entityId',\n type: 'text',\n admin: {\n description: 'ID of the changed entity',\n },\n },\n ],\n} satisfies CollectionConfig;\n"],"names":["PublishQueue","req"],"mappings":"AAEO,MAAMA,IAAe;AAAA,EAC1B,MAAM;AAAA,EACN,OAAO;AAAA,IACL,QAAQ;AAAA,EAAA;AAAA,EAEV,QAAQ;AAAA,IACN,MAAM,CAAC,EAAE,KAAAC,QAAU,EAAQA,EAAI;AAAA,IAC/B,QAAQ,CAAC,EAAE,KAAAA,QAAU,EAAQA,EAAI;AAAA,IACjC,QAAQ,CAAC,EAAE,KAAAA,QAAU,EAAQA,EAAI;AAAA,IACjC,QAAQ,CAAC,EAAE,KAAAA,QAAU,EAAQA,EAAI;AAAA,EAAI;AAAA,EAEvC,QAAQ;AAAA,IACN;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,IAAA;AAAA,IAEZ;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,QACL,aAAa;AAAA,MAAA;AAAA,IACf;AAAA,EACF;AAEJ;"}
|
package/dist/const.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CollectionOperation } from './types';
|
|
2
|
+
export declare const ENDPOINT_CONFIG: {
|
|
3
|
+
publish: {
|
|
4
|
+
path: string;
|
|
5
|
+
method: "post";
|
|
6
|
+
};
|
|
7
|
+
check: {
|
|
8
|
+
path: string;
|
|
9
|
+
method: "get";
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export declare const DEFAULT_OPERATIONS: CollectionOperation[];
|
|
13
|
+
//# sourceMappingURL=const.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../src/const.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEnD,eAAO,MAAM,eAAe;;;;;;;;;CASiC,CAAC;AAE9D,eAAO,MAAM,kBAAkB,EAAE,mBAAmB,EAInD,CAAC"}
|
package/dist/const.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const e = {
|
|
2
|
+
publish: {
|
|
3
|
+
path: "/cache-plugin/publish",
|
|
4
|
+
method: "post"
|
|
5
|
+
},
|
|
6
|
+
check: {
|
|
7
|
+
path: "/cache-plugin/check",
|
|
8
|
+
method: "get"
|
|
9
|
+
}
|
|
10
|
+
}, t = [
|
|
11
|
+
"create",
|
|
12
|
+
"update",
|
|
13
|
+
"delete"
|
|
14
|
+
];
|
|
15
|
+
export {
|
|
16
|
+
t as DEFAULT_OPERATIONS,
|
|
17
|
+
e as ENDPOINT_CONFIG
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=const.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"const.js","sources":["../src/const.ts"],"sourcesContent":["import type { Endpoint } from 'payload';\n\nimport type { CollectionOperation } from './types';\n\nexport const ENDPOINT_CONFIG = {\n publish: {\n path: '/cache-plugin/publish',\n method: 'post',\n },\n check: {\n path: '/cache-plugin/check',\n method: 'get',\n },\n} satisfies Record<string, Pick<Endpoint, 'path' | 'method'>>;\n\nexport const DEFAULT_OPERATIONS: CollectionOperation[] = [\n 'create',\n 'update',\n 'delete',\n];\n"],"names":["ENDPOINT_CONFIG","DEFAULT_OPERATIONS"],"mappings":"AAIO,MAAMA,IAAkB;AAAA,EAC7B,SAAS;AAAA,IACP,MAAM;AAAA,IACN,QAAQ;AAAA,EAAA;AAAA,EAEV,OAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ;AAAA,EAAA;AAEZ,GAEaC,IAA4C;AAAA,EACvD;AAAA,EACA;AAAA,EACA;AACF;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/endpoints/check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,SAAS,CAAC;AAIxD,eAAO,MAAM,aAAa,EAAE,QAc3B,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ENDPOINT_CONFIG as n } from "../const.js";
|
|
2
|
+
const c = {
|
|
3
|
+
...n.check,
|
|
4
|
+
handler: async ({ payload: o }) => {
|
|
5
|
+
const { totalDocs: t } = await o.count({
|
|
6
|
+
collection: "publish-queue"
|
|
7
|
+
});
|
|
8
|
+
return Response.json(
|
|
9
|
+
{
|
|
10
|
+
hasChanges: t > 0
|
|
11
|
+
},
|
|
12
|
+
{ status: 200 }
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
export {
|
|
17
|
+
c as checkEndpoint
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sources":["../../src/endpoints/check.ts"],"sourcesContent":["import type { Endpoint, PayloadRequest } from 'payload';\n\nimport { ENDPOINT_CONFIG } from '../const';\n\nexport const checkEndpoint: Endpoint = {\n ...ENDPOINT_CONFIG.check,\n handler: async ({ payload }: PayloadRequest) => {\n const { totalDocs } = await payload.count({\n collection: 'publish-queue',\n });\n\n return Response.json(\n {\n hasChanges: totalDocs > 0,\n },\n { status: 200 },\n );\n },\n};\n"],"names":["checkEndpoint","ENDPOINT_CONFIG","payload","totalDocs"],"mappings":";AAIO,MAAMA,IAA0B;AAAA,EACrC,GAAGC,EAAgB;AAAA,EACnB,SAAS,OAAO,EAAE,SAAAC,QAA8B;AAC9C,UAAM,EAAE,WAAAC,EAAA,IAAc,MAAMD,EAAQ,MAAM;AAAA,MACxC,YAAY;AAAA,IAAA,CACb;AAED,WAAO,SAAS;AAAA,MACd;AAAA,QACE,YAAYC,IAAY;AAAA,MAAA;AAAA,MAE1B,EAAE,QAAQ,IAAA;AAAA,IAAI;AAAA,EAElB;AACF;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/endpoints/publish.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,QAAQ,EAAkB,MAAM,SAAS,CAAC;AAExE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAMvD,eAAO,MAAM,4BAA4B,mBACvB,sBAAsB,CAAC,gBAAgB,CAAC,KACvD,QAwGD,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ENDPOINT_CONFIG as w } from "../const.js";
|
|
2
|
+
import { revalidateCache as y } from "../server/revalidate.js";
|
|
3
|
+
import { CollectionChanges as b } from "../utils/CollectionChanges.js";
|
|
4
|
+
import { createDependencyGraph as I } from "../utils/dependency-graph.js";
|
|
5
|
+
const D = (h) => ({
|
|
6
|
+
...w.publish,
|
|
7
|
+
handler: async ({ payload: i }) => {
|
|
8
|
+
const { docs: s } = await i.find({
|
|
9
|
+
collection: "publish-queue",
|
|
10
|
+
sort: "-updatedAt"
|
|
11
|
+
});
|
|
12
|
+
if (s.length === 0)
|
|
13
|
+
return new Response("No changes to publish", { status: 200 });
|
|
14
|
+
const c = /* @__PURE__ */ new Set(), n = new b();
|
|
15
|
+
n.initialize(s);
|
|
16
|
+
const p = I(i);
|
|
17
|
+
for (const t of s)
|
|
18
|
+
await i.delete({
|
|
19
|
+
collection: "publish-queue",
|
|
20
|
+
id: t.id
|
|
21
|
+
});
|
|
22
|
+
async function l(t, a, r) {
|
|
23
|
+
const d = p.getDependants(t);
|
|
24
|
+
if (d.length !== 0)
|
|
25
|
+
for (const e of d) {
|
|
26
|
+
if (e.entity.type === "global") {
|
|
27
|
+
c.add(e.entity.slug);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (r.has(e.entity.slug)) continue;
|
|
31
|
+
const u = /* @__PURE__ */ new Map();
|
|
32
|
+
for (const o of e.fields) {
|
|
33
|
+
const { docs: m } = await i.find({
|
|
34
|
+
collection: e.entity.slug,
|
|
35
|
+
where: {
|
|
36
|
+
[o.field]: {
|
|
37
|
+
in: a
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
for (const g of m)
|
|
42
|
+
u.set(g.id.toString(), g);
|
|
43
|
+
}
|
|
44
|
+
const f = Array.from(u.values());
|
|
45
|
+
if (r.add(e.entity.slug), f.length !== 0) {
|
|
46
|
+
for (const o of f)
|
|
47
|
+
n.addItem(e.entity.slug, o.id.toString());
|
|
48
|
+
return l(
|
|
49
|
+
e.entity.slug,
|
|
50
|
+
f.map((o) => o.id.toString()),
|
|
51
|
+
r
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
for (const [t, a] of n.entries())
|
|
57
|
+
await l(t, Array.from(a), /* @__PURE__ */ new Set());
|
|
58
|
+
for (const t of n.keys())
|
|
59
|
+
c.add(t);
|
|
60
|
+
for (const t of c)
|
|
61
|
+
await y(t);
|
|
62
|
+
return await h?.(n.serialize()), new Response("OK");
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
export {
|
|
66
|
+
D as createPublishChangesEndpoint
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sources":["../../src/endpoints/publish.ts"],"sourcesContent":["import type { CollectionSlug, Endpoint, PayloadRequest } from 'payload';\nimport { ENDPOINT_CONFIG } from '../const';\nimport type { SmartCachePluginConfig } from '../index';\nimport { revalidateCache } from '../server/revalidate';\nimport type { EntitySlug, PublishQueue } from '../types';\nimport { CollectionChanges } from '../utils/CollectionChanges';\nimport { createDependencyGraph } from '../utils/dependency-graph';\n\nexport const createPublishChangesEndpoint = (\n publishHandler: SmartCachePluginConfig['publishHandler'],\n): Endpoint => ({\n ...ENDPOINT_CONFIG.publish,\n handler: async ({ payload }: PayloadRequest) => {\n const { docs: changesToPublish } = await payload.find({\n collection: 'publish-queue',\n sort: '-updatedAt',\n });\n\n if (changesToPublish.length === 0)\n return new Response('No changes to publish', { status: 200 });\n\n const tagsToInvalidate = new Set<EntitySlug>();\n const collectionChanges = new CollectionChanges();\n\n collectionChanges.initialize(changesToPublish as PublishQueue[]);\n\n const graph = createDependencyGraph(payload);\n\n for (const change of changesToPublish) {\n // Delete the change record (it's been processed)\n await payload.delete({\n collection: 'publish-queue',\n id: change.id,\n });\n }\n\n async function trackAffectedItems(\n collection: CollectionSlug,\n ids: string[],\n visited: Set<string>,\n ): Promise<void> {\n const dependents = graph.getDependants(collection);\n\n if (dependents.length === 0) return;\n\n for (const dependent of dependents) {\n if (dependent.entity.type === 'global') {\n // This causes too many revalidations, but maybe we can skip this completely?\n tagsToInvalidate.add(dependent.entity.slug);\n continue;\n }\n\n if (visited.has(dependent.entity.slug)) continue;\n\n // Query each field separately to avoid duplicate table alias errors\n // when multiple fields map to the same table (e.g., highlights.split-image-text.image\n // and architecture.split-image-text.image both use projects_blocks_split_image_text)\n const allAffectedItems = new Map<\n string,\n {\n id: string | number;\n }\n >();\n\n for (const field of dependent.fields) {\n const { docs } = await payload.find({\n collection: dependent.entity.slug,\n where: {\n [field.field]: {\n in: ids,\n },\n },\n });\n\n // Use a Map keyed by ID to deduplicate results\n for (const item of docs) {\n allAffectedItems.set(item.id.toString(), item);\n }\n }\n\n const affectedItems = Array.from(allAffectedItems.values());\n\n visited.add(dependent.entity.slug);\n\n if (affectedItems.length === 0) continue;\n\n for (const item of affectedItems) {\n collectionChanges.addItem(dependent.entity.slug, item.id.toString());\n }\n\n return trackAffectedItems(\n dependent.entity.slug,\n affectedItems.map((item) => item.id.toString()),\n visited,\n );\n }\n }\n\n for (const [collection, ids] of collectionChanges.entries()) {\n await trackAffectedItems(collection, Array.from(ids), new Set<string>());\n }\n\n for (const entity of collectionChanges.keys()) {\n tagsToInvalidate.add(entity);\n }\n\n for (const tag of tagsToInvalidate) {\n await revalidateCache(tag);\n }\n\n await publishHandler?.(collectionChanges.serialize());\n\n return new Response('OK');\n },\n});\n"],"names":["createPublishChangesEndpoint","publishHandler","ENDPOINT_CONFIG","payload","changesToPublish","tagsToInvalidate","collectionChanges","CollectionChanges","graph","createDependencyGraph","change","trackAffectedItems","collection","ids","visited","dependents","dependent","allAffectedItems","field","docs","item","affectedItems","entity","tag","revalidateCache"],"mappings":";;;;AAQO,MAAMA,IAA+B,CAC1CC,OACc;AAAA,EACd,GAAGC,EAAgB;AAAA,EACnB,SAAS,OAAO,EAAE,SAAAC,QAA8B;AAC9C,UAAM,EAAE,MAAMC,EAAA,IAAqB,MAAMD,EAAQ,KAAK;AAAA,MACpD,YAAY;AAAA,MACZ,MAAM;AAAA,IAAA,CACP;AAED,QAAIC,EAAiB,WAAW;AAC9B,aAAO,IAAI,SAAS,yBAAyB,EAAE,QAAQ,KAAK;AAE9D,UAAMC,wBAAuB,IAAA,GACvBC,IAAoB,IAAIC,EAAA;AAE9B,IAAAD,EAAkB,WAAWF,CAAkC;AAE/D,UAAMI,IAAQC,EAAsBN,CAAO;AAE3C,eAAWO,KAAUN;AAEnB,YAAMD,EAAQ,OAAO;AAAA,QACnB,YAAY;AAAA,QACZ,IAAIO,EAAO;AAAA,MAAA,CACZ;AAGH,mBAAeC,EACbC,GACAC,GACAC,GACe;AACf,YAAMC,IAAaP,EAAM,cAAcI,CAAU;AAEjD,UAAIG,EAAW,WAAW;AAE1B,mBAAWC,KAAaD,GAAY;AAClC,cAAIC,EAAU,OAAO,SAAS,UAAU;AAEtC,YAAAX,EAAiB,IAAIW,EAAU,OAAO,IAAI;AAC1C;AAAA,UACF;AAEA,cAAIF,EAAQ,IAAIE,EAAU,OAAO,IAAI,EAAG;AAKxC,gBAAMC,wBAAuB,IAAA;AAO7B,qBAAWC,KAASF,EAAU,QAAQ;AACpC,kBAAM,EAAE,MAAAG,EAAA,IAAS,MAAMhB,EAAQ,KAAK;AAAA,cAClC,YAAYa,EAAU,OAAO;AAAA,cAC7B,OAAO;AAAA,gBACL,CAACE,EAAM,KAAK,GAAG;AAAA,kBACb,IAAIL;AAAA,gBAAA;AAAA,cACN;AAAA,YACF,CACD;AAGD,uBAAWO,KAAQD;AACjB,cAAAF,EAAiB,IAAIG,EAAK,GAAG,SAAA,GAAYA,CAAI;AAAA,UAEjD;AAEA,gBAAMC,IAAgB,MAAM,KAAKJ,EAAiB,QAAQ;AAI1D,cAFAH,EAAQ,IAAIE,EAAU,OAAO,IAAI,GAE7BK,EAAc,WAAW,GAE7B;AAAA,uBAAWD,KAAQC;AACjB,cAAAf,EAAkB,QAAQU,EAAU,OAAO,MAAMI,EAAK,GAAG,UAAU;AAGrE,mBAAOT;AAAA,cACLK,EAAU,OAAO;AAAA,cACjBK,EAAc,IAAI,CAACD,MAASA,EAAK,GAAG,UAAU;AAAA,cAC9CN;AAAA,YAAA;AAAA;AAAA,QAEJ;AAAA,IACF;AAEA,eAAW,CAACF,GAAYC,CAAG,KAAKP,EAAkB;AAChD,YAAMK,EAAmBC,GAAY,MAAM,KAAKC,CAAG,GAAG,oBAAI,KAAa;AAGzE,eAAWS,KAAUhB,EAAkB;AACrC,MAAAD,EAAiB,IAAIiB,CAAM;AAG7B,eAAWC,KAAOlB;AAChB,YAAMmB,EAAgBD,CAAG;AAG3B,iBAAMtB,IAAiBK,EAAkB,WAAW,GAE7C,IAAI,SAAS,IAAI;AAAA,EAC1B;AACF;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rsc.d.ts","sourceRoot":"","sources":["../../src/exports/rsc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rsc.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CollectionSlug, Plugin } from 'payload';
|
|
2
|
+
import { ChangedDocuments, CollectionOperation } from './types';
|
|
3
|
+
export interface SmartCachePluginConfig {
|
|
4
|
+
collections?: Partial<Record<CollectionSlug, CollectionOperation[] | false>>;
|
|
5
|
+
publishHandler?: (changes: ChangedDocuments) => void | Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export declare const smartCachePlugin: ({ collections: collectionOperations, publishHandler, }: SmartCachePluginConfig) => Plugin;
|
|
8
|
+
export { createRequestHandler } from './server/request';
|
|
9
|
+
export type { ChangedDocuments } from './types';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAStD,OAAO,KAAK,EACV,gBAAgB,EAEhB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,mBAAmB,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;IAC7E,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE;AAED,eAAO,MAAM,gBAAgB,2DAIxB,sBAAsB,KAAG,MAwD3B,CAAC;AAEJ,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { PublishQueue as i } from "./collections.js";
|
|
2
|
+
import { DEFAULT_OPERATIONS as u } from "./const.js";
|
|
3
|
+
import { checkEndpoint as l } from "./endpoints/check.js";
|
|
4
|
+
import { createPublishChangesEndpoint as m } from "./endpoints/publish.js";
|
|
5
|
+
import { trackCollectionChange as d, trackCollectionDelete as c } from "./server/track-changes.js";
|
|
6
|
+
import { createRequestHandler as x } from "./server/request.js";
|
|
7
|
+
const E = ({
|
|
8
|
+
collections: n = {},
|
|
9
|
+
publishHandler: h
|
|
10
|
+
}) => (e) => (e.admin ??= {}, e.admin.components ??= {}, e.admin.components.actions ??= [], e.admin.components.actions.push({
|
|
11
|
+
path: "payload-smart-cache/rsc#PublishButton"
|
|
12
|
+
}), e.collections ??= [], e.collections.forEach((t) => {
|
|
13
|
+
const s = n[t.slug] ?? u;
|
|
14
|
+
if (s === !1 || s.length === 0) return;
|
|
15
|
+
t.hooks ??= {};
|
|
16
|
+
const { hasDeleteOperation: p, changeOperations: o } = s.reduce(
|
|
17
|
+
(r, a) => (a === "delete" ? r.hasDeleteOperation = !0 : r.changeOperations.push(a), r),
|
|
18
|
+
{
|
|
19
|
+
hasDeleteOperation: !1,
|
|
20
|
+
changeOperations: []
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
o.length > 0 && (t.hooks.afterChange ??= [], t.hooks.afterChange.push(
|
|
24
|
+
d(o)
|
|
25
|
+
)), p && (t.hooks.afterDelete ??= [], t.hooks.afterDelete.push(c));
|
|
26
|
+
}), e.collections.push(i), e.endpoints ??= [], e.endpoints.push(m(h)), e.endpoints.push(l), e);
|
|
27
|
+
export {
|
|
28
|
+
x as createRequestHandler,
|
|
29
|
+
E as smartCachePlugin
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import type { CollectionSlug, Plugin } from 'payload';\nimport { PublishQueue } from './collections';\nimport { DEFAULT_OPERATIONS } from './const';\nimport { checkEndpoint } from './endpoints/check';\nimport { createPublishChangesEndpoint } from './endpoints/publish';\nimport {\n trackCollectionChange,\n trackCollectionDelete,\n} from './server/track-changes';\nimport type {\n ChangedDocuments,\n CollectionChangeOperation,\n CollectionOperation,\n} from './types';\n\nexport interface SmartCachePluginConfig {\n collections?: Partial<Record<CollectionSlug, CollectionOperation[] | false>>;\n publishHandler?: (changes: ChangedDocuments) => void | Promise<void>;\n}\n\nexport const smartCachePlugin =\n ({\n collections: collectionOperations = {},\n publishHandler,\n }: SmartCachePluginConfig): Plugin =>\n (config) => {\n config.admin ??= {};\n config.admin.components ??= {};\n config.admin.components.actions ??= [];\n config.admin.components.actions.push({\n path: 'payload-smart-cache/rsc#PublishButton',\n });\n\n config.collections ??= [];\n config.collections.forEach((collection) => {\n const operations =\n collectionOperations[collection.slug as CollectionSlug] ??\n DEFAULT_OPERATIONS;\n if (operations === false) return;\n if (operations.length === 0) return;\n\n collection.hooks ??= {};\n\n const { hasDeleteOperation, changeOperations } = operations.reduce<{\n hasDeleteOperation: boolean;\n changeOperations: CollectionChangeOperation[];\n }>(\n (acc, operation) => {\n if (operation === 'delete') {\n acc.hasDeleteOperation = true;\n } else {\n acc.changeOperations.push(operation);\n }\n return acc;\n },\n {\n hasDeleteOperation: false,\n changeOperations: [],\n },\n );\n\n if (changeOperations.length > 0) {\n collection.hooks.afterChange ??= [];\n collection.hooks.afterChange.push(\n trackCollectionChange(changeOperations),\n );\n }\n if (hasDeleteOperation) {\n collection.hooks.afterDelete ??= [];\n collection.hooks.afterDelete.push(trackCollectionDelete);\n }\n });\n\n config.collections.push(PublishQueue);\n\n config.endpoints ??= [];\n config.endpoints.push(createPublishChangesEndpoint(publishHandler));\n config.endpoints.push(checkEndpoint);\n\n return config;\n };\n\nexport { createRequestHandler } from './server/request';\nexport type { ChangedDocuments } from './types';\n"],"names":["smartCachePlugin","collectionOperations","publishHandler","config","collection","operations","DEFAULT_OPERATIONS","hasDeleteOperation","changeOperations","acc","operation","trackCollectionChange","trackCollectionDelete","PublishQueue","createPublishChangesEndpoint","checkEndpoint"],"mappings":";;;;;;AAoBO,MAAMA,IACX,CAAC;AAAA,EACC,aAAaC,IAAuB,CAAA;AAAA,EACpC,gBAAAC;AACF,MACA,CAACC,OACCA,EAAO,UAAU,CAAA,GACjBA,EAAO,MAAM,eAAe,CAAA,GAC5BA,EAAO,MAAM,WAAW,YAAY,CAAA,GACpCA,EAAO,MAAM,WAAW,QAAQ,KAAK;AAAA,EACnC,MAAM;AAAA,CACP,GAEDA,EAAO,gBAAgB,CAAA,GACvBA,EAAO,YAAY,QAAQ,CAACC,MAAe;AACzC,QAAMC,IACJJ,EAAqBG,EAAW,IAAsB,KACtDE;AAEF,MADID,MAAe,MACfA,EAAW,WAAW,EAAG;AAE7B,EAAAD,EAAW,UAAU,CAAA;AAErB,QAAM,EAAE,oBAAAG,GAAoB,kBAAAC,EAAA,IAAqBH,EAAW;AAAA,IAI1D,CAACI,GAAKC,OACAA,MAAc,WAChBD,EAAI,qBAAqB,KAEzBA,EAAI,iBAAiB,KAAKC,CAAS,GAE9BD;AAAA,IAET;AAAA,MACE,oBAAoB;AAAA,MACpB,kBAAkB,CAAA;AAAA,IAAC;AAAA,EACrB;AAGF,EAAID,EAAiB,SAAS,MAC5BJ,EAAW,MAAM,gBAAgB,CAAA,GACjCA,EAAW,MAAM,YAAY;AAAA,IAC3BO,EAAsBH,CAAgB;AAAA,EAAA,IAGtCD,MACFH,EAAW,MAAM,gBAAgB,CAAA,GACjCA,EAAW,MAAM,YAAY,KAAKQ,CAAqB;AAE3D,CAAC,GAEDT,EAAO,YAAY,KAAKU,CAAY,GAEpCV,EAAO,cAAc,CAAA,GACrBA,EAAO,UAAU,KAAKW,EAA6BZ,CAAc,CAAC,GAClEC,EAAO,UAAU,KAAKY,CAAa,GAE5BZ;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/server/request.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,eAAO,MAAM,oBAAoB,GAAI,IAAI,EAAE,MAAM,SAAS,OAAO,EAAE,WACxD,CAAC,GAAG,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,SACtC,UAAU,EAAE,KAClB,CAAC,CAAC,GAAG,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAIpC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.js","sources":["../../src/server/request.ts"],"sourcesContent":["import { unstable_cache } from 'next/cache';\n\nimport type { EntitySlug } from '../types';\n\nexport const createRequestHandler = <Data, Inputs extends unknown[]>(\n handler: (...inputs: Inputs) => Promise<Data>,\n tags?: EntitySlug[],\n): ((...inputs: Inputs) => Promise<Data>) =>\n unstable_cache(handler, undefined, {\n tags,\n revalidate: false,\n });\n"],"names":["createRequestHandler","handler","tags","unstable_cache"],"mappings":";AAIO,MAAMA,IAAuB,CAClCC,GACAC,MAEAC,EAAeF,GAAS,QAAW;AAAA,EACjC,MAAAC;AAAA,EACA,YAAY;AACd,CAAC;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revalidate.d.ts","sourceRoot":"","sources":["../../src/server/revalidate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,eAAO,MAAM,eAAe,QAAe,UAAU,kBAGpD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revalidate.js","sources":["../../src/server/revalidate.ts"],"sourcesContent":["'use server';\n\nimport { revalidateTag } from 'next/cache';\n\nimport type { EntitySlug } from '../types';\n\nexport const revalidateCache = async (tag: EntitySlug) => {\n console.log('INVALIDATE CACHE', tag);\n revalidateTag(tag);\n};\n"],"names":["revalidateCache","tag","revalidateTag"],"mappings":";;AAMO,MAAMA,IAAkB,OAAOC,MAAoB;AACxD,UAAQ,IAAI,oBAAoBA,CAAG,GACnCC,EAAcD,CAAG;AACnB;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CollectionAfterChangeHook, CollectionAfterDeleteHook, GlobalAfterChangeHook } from 'payload';
|
|
2
|
+
import { CollectionChangeOperation } from '../types';
|
|
3
|
+
export declare const trackCollectionChange: (operations: CollectionChangeOperation[]) => CollectionAfterChangeHook<{
|
|
4
|
+
id: string | number;
|
|
5
|
+
}>;
|
|
6
|
+
export declare const trackCollectionDelete: CollectionAfterDeleteHook<{
|
|
7
|
+
id: string | number;
|
|
8
|
+
}>;
|
|
9
|
+
export declare const trackGlobalChange: GlobalAfterChangeHook;
|
|
10
|
+
//# sourceMappingURL=track-changes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track-changes.d.ts","sourceRoot":"","sources":["../../src/server/track-changes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,yBAAyB,EACzB,qBAAqB,EACtB,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAE1D,eAAO,MAAM,qBAAqB,eAElB,yBAAyB,EAAE,KACtC,yBAAyB,CAAC;IAC3B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB,CAuCA,CAAC;AAEJ,eAAO,MAAM,qBAAqB,EAAE,yBAAyB,CAAC;IAC5D,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;CACrB,CAoCA,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,qBAmC/B,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const s = (e) => async ({ req: { payload: t }, doc: c, collection: n, operation: a }) => {
|
|
2
|
+
if (!e.includes(a)) return;
|
|
3
|
+
const i = n.slug, l = c.id.toString(), {
|
|
4
|
+
docs: [u]
|
|
5
|
+
} = await t.find({
|
|
6
|
+
collection: "publish-queue",
|
|
7
|
+
where: {
|
|
8
|
+
and: [
|
|
9
|
+
{ entityType: { equals: i } },
|
|
10
|
+
{ entityId: { equals: l } }
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
limit: 1
|
|
14
|
+
});
|
|
15
|
+
u ? await t.update({
|
|
16
|
+
collection: "publish-queue",
|
|
17
|
+
id: u.id,
|
|
18
|
+
data: {
|
|
19
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
20
|
+
}
|
|
21
|
+
}) : await t.create({
|
|
22
|
+
collection: "publish-queue",
|
|
23
|
+
data: {
|
|
24
|
+
entityType: i,
|
|
25
|
+
entityId: l
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}, o = async ({ req: { payload: e }, doc: t, collection: c }) => {
|
|
29
|
+
const n = c.slug, a = t.id.toString(), {
|
|
30
|
+
docs: [i]
|
|
31
|
+
} = await e.find({
|
|
32
|
+
collection: "publish-queue",
|
|
33
|
+
where: {
|
|
34
|
+
and: [
|
|
35
|
+
{ entityType: { equals: n } },
|
|
36
|
+
{ entityId: { equals: a } }
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
limit: 1
|
|
40
|
+
});
|
|
41
|
+
i ? await e.update({
|
|
42
|
+
collection: "publish-queue",
|
|
43
|
+
id: i.id,
|
|
44
|
+
data: {
|
|
45
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
46
|
+
}
|
|
47
|
+
}) : await e.create({
|
|
48
|
+
collection: "publish-queue",
|
|
49
|
+
data: {
|
|
50
|
+
entityType: n,
|
|
51
|
+
entityId: a
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
export {
|
|
56
|
+
s as trackCollectionChange,
|
|
57
|
+
o as trackCollectionDelete
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=track-changes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track-changes.js","sources":["../../src/server/track-changes.ts"],"sourcesContent":["import type {\n CollectionAfterChangeHook,\n CollectionAfterDeleteHook,\n GlobalAfterChangeHook,\n} from 'payload';\n\nimport type { CollectionChangeOperation } from '../types';\n\nexport const trackCollectionChange =\n (\n operations: CollectionChangeOperation[],\n ): CollectionAfterChangeHook<{\n id: string | number;\n }> =>\n async ({ req: { payload }, doc, collection, operation }) => {\n if (!operations.includes(operation)) return;\n\n const entityType = collection.slug;\n const entityId = doc.id.toString();\n\n // Check if this entity already has a pending change\n const {\n docs: [existingChange],\n } = await payload.find({\n collection: 'publish-queue',\n where: {\n and: [\n { entityType: { equals: entityType } },\n { entityId: { equals: entityId } },\n ],\n },\n limit: 1,\n });\n\n if (existingChange) {\n // Update existing change record\n await payload.update({\n collection: 'publish-queue',\n id: existingChange.id,\n data: {\n updatedAt: new Date().toISOString(),\n },\n });\n } else {\n await payload.create({\n collection: 'publish-queue',\n data: {\n entityType,\n entityId,\n },\n });\n }\n };\n\nexport const trackCollectionDelete: CollectionAfterDeleteHook<{\n id: string | number;\n}> = async ({ req: { payload }, doc, collection }) => {\n const entityType = collection.slug;\n const entityId = doc.id.toString();\n\n // Check if this entity already has a pending change\n const {\n docs: [existingChange],\n } = await payload.find({\n collection: 'publish-queue',\n where: {\n and: [\n { entityType: { equals: entityType } },\n { entityId: { equals: entityId } },\n ],\n },\n limit: 1,\n });\n\n if (existingChange) {\n // Update existing change record\n await payload.update({\n collection: 'publish-queue',\n id: existingChange.id,\n data: {\n updatedAt: new Date().toISOString(),\n },\n });\n } else {\n await payload.create({\n collection: 'publish-queue',\n data: {\n entityType,\n entityId,\n },\n });\n }\n};\n\nexport const trackGlobalChange: GlobalAfterChangeHook = async ({\n req: { payload },\n global,\n}) => {\n const entityType = global.slug;\n\n // Check if this entity already has a pending change\n const {\n docs: [existingChange],\n } = await payload.find({\n collection: 'publish-queue',\n where: {\n and: [{ entityType: { equals: entityType } }],\n },\n limit: 1,\n });\n\n if (existingChange) {\n // Update existing change record\n await payload.update({\n collection: 'publish-queue',\n id: existingChange.id,\n data: {\n updatedAt: new Date().toISOString(),\n },\n });\n } else {\n // Create new change record\n await payload.create({\n collection: 'publish-queue',\n data: {\n entityType,\n },\n });\n }\n};\n"],"names":["trackCollectionChange","operations","payload","doc","collection","operation","entityType","entityId","existingChange","trackCollectionDelete"],"mappings":"AAQO,MAAMA,IACX,CACEC,MAIF,OAAO,EAAE,KAAK,EAAE,SAAAC,EAAA,GAAW,KAAAC,GAAK,YAAAC,GAAY,WAAAC,QAAgB;AAC1D,MAAI,CAACJ,EAAW,SAASI,CAAS,EAAG;AAErC,QAAMC,IAAaF,EAAW,MACxBG,IAAWJ,EAAI,GAAG,SAAA,GAGlB;AAAA,IACJ,MAAM,CAACK,CAAc;AAAA,EAAA,IACnB,MAAMN,EAAQ,KAAK;AAAA,IACrB,YAAY;AAAA,IACZ,OAAO;AAAA,MACL,KAAK;AAAA,QACH,EAAE,YAAY,EAAE,QAAQI,IAAW;AAAA,QACnC,EAAE,UAAU,EAAE,QAAQC,IAAS;AAAA,MAAE;AAAA,IACnC;AAAA,IAEF,OAAO;AAAA,EAAA,CACR;AAED,EAAIC,IAEF,MAAMN,EAAQ,OAAO;AAAA,IACnB,YAAY;AAAA,IACZ,IAAIM,EAAe;AAAA,IACnB,MAAM;AAAA,MACJ,YAAW,oBAAI,KAAA,GAAO,YAAA;AAAA,IAAY;AAAA,EACpC,CACD,IAED,MAAMN,EAAQ,OAAO;AAAA,IACnB,YAAY;AAAA,IACZ,MAAM;AAAA,MACJ,YAAAI;AAAA,MACA,UAAAC;AAAA,IAAA;AAAA,EACF,CACD;AAEL,GAEWE,IAER,OAAO,EAAE,KAAK,EAAE,SAAAP,EAAA,GAAW,KAAAC,GAAK,YAAAC,QAAiB;AACpD,QAAME,IAAaF,EAAW,MACxBG,IAAWJ,EAAI,GAAG,SAAA,GAGlB;AAAA,IACJ,MAAM,CAACK,CAAc;AAAA,EAAA,IACnB,MAAMN,EAAQ,KAAK;AAAA,IACrB,YAAY;AAAA,IACZ,OAAO;AAAA,MACL,KAAK;AAAA,QACH,EAAE,YAAY,EAAE,QAAQI,IAAW;AAAA,QACnC,EAAE,UAAU,EAAE,QAAQC,IAAS;AAAA,MAAE;AAAA,IACnC;AAAA,IAEF,OAAO;AAAA,EAAA,CACR;AAED,EAAIC,IAEF,MAAMN,EAAQ,OAAO;AAAA,IACnB,YAAY;AAAA,IACZ,IAAIM,EAAe;AAAA,IACnB,MAAM;AAAA,MACJ,YAAW,oBAAI,KAAA,GAAO,YAAA;AAAA,IAAY;AAAA,EACpC,CACD,IAED,MAAMN,EAAQ,OAAO;AAAA,IACnB,YAAY;AAAA,IACZ,MAAM;AAAA,MACJ,YAAAI;AAAA,MACA,UAAAC;AAAA,IAAA;AAAA,EACF,CACD;AAEL;"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CollectionSlug, GlobalSlug } from 'payload';
|
|
2
|
+
export type EntitySlug = CollectionSlug | GlobalSlug;
|
|
3
|
+
export type CollectionOperation = CollectionChangeOperation | 'delete';
|
|
4
|
+
export type CollectionChangeOperation = 'create' | 'update';
|
|
5
|
+
type CollectionId = string;
|
|
6
|
+
export type ChangedDocuments = Partial<Record<CollectionSlug, CollectionId[]>>;
|
|
7
|
+
export interface PublishQueue {
|
|
8
|
+
id: number;
|
|
9
|
+
entityType: string;
|
|
10
|
+
/**
|
|
11
|
+
* ID of the changed entity
|
|
12
|
+
*/
|
|
13
|
+
entityId?: string | null;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1D,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,UAAU,CAAC;AAErD,MAAM,MAAM,mBAAmB,GAAG,yBAAyB,GAAG,QAAQ,CAAC;AAEvE,MAAM,MAAM,yBAAyB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE5D,KAAK,YAAY,GAAG,MAAM,CAAC;AAE3B,MAAM,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;AAG/E,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CollectionSlug } from 'payload';
|
|
2
|
+
import { PublishQueue } from '../types';
|
|
3
|
+
export declare class CollectionChanges extends Map<CollectionSlug, Set<string>> {
|
|
4
|
+
initialize(changes: PublishQueue[]): void;
|
|
5
|
+
addItem(collection: CollectionSlug, id: string): void;
|
|
6
|
+
serialize(): Partial<Record<CollectionSlug, string[]>>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=CollectionChanges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CollectionChanges.d.ts","sourceRoot":"","sources":["../../src/utils/CollectionChanges.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,qBAAa,iBAAkB,SAAQ,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrE,UAAU,CAAC,OAAO,EAAE,YAAY,EAAE;IAQlC,OAAO,CAAC,UAAU,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM;IAS9C,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC;CAOvD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class n extends Map {
|
|
2
|
+
initialize(e) {
|
|
3
|
+
for (const t of e)
|
|
4
|
+
typeof t.entityId == "string" && this.addItem(t.entityType, t.entityId);
|
|
5
|
+
}
|
|
6
|
+
addItem(e, t) {
|
|
7
|
+
const s = this.get(e);
|
|
8
|
+
s ? s.add(t) : this.set(e, /* @__PURE__ */ new Set([t]));
|
|
9
|
+
}
|
|
10
|
+
serialize() {
|
|
11
|
+
const e = {};
|
|
12
|
+
for (const [t, s] of this.entries())
|
|
13
|
+
e[t] = Array.from(s);
|
|
14
|
+
return e;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
n as CollectionChanges
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=CollectionChanges.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CollectionChanges.js","sources":["../../src/utils/CollectionChanges.ts"],"sourcesContent":["import type { CollectionSlug } from 'payload';\n\nimport type { PublishQueue } from '../types';\n\nexport class CollectionChanges extends Map<CollectionSlug, Set<string>> {\n initialize(changes: PublishQueue[]) {\n for (const change of changes) {\n if (typeof change.entityId !== 'string') continue;\n\n this.addItem(change.entityType as CollectionSlug, change.entityId);\n }\n }\n\n addItem(collection: CollectionSlug, id: string) {\n const changedIds = this.get(collection);\n if (changedIds) {\n changedIds.add(id);\n } else {\n this.set(collection, new Set([id]));\n }\n }\n\n serialize(): Partial<Record<CollectionSlug, string[]>> {\n const result: Partial<Record<CollectionSlug, string[]>> = {};\n for (const [collection, ids] of this.entries()) {\n result[collection] = Array.from(ids);\n }\n return result;\n }\n}\n"],"names":["CollectionChanges","changes","change","collection","id","changedIds","result","ids"],"mappings":"AAIO,MAAMA,UAA0B,IAAiC;AAAA,EACtE,WAAWC,GAAyB;AAClC,eAAWC,KAAUD;AACnB,MAAI,OAAOC,EAAO,YAAa,YAE/B,KAAK,QAAQA,EAAO,YAA8BA,EAAO,QAAQ;AAAA,EAErE;AAAA,EAEA,QAAQC,GAA4BC,GAAY;AAC9C,UAAMC,IAAa,KAAK,IAAIF,CAAU;AACtC,IAAIE,IACFA,EAAW,IAAID,CAAE,IAEjB,KAAK,IAAID,GAAY,oBAAI,IAAI,CAACC,CAAE,CAAC,CAAC;AAAA,EAEtC;AAAA,EAEA,YAAuD;AACrD,UAAME,IAAoD,CAAA;AAC1D,eAAW,CAACH,GAAYI,CAAG,KAAK,KAAK;AACnC,MAAAD,EAAOH,CAAU,IAAI,MAAM,KAAKI,CAAG;AAErC,WAAOD;AAAA,EACT;AACF;"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Graph } from 'graph-data-structure';
|
|
2
|
+
import { BasePayload, CollectionSlug, FlattenedField, GlobalSlug } from 'payload';
|
|
3
|
+
export declare function createDependencyGraph({ collections, globals }: BasePayload): EntitiesGraph;
|
|
4
|
+
interface FieldRelation {
|
|
5
|
+
field: string;
|
|
6
|
+
collection: CollectionSlug;
|
|
7
|
+
hasMany: boolean;
|
|
8
|
+
}
|
|
9
|
+
type StringifiedEntityReference = `collection|${CollectionSlug}` | `global|${GlobalSlug}`;
|
|
10
|
+
type EntityReference = {
|
|
11
|
+
type: 'collection';
|
|
12
|
+
slug: CollectionSlug;
|
|
13
|
+
} | {
|
|
14
|
+
type: 'global';
|
|
15
|
+
slug: GlobalSlug;
|
|
16
|
+
};
|
|
17
|
+
export declare class EntitiesGraph extends Graph<StringifiedEntityReference, {
|
|
18
|
+
field: string;
|
|
19
|
+
hasMany: boolean;
|
|
20
|
+
}[]> {
|
|
21
|
+
static parseEntityReference(entity: StringifiedEntityReference): EntityReference;
|
|
22
|
+
static stringifyEntityReference(entity: EntityReference): StringifiedEntityReference;
|
|
23
|
+
static getFieldRelations(field: FlattenedField, prevPath: string[]): FieldRelation[];
|
|
24
|
+
getDependants(collection: CollectionSlug): {
|
|
25
|
+
entity: EntityReference;
|
|
26
|
+
fields: {
|
|
27
|
+
field: string;
|
|
28
|
+
hasMany: boolean;
|
|
29
|
+
}[];
|
|
30
|
+
}[];
|
|
31
|
+
addRelations(entity: EntityReference, flattenedFields: FlattenedField[]): void;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=dependency-graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-graph.d.ts","sourceRoot":"","sources":["../../src/utils/dependency-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,cAAc,EACd,UAAU,EACX,MAAM,SAAS,CAAC;AAEjB,wBAAgB,qBAAqB,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,WAAW,iBAc1E;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,cAAc,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,KAAK,0BAA0B,GAC3B,cAAc,cAAc,EAAE,GAC9B,UAAU,UAAU,EAAE,CAAC;AAE3B,KAAK,eAAe,GAChB;IACE,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,cAAc,CAAC;CACtB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAEN,qBAAa,aAAc,SAAQ,KAAK,CACtC,0BAA0B,EAC1B;IACE,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB,EAAE,CACJ;IACC,MAAM,CAAC,oBAAoB,CACzB,MAAM,EAAE,0BAA0B,GACjC,eAAe;IAqBlB,MAAM,CAAC,wBAAwB,CAC7B,MAAM,EAAE,eAAe,GACtB,0BAA0B;IAS7B,MAAM,CAAC,iBAAiB,CACtB,KAAK,EAAE,cAAc,EACrB,QAAQ,EAAE,MAAM,EAAE,GACjB,aAAa,EAAE;IAiClB,aAAa,CAAC,UAAU,EAAE,cAAc;gBAK5B,eAAe;gBACf;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,OAAO,CAAA;SAAE,EAAE;;IAOjD,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE;CAsBxE"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Graph as f } from "graph-data-structure";
|
|
2
|
+
import { groupBy as d } from "lodash-es";
|
|
3
|
+
function u({ collections: r, globals: e }) {
|
|
4
|
+
const o = new n();
|
|
5
|
+
for (const {
|
|
6
|
+
config: { slug: t, flattenedFields: l }
|
|
7
|
+
} of Object.values(r))
|
|
8
|
+
o.addRelations({ type: "collection", slug: t }, l);
|
|
9
|
+
for (const { slug: t, flattenedFields: l } of Object.values(e.config))
|
|
10
|
+
o.addRelations({ type: "global", slug: t }, l);
|
|
11
|
+
return o;
|
|
12
|
+
}
|
|
13
|
+
class n extends f {
|
|
14
|
+
static parseEntityReference(e) {
|
|
15
|
+
const [o, t] = e.split("|");
|
|
16
|
+
switch (o) {
|
|
17
|
+
case "collection":
|
|
18
|
+
return {
|
|
19
|
+
type: "collection",
|
|
20
|
+
slug: t
|
|
21
|
+
};
|
|
22
|
+
case "global":
|
|
23
|
+
return {
|
|
24
|
+
type: "global",
|
|
25
|
+
slug: t
|
|
26
|
+
};
|
|
27
|
+
default:
|
|
28
|
+
throw new Error(`Invalid entity reference: ${e}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
static stringifyEntityReference(e) {
|
|
32
|
+
switch (e.type) {
|
|
33
|
+
case "collection":
|
|
34
|
+
return `collection|${e.slug}`;
|
|
35
|
+
case "global":
|
|
36
|
+
return `global|${e.slug}`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
static getFieldRelations(e, o) {
|
|
40
|
+
const t = [...o, e.name];
|
|
41
|
+
switch (e.type) {
|
|
42
|
+
case "upload":
|
|
43
|
+
case "relationship":
|
|
44
|
+
return Array.isArray(e.relationTo) ? [] : [
|
|
45
|
+
{
|
|
46
|
+
field: t.join("."),
|
|
47
|
+
collection: e.relationTo,
|
|
48
|
+
hasMany: e.hasMany ?? !1
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
case "array":
|
|
52
|
+
return e.flattenedFields.flatMap(
|
|
53
|
+
(l) => n.getFieldRelations(l, t)
|
|
54
|
+
);
|
|
55
|
+
case "group":
|
|
56
|
+
return e.flattenedFields.flatMap(
|
|
57
|
+
(l) => n.getFieldRelations(l, t)
|
|
58
|
+
);
|
|
59
|
+
case "blocks":
|
|
60
|
+
return e.blocks.flatMap(
|
|
61
|
+
(l) => l.flattenedFields.flatMap(
|
|
62
|
+
(a) => n.getFieldRelations(a, t)
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
default:
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
getDependants(e) {
|
|
70
|
+
const o = this.edgeProperties.get(
|
|
71
|
+
`collection|${e}`
|
|
72
|
+
);
|
|
73
|
+
return Array.from(o?.entries() ?? []).map(([t, l]) => ({
|
|
74
|
+
entity: n.parseEntityReference(t),
|
|
75
|
+
fields: l
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
addRelations(e, o) {
|
|
79
|
+
const t = o.flatMap(
|
|
80
|
+
(a) => n.getFieldRelations(a, [])
|
|
81
|
+
), l = Object.entries(
|
|
82
|
+
d(t, "collection")
|
|
83
|
+
).map(([a, s]) => ({
|
|
84
|
+
collection: a,
|
|
85
|
+
fields: s.map(({ field: c, hasMany: i }) => ({ field: c, hasMany: i }))
|
|
86
|
+
}));
|
|
87
|
+
for (const { collection: a, fields: s } of l)
|
|
88
|
+
this.addEdge(
|
|
89
|
+
`collection|${a}`,
|
|
90
|
+
n.stringifyEntityReference(e),
|
|
91
|
+
{
|
|
92
|
+
props: s
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export {
|
|
98
|
+
n as EntitiesGraph,
|
|
99
|
+
u as createDependencyGraph
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=dependency-graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-graph.js","sources":["../../src/utils/dependency-graph.ts"],"sourcesContent":["import { Graph } from 'graph-data-structure';\nimport { groupBy } from 'lodash-es';\nimport type {\n BasePayload,\n CollectionSlug,\n FlattenedField,\n GlobalSlug,\n} from 'payload';\n\nexport function createDependencyGraph({ collections, globals }: BasePayload) {\n const graph = new EntitiesGraph();\n\n for (const {\n config: { slug, flattenedFields },\n } of Object.values(collections)) {\n graph.addRelations({ type: 'collection', slug }, flattenedFields);\n }\n\n for (const { slug, flattenedFields } of Object.values(globals.config)) {\n graph.addRelations({ type: 'global', slug }, flattenedFields);\n }\n\n return graph;\n}\n\ninterface FieldRelation {\n field: string;\n collection: CollectionSlug;\n hasMany: boolean;\n}\n\ntype StringifiedEntityReference =\n | `collection|${CollectionSlug}`\n | `global|${GlobalSlug}`;\n\ntype EntityReference =\n | {\n type: 'collection';\n slug: CollectionSlug;\n }\n | {\n type: 'global';\n slug: GlobalSlug;\n };\n\nexport class EntitiesGraph extends Graph<\n StringifiedEntityReference,\n {\n field: string;\n hasMany: boolean;\n }[]\n> {\n static parseEntityReference(\n entity: StringifiedEntityReference,\n ): EntityReference {\n const [type, slug] = entity.split('|') as\n | ['collection', CollectionSlug]\n | ['global', GlobalSlug];\n\n switch (type) {\n case 'collection':\n return {\n type: 'collection',\n slug,\n };\n case 'global':\n return {\n type: 'global',\n slug,\n };\n default:\n throw new Error(`Invalid entity reference: ${entity}`);\n }\n }\n\n static stringifyEntityReference(\n entity: EntityReference,\n ): StringifiedEntityReference {\n switch (entity.type) {\n case 'collection':\n return `collection|${entity.slug}`;\n case 'global':\n return `global|${entity.slug}`;\n }\n }\n\n static getFieldRelations(\n field: FlattenedField,\n prevPath: string[],\n ): FieldRelation[] {\n const fieldPath = [...prevPath, field.name];\n\n switch (field.type) {\n case 'upload':\n case 'relationship':\n if (Array.isArray(field.relationTo)) return [];\n return [\n {\n field: fieldPath.join('.'),\n collection: field.relationTo,\n hasMany: field.hasMany ?? false,\n },\n ];\n case 'array':\n return field.flattenedFields.flatMap((subField) =>\n EntitiesGraph.getFieldRelations(subField, fieldPath),\n );\n case 'group':\n return field.flattenedFields.flatMap((subField) =>\n EntitiesGraph.getFieldRelations(subField, fieldPath),\n );\n case 'blocks':\n return field.blocks.flatMap((block) =>\n block.flattenedFields.flatMap((subField) =>\n EntitiesGraph.getFieldRelations(subField, fieldPath),\n ),\n );\n default:\n return [];\n }\n }\n\n getDependants(collection: CollectionSlug) {\n const collectionRelations = this.edgeProperties.get(\n `collection|${collection}`,\n );\n return Array.from(collectionRelations?.entries() ?? []).map<{\n entity: EntityReference;\n fields: { field: string; hasMany: boolean }[];\n }>(([entity, fields]) => ({\n entity: EntitiesGraph.parseEntityReference(entity),\n fields,\n }));\n }\n\n addRelations(entity: EntityReference, flattenedFields: FlattenedField[]) {\n const fieldRelations = flattenedFields.flatMap((field) =>\n EntitiesGraph.getFieldRelations(field, []),\n );\n\n const fieldRelationsByCollection = Object.entries(\n groupBy(fieldRelations, 'collection'),\n ).map(([collection, fields]) => ({\n collection: collection as CollectionSlug,\n fields: fields.map(({ field, hasMany }) => ({ field, hasMany })),\n }));\n\n for (const { collection, fields } of fieldRelationsByCollection) {\n this.addEdge(\n `collection|${collection}`,\n EntitiesGraph.stringifyEntityReference(entity),\n {\n props: fields,\n },\n );\n }\n }\n}\n"],"names":["createDependencyGraph","collections","globals","graph","EntitiesGraph","slug","flattenedFields","Graph","entity","type","field","prevPath","fieldPath","subField","block","collection","collectionRelations","fields","fieldRelations","fieldRelationsByCollection","groupBy","hasMany"],"mappings":";;AASO,SAASA,EAAsB,EAAE,aAAAC,GAAa,SAAAC,KAAwB;AAC3E,QAAMC,IAAQ,IAAIC,EAAA;AAElB,aAAW;AAAA,IACT,QAAQ,EAAE,MAAAC,GAAM,iBAAAC,EAAA;AAAA,EAAgB,KAC7B,OAAO,OAAOL,CAAW;AAC5B,IAAAE,EAAM,aAAa,EAAE,MAAM,cAAc,MAAAE,EAAA,GAAQC,CAAe;AAGlE,aAAW,EAAE,MAAAD,GAAM,iBAAAC,EAAA,KAAqB,OAAO,OAAOJ,EAAQ,MAAM;AAClE,IAAAC,EAAM,aAAa,EAAE,MAAM,UAAU,MAAAE,EAAA,GAAQC,CAAe;AAG9D,SAAOH;AACT;AAsBO,MAAMC,UAAsBG,EAMjC;AAAA,EACA,OAAO,qBACLC,GACiB;AACjB,UAAM,CAACC,GAAMJ,CAAI,IAAIG,EAAO,MAAM,GAAG;AAIrC,YAAQC,GAAA;AAAA,MACN,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAAJ;AAAA,QAAA;AAAA,MAEJ,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,MAAAA;AAAA,QAAA;AAAA,MAEJ;AACE,cAAM,IAAI,MAAM,6BAA6BG,CAAM,EAAE;AAAA,IAAA;AAAA,EAE3D;AAAA,EAEA,OAAO,yBACLA,GAC4B;AAC5B,YAAQA,EAAO,MAAA;AAAA,MACb,KAAK;AACH,eAAO,cAAcA,EAAO,IAAI;AAAA,MAClC,KAAK;AACH,eAAO,UAAUA,EAAO,IAAI;AAAA,IAAA;AAAA,EAElC;AAAA,EAEA,OAAO,kBACLE,GACAC,GACiB;AACjB,UAAMC,IAAY,CAAC,GAAGD,GAAUD,EAAM,IAAI;AAE1C,YAAQA,EAAM,MAAA;AAAA,MACZ,KAAK;AAAA,MACL,KAAK;AACH,eAAI,MAAM,QAAQA,EAAM,UAAU,IAAU,CAAA,IACrC;AAAA,UACL;AAAA,YACE,OAAOE,EAAU,KAAK,GAAG;AAAA,YACzB,YAAYF,EAAM;AAAA,YAClB,SAASA,EAAM,WAAW;AAAA,UAAA;AAAA,QAC5B;AAAA,MAEJ,KAAK;AACH,eAAOA,EAAM,gBAAgB;AAAA,UAAQ,CAACG,MACpCT,EAAc,kBAAkBS,GAAUD,CAAS;AAAA,QAAA;AAAA,MAEvD,KAAK;AACH,eAAOF,EAAM,gBAAgB;AAAA,UAAQ,CAACG,MACpCT,EAAc,kBAAkBS,GAAUD,CAAS;AAAA,QAAA;AAAA,MAEvD,KAAK;AACH,eAAOF,EAAM,OAAO;AAAA,UAAQ,CAACI,MAC3BA,EAAM,gBAAgB;AAAA,YAAQ,CAACD,MAC7BT,EAAc,kBAAkBS,GAAUD,CAAS;AAAA,UAAA;AAAA,QACrD;AAAA,MAEJ;AACE,eAAO,CAAA;AAAA,IAAC;AAAA,EAEd;AAAA,EAEA,cAAcG,GAA4B;AACxC,UAAMC,IAAsB,KAAK,eAAe;AAAA,MAC9C,cAAcD,CAAU;AAAA,IAAA;AAE1B,WAAO,MAAM,KAAKC,GAAqB,QAAA,KAAa,EAAE,EAAE,IAGrD,CAAC,CAACR,GAAQS,CAAM,OAAO;AAAA,MACxB,QAAQb,EAAc,qBAAqBI,CAAM;AAAA,MACjD,QAAAS;AAAA,IAAA,EACA;AAAA,EACJ;AAAA,EAEA,aAAaT,GAAyBF,GAAmC;AACvE,UAAMY,IAAiBZ,EAAgB;AAAA,MAAQ,CAACI,MAC9CN,EAAc,kBAAkBM,GAAO,CAAA,CAAE;AAAA,IAAA,GAGrCS,IAA6B,OAAO;AAAA,MACxCC,EAAQF,GAAgB,YAAY;AAAA,IAAA,EACpC,IAAI,CAAC,CAACH,GAAYE,CAAM,OAAO;AAAA,MAC/B,YAAAF;AAAA,MACA,QAAQE,EAAO,IAAI,CAAC,EAAE,OAAAP,GAAO,SAAAW,SAAe,EAAE,OAAAX,GAAO,SAAAW,IAAU;AAAA,IAAA,EAC/D;AAEF,eAAW,EAAE,YAAAN,GAAY,QAAAE,EAAA,KAAYE;AACnC,WAAK;AAAA,QACH,cAAcJ,CAAU;AAAA,QACxBX,EAAc,yBAAyBI,CAAM;AAAA,QAC7C;AAAA,UACE,OAAOS;AAAA,QAAA;AAAA,MACT;AAAA,EAGN;AACF;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "payload-smart-cache",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Payload Plugin for Cached Data",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"payload",
|
|
7
|
+
"cached",
|
|
8
|
+
"cache",
|
|
9
|
+
"react",
|
|
10
|
+
"next.js"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/davincicoding-org/payload-plugins.git",
|
|
15
|
+
"directory": "packages/smart-cache"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "Michael Zeltner",
|
|
19
|
+
"type": "module",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"default": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./rsc": {
|
|
27
|
+
"types": "./dist/exports/rsc.d.ts",
|
|
28
|
+
"import": "./dist/exports/rsc.js",
|
|
29
|
+
"default": "./dist/exports/rsc.js"
|
|
30
|
+
},
|
|
31
|
+
"./styles.css": "./dist/styles.css"
|
|
32
|
+
},
|
|
33
|
+
"main": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"graph-data-structure": "^4.5.0",
|
|
40
|
+
"lodash-es": "^4.17.21",
|
|
41
|
+
"tailwind-merge": "^3.3.1",
|
|
42
|
+
"zod": "^4.3.6"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@payloadcms/ui": "3.72.0",
|
|
46
|
+
"@tailwindcss/typography": "^0.5.16",
|
|
47
|
+
"@tailwindcss/vite": "^4.1.11",
|
|
48
|
+
"@types/lodash-es": "^4.17.12",
|
|
49
|
+
"@types/node": "^22.5.4",
|
|
50
|
+
"@types/react": "19.2.1",
|
|
51
|
+
"@types/react-dom": "19.2.1",
|
|
52
|
+
"next": "15.5.9",
|
|
53
|
+
"payload": "3.72.0",
|
|
54
|
+
"react": "19.2.1",
|
|
55
|
+
"react-dom": "19.2.1",
|
|
56
|
+
"rollup-preserve-directives": "1.1.3",
|
|
57
|
+
"tailwindcss": "^4.1.11",
|
|
58
|
+
"tw-animate-css": "^1.3.6",
|
|
59
|
+
"typescript": "5.7.3",
|
|
60
|
+
"vite": "7.0.6",
|
|
61
|
+
"vite-plugin-dts": "4.5.4",
|
|
62
|
+
"vite-tsconfig-paths": "5.1.4",
|
|
63
|
+
"vitest": "^3.1.2",
|
|
64
|
+
"@repo/configs": "0.0.1"
|
|
65
|
+
},
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"@payloadcms/next": ">=3.72.0",
|
|
68
|
+
"@payloadcms/ui": ">=3.72.0",
|
|
69
|
+
"next": ">=15.2.3",
|
|
70
|
+
"payload": ">=3.72.0"
|
|
71
|
+
},
|
|
72
|
+
"engines": {
|
|
73
|
+
"node": "^18.20.2 || >=20.9.0",
|
|
74
|
+
"pnpm": "^9 || ^10"
|
|
75
|
+
},
|
|
76
|
+
"publishConfig": {
|
|
77
|
+
"access": "public"
|
|
78
|
+
},
|
|
79
|
+
"registry": "https://registry.npmjs.org/",
|
|
80
|
+
"scripts": {
|
|
81
|
+
"prebuild": "pnpm typecheck",
|
|
82
|
+
"build": "vite build",
|
|
83
|
+
"clean": "rm -rf dist && rm -rf node_modules",
|
|
84
|
+
"dev": "vite build --watch",
|
|
85
|
+
"lint": "biome check .",
|
|
86
|
+
"lint:fix": "biome check --write .",
|
|
87
|
+
"test": "vitest run",
|
|
88
|
+
"test:watch": "vitest",
|
|
89
|
+
"typecheck": "tsc --noEmit"
|
|
90
|
+
}
|
|
91
|
+
}
|