payload-smart-cache 1.1.10 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +29 -11
  2. package/dist/exports/create-request.d.ts +15 -1
  3. package/dist/exports/create-request.d.ts.map +1 -1
  4. package/dist/exports/create-request.js +13 -4
  5. package/dist/exports/create-request.js.map +1 -1
  6. package/dist/hooks.d.ts +12 -4
  7. package/dist/hooks.d.ts.map +1 -1
  8. package/dist/hooks.js +98 -107
  9. package/dist/hooks.js.map +1 -1
  10. package/dist/index.d.ts +12 -8
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +28 -18
  13. package/dist/index.js.map +1 -1
  14. package/dist/types.d.ts +18 -7
  15. package/dist/types.d.ts.map +1 -1
  16. package/dist/types.js +1 -1
  17. package/dist/types.js.map +1 -1
  18. package/dist/utils/dependency-graph.d.ts +3 -10
  19. package/dist/utils/dependency-graph.d.ts.map +1 -1
  20. package/dist/utils/dependency-graph.js +27 -50
  21. package/dist/utils/dependency-graph.js.map +1 -1
  22. package/dist/utils/tracked-collections.d.ts.map +1 -1
  23. package/dist/utils/tracked-collections.js.map +1 -1
  24. package/package.json +6 -26
  25. package/dist/components/PublishButton.d.ts +0 -2
  26. package/dist/components/PublishButton.d.ts.map +0 -1
  27. package/dist/components/PublishButton.js +0 -52
  28. package/dist/components/PublishButton.js.map +0 -1
  29. package/dist/const.d.ts +0 -7
  30. package/dist/const.d.ts.map +0 -1
  31. package/dist/const.js +0 -13
  32. package/dist/const.js.map +0 -1
  33. package/dist/endpoints/check.d.ts +0 -3
  34. package/dist/endpoints/check.d.ts.map +0 -1
  35. package/dist/endpoints/check.js +0 -21
  36. package/dist/endpoints/check.js.map +0 -1
  37. package/dist/endpoints/publish.d.ts +0 -4
  38. package/dist/endpoints/publish.d.ts.map +0 -1
  39. package/dist/endpoints/publish.js +0 -109
  40. package/dist/endpoints/publish.js.map +0 -1
  41. package/dist/entities.d.ts +0 -26
  42. package/dist/entities.d.ts.map +0 -1
  43. package/dist/entities.js +0 -28
  44. package/dist/entities.js.map +0 -1
  45. package/dist/exports/client.d.ts +0 -2
  46. package/dist/exports/client.d.ts.map +0 -1
  47. package/dist/exports/client.js +0 -3
  48. package/dist/exports/client.js.map +0 -1
  49. package/dist/exports/rsc.d.ts +0 -2
  50. package/dist/exports/rsc.d.ts.map +0 -1
  51. package/dist/exports/rsc.js +0 -3
  52. package/dist/exports/rsc.js.map +0 -1
  53. package/dist/payload-types.d.ts +0 -241
  54. package/dist/payload-types.d.ts.map +0 -1
  55. package/dist/utils/collection-changes.d.ts +0 -8
  56. package/dist/utils/collection-changes.d.ts.map +0 -1
  57. package/dist/utils/collection-changes.js +0 -27
  58. package/dist/utils/collection-changes.js.map +0 -1
package/dist/types.d.ts CHANGED
@@ -1,10 +1,21 @@
1
- import type { CollectionSlug, GlobalSlug } from 'payload';
1
+ import type { DocumentID } from '@davincicoding/payload-plugin-kit';
2
+ import type { CollectionSlug, GlobalSlug, TypeWithID } from 'payload';
2
3
  import type { SmartCachePluginConfig } from '.';
3
- export type ResolvedPluginOptions<K extends keyof SmartCachePluginConfig = keyof SmartCachePluginConfig> = Pick<Required<SmartCachePluginConfig>, K>;
4
+ export type ResolvedPluginOptions<Req extends keyof SmartCachePluginConfig = keyof SmartCachePluginConfig, Opt extends keyof SmartCachePluginConfig = never> = Pick<Required<SmartCachePluginConfig>, Req> & Pick<SmartCachePluginConfig, Opt>;
4
5
  export type EntitySlug = CollectionSlug | GlobalSlug;
5
- export type CollectionOperation = CollectionChangeOperation | 'delete';
6
- export type CollectionChangeOperation = 'create' | 'update';
7
- type CollectionId = string;
8
- export type ChangedDocuments = Partial<Record<CollectionSlug, CollectionId[]>>;
9
- export {};
6
+ /** Discriminated union passed to the `onInvalidate` callback. */
7
+ export type DocumentInvalidation<C extends CollectionSlug = CollectionSlug, G extends GlobalSlug = GlobalSlug> = {
8
+ type: 'collection';
9
+ slug: C;
10
+ docID: DocumentID;
11
+ } | {
12
+ type: 'global';
13
+ slug: G;
14
+ };
15
+ /** Callback type for the `onInvalidate` option. */
16
+ export type DocumentInvalidationCallback<C extends CollectionSlug = CollectionSlug, G extends GlobalSlug = GlobalSlug> = (change: DocumentInvalidation<C, G>) => void | Promise<void>;
17
+ /** A document with an optional draft/publish status field. */
18
+ export type DocumentWithStatus = TypeWithID & {
19
+ _status?: 'published' | 'draft';
20
+ };
10
21
  //# sourceMappingURL=types.d.ts.map
@@ -1 +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;AAC1D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,GAAG,CAAC;AAEhD,MAAM,MAAM,qBAAqB,CAC/B,CAAC,SAAS,MAAM,sBAAsB,GAAG,MAAM,sBAAsB,IACnE,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC,CAAC;AAE9C,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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACtE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,GAAG,CAAC;AAEhD,MAAM,MAAM,qBAAqB,CAC/B,GAAG,SAAS,MAAM,sBAAsB,GAAG,MAAM,sBAAsB,EACvE,GAAG,SAAS,MAAM,sBAAsB,GAAG,KAAK,IAC9C,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,GAAG,CAAC,GAC7C,IAAI,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAC;AAEpC,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,UAAU,CAAC;AAErD,iEAAiE;AACjE,MAAM,MAAM,oBAAoB,CAC9B,CAAC,SAAS,cAAc,GAAG,cAAc,EACzC,CAAC,SAAS,UAAU,GAAG,UAAU,IAE/B;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC;AAEhC,mDAAmD;AACnD,MAAM,MAAM,4BAA4B,CACtC,CAAC,SAAS,cAAc,GAAG,cAAc,EACzC,CAAC,SAAS,UAAU,GAAG,UAAU,IAC/B,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEjE,8DAA8D;AAC9D,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG;IAC5C,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;CACjC,CAAC"}
package/dist/types.js CHANGED
@@ -1,3 +1,3 @@
1
- export { };
1
+ /** A document with an optional draft/publish status field. */ export { };
2
2
 
3
3
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { CollectionSlug, GlobalSlug } from 'payload';\nimport type { SmartCachePluginConfig } from '.';\n\nexport type ResolvedPluginOptions<\n K extends keyof SmartCachePluginConfig = keyof SmartCachePluginConfig,\n> = Pick<Required<SmartCachePluginConfig>, K>;\n\nexport type EntitySlug = CollectionSlug | GlobalSlug;\n\nexport type CollectionOperation = CollectionChangeOperation | 'delete';\n\nexport type CollectionChangeOperation = 'create' | 'update';\n\ntype CollectionId = string; //| number;\n\nexport type ChangedDocuments = Partial<Record<CollectionSlug, CollectionId[]>>;\n"],"names":[],"mappings":"AAeA,WAA+E"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { DocumentID } from '@davincicoding/payload-plugin-kit';\nimport type { CollectionSlug, GlobalSlug, TypeWithID } from 'payload';\nimport type { SmartCachePluginConfig } from '.';\n\nexport type ResolvedPluginOptions<\n Req extends keyof SmartCachePluginConfig = keyof SmartCachePluginConfig,\n Opt extends keyof SmartCachePluginConfig = never,\n> = Pick<Required<SmartCachePluginConfig>, Req> &\n Pick<SmartCachePluginConfig, Opt>;\n\nexport type EntitySlug = CollectionSlug | GlobalSlug;\n\n/** Discriminated union passed to the `onInvalidate` callback. */\nexport type DocumentInvalidation<\n C extends CollectionSlug = CollectionSlug,\n G extends GlobalSlug = GlobalSlug,\n> =\n | { type: 'collection'; slug: C; docID: DocumentID }\n | { type: 'global'; slug: G };\n\n/** Callback type for the `onInvalidate` option. */\nexport type DocumentInvalidationCallback<\n C extends CollectionSlug = CollectionSlug,\n G extends GlobalSlug = GlobalSlug,\n> = (change: DocumentInvalidation<C, G>) => void | Promise<void>;\n\n/** A document with an optional draft/publish status field. */\nexport type DocumentWithStatus = TypeWithID & {\n _status?: 'published' | 'draft';\n};\n"],"names":[],"mappings":"AA0BA,4DAA4D,GAC5D,WAEE"}
@@ -1,12 +1,6 @@
1
1
  import { Graph } from 'graph-data-structure';
2
- import type { 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
- polymorphic: boolean;
9
- }
2
+ import type { CollectionSlug, Config, Field, GlobalSlug } from 'payload';
3
+ export declare function createDependencyGraph({ collections, globals, }: Pick<Config, 'collections' | 'globals'>): EntitiesGraph;
10
4
  type StringifiedEntityReference = `collection|${CollectionSlug}` | `global|${GlobalSlug}`;
11
5
  type EntityReference = {
12
6
  type: 'collection';
@@ -22,7 +16,6 @@ export declare class EntitiesGraph extends Graph<StringifiedEntityReference, {
22
16
  }[]> {
23
17
  static parseEntityReference(entity: StringifiedEntityReference): EntityReference;
24
18
  static stringifyEntityReference(entity: EntityReference): StringifiedEntityReference;
25
- static getFieldRelations(field: FlattenedField, prevPath: string[]): FieldRelation[];
26
19
  getDependants(collection: CollectionSlug): {
27
20
  entity: EntityReference;
28
21
  fields: {
@@ -31,7 +24,7 @@ export declare class EntitiesGraph extends Graph<StringifiedEntityReference, {
31
24
  polymorphic: boolean;
32
25
  }[];
33
26
  }[];
34
- addRelations(entity: EntityReference, flattenedFields: FlattenedField[]): void;
27
+ addRelations(entity: EntityReference, fields: Field[]): void;
35
28
  }
36
29
  export {};
37
30
  //# sourceMappingURL=dependency-graph.d.ts.map
@@ -1 +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;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;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;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB,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;IAyClB,aAAa,CAAC,UAAU,EAAE,cAAc;gBAK5B,eAAe;gBACf;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,OAAO,CAAC;YAAC,WAAW,EAAE,OAAO,CAAA;SAAE,EAAE;;IAOvE,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE;CA0BxE"}
1
+ {"version":3,"file":"dependency-graph.d.ts","sourceRoot":"","sources":["../../src/utils/dependency-graph.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,OAAO,KAAK,EACV,cAAc,EACd,MAAM,EACN,KAAK,EACL,UAAU,EAGX,MAAM,SAAS,CAAC;AAOjB,wBAAgB,qBAAqB,CAAC,EACpC,WAAgB,EAChB,OAAY,GACb,EAAE,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAAC,iBAezC;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;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB,EAAE,CACJ;IACC,MAAM,CAAC,oBAAoB,CACzB,MAAM,EAAE,0BAA0B,GACjC,eAAe;IAqBlB,MAAM,CAAC,wBAAwB,CAC7B,MAAM,EAAE,eAAe,GACtB,0BAA0B;IAS7B,aAAa,CAAC,UAAU,EAAE,cAAc;gBAK5B,eAAe;gBACf;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,OAAO,CAAC;YAAC,WAAW,EAAE,OAAO,CAAA;SAAE,EAAE;;IAOvE,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,KAAK,EAAE;CAiCtD"}
@@ -1,18 +1,20 @@
1
+ import { findFields } from '@davincicoding/payload-plugin-kit';
1
2
  import { Graph } from 'graph-data-structure';
2
3
  import { groupBy } from 'lodash-es';
3
- export function createDependencyGraph({ collections, globals }) {
4
+ const isRelationshipOrUpload = (field)=>field.type === 'relationship' || field.type === 'upload';
5
+ export function createDependencyGraph({ collections = [], globals = [] }) {
4
6
  const graph = new EntitiesGraph();
5
- for (const { config: { slug, flattenedFields } } of Object.values(collections)){
7
+ for (const { slug, fields } of collections){
6
8
  graph.addRelations({
7
9
  type: 'collection',
8
- slug
9
- }, flattenedFields);
10
+ slug: slug
11
+ }, fields);
10
12
  }
11
- for (const { slug, flattenedFields } of Object.values(globals.config)){
13
+ for (const { slug, fields } of globals){
12
14
  graph.addRelations({
13
15
  type: 'global',
14
- slug
15
- }, flattenedFields);
16
+ slug: slug
17
+ }, fields);
16
18
  }
17
19
  return graph;
18
20
  }
@@ -42,40 +44,6 @@ export class EntitiesGraph extends Graph {
42
44
  return `global|${entity.slug}`;
43
45
  }
44
46
  }
45
- static getFieldRelations(field, prevPath) {
46
- const fieldPath = [
47
- ...prevPath,
48
- field.name
49
- ];
50
- switch(field.type){
51
- case 'upload':
52
- case 'relationship':
53
- if (Array.isArray(field.relationTo)) {
54
- return field.relationTo.map((slug)=>({
55
- field: fieldPath.join('.'),
56
- collection: slug,
57
- hasMany: field.hasMany ?? false,
58
- polymorphic: true
59
- }));
60
- }
61
- return [
62
- {
63
- field: fieldPath.join('.'),
64
- collection: field.relationTo,
65
- hasMany: field.hasMany ?? false,
66
- polymorphic: false
67
- }
68
- ];
69
- case 'array':
70
- return field.flattenedFields.flatMap((subField)=>EntitiesGraph.getFieldRelations(subField, fieldPath));
71
- case 'group':
72
- return field.flattenedFields.flatMap((subField)=>EntitiesGraph.getFieldRelations(subField, fieldPath));
73
- case 'blocks':
74
- return field.blocks.flatMap((block)=>block.flattenedFields.flatMap((subField)=>EntitiesGraph.getFieldRelations(subField, fieldPath)));
75
- default:
76
- return [];
77
- }
78
- }
79
47
  getDependants(collection) {
80
48
  const collectionRelations = this.edgeProperties.get(`collection|${collection}`);
81
49
  return Array.from(collectionRelations?.entries() ?? []).map(([entity, fields])=>({
@@ -83,19 +51,28 @@ export class EntitiesGraph extends Graph {
83
51
  fields
84
52
  }));
85
53
  }
86
- addRelations(entity, flattenedFields) {
87
- const fieldRelations = flattenedFields.flatMap((field)=>EntitiesGraph.getFieldRelations(field, []));
88
- const fieldRelationsByCollection = Object.entries(groupBy(fieldRelations, 'collection')).map(([collection, fields])=>({
89
- collection: collection,
90
- fields: fields.map(({ field, hasMany, polymorphic })=>({
54
+ addRelations(entity, fields) {
55
+ const relationFields = findFields(fields, isRelationshipOrUpload);
56
+ const fieldRelations = relationFields.flatMap((field)=>{
57
+ const targets = Array.isArray(field.relationTo) ? field.relationTo : [
58
+ field.relationTo
59
+ ];
60
+ const polymorphic = Array.isArray(field.relationTo);
61
+ return targets.map((collection)=>({
62
+ collection: collection,
63
+ field: field.path.join('.'),
64
+ hasMany: field.hasMany ?? false,
65
+ polymorphic
66
+ }));
67
+ });
68
+ const byCollection = Object.entries(groupBy(fieldRelations, 'collection'));
69
+ for (const [collection, fields] of byCollection){
70
+ this.addEdge(`collection|${collection}`, EntitiesGraph.stringifyEntityReference(entity), {
71
+ props: fields.map(({ field, hasMany, polymorphic })=>({
91
72
  field,
92
73
  hasMany,
93
74
  polymorphic
94
75
  }))
95
- }));
96
- for (const { collection, fields } of fieldRelationsByCollection){
97
- this.addEdge(`collection|${collection}`, EntitiesGraph.stringifyEntityReference(entity), {
98
- props: fields
99
76
  });
100
77
  }
101
78
  }
@@ -1 +1 @@
1
- {"version":3,"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 polymorphic: 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 polymorphic: 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)) {\n return field.relationTo.map((slug) => ({\n field: fieldPath.join('.'),\n collection: slug,\n hasMany: field.hasMany ?? false,\n polymorphic: true,\n }));\n }\n return [\n {\n field: fieldPath.join('.'),\n collection: field.relationTo,\n hasMany: field.hasMany ?? false,\n polymorphic: 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; polymorphic: 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, polymorphic }) => ({\n field,\n hasMany,\n polymorphic,\n })),\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":["Graph","groupBy","createDependencyGraph","collections","globals","graph","EntitiesGraph","config","slug","flattenedFields","Object","values","addRelations","type","parseEntityReference","entity","split","Error","stringifyEntityReference","getFieldRelations","field","prevPath","fieldPath","name","Array","isArray","relationTo","map","join","collection","hasMany","polymorphic","flatMap","subField","blocks","block","getDependants","collectionRelations","edgeProperties","get","from","entries","fields","fieldRelations","fieldRelationsByCollection","addEdge","props"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utils/dependency-graph.ts"],"sourcesContent":["import { findFields } from '@davincicoding/payload-plugin-kit';\nimport { Graph } from 'graph-data-structure';\nimport { groupBy } from 'lodash-es';\nimport type {\n CollectionSlug,\n Config,\n Field,\n GlobalSlug,\n RelationshipField,\n UploadField,\n} from 'payload';\n\nconst isRelationshipOrUpload = (\n field: Field,\n): field is RelationshipField | UploadField =>\n field.type === 'relationship' || field.type === 'upload';\n\nexport function createDependencyGraph({\n collections = [],\n globals = [],\n}: Pick<Config, 'collections' | 'globals'>) {\n const graph = new EntitiesGraph();\n\n for (const { slug, fields } of collections) {\n graph.addRelations(\n { type: 'collection', slug: slug as CollectionSlug },\n fields,\n );\n }\n\n for (const { slug, fields } of globals) {\n graph.addRelations({ type: 'global', slug: slug as GlobalSlug }, fields);\n }\n\n return graph;\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 polymorphic: 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 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; polymorphic: boolean }[];\n }>(([entity, fields]) => ({\n entity: EntitiesGraph.parseEntityReference(entity),\n fields,\n }));\n }\n\n addRelations(entity: EntityReference, fields: Field[]) {\n const relationFields = findFields(fields, isRelationshipOrUpload);\n\n const fieldRelations = relationFields.flatMap((field) => {\n const targets = Array.isArray(field.relationTo)\n ? field.relationTo\n : [field.relationTo];\n const polymorphic = Array.isArray(field.relationTo);\n\n return targets.map((collection) => ({\n collection: collection as CollectionSlug,\n field: field.path.join('.'),\n hasMany: field.hasMany ?? false,\n polymorphic,\n }));\n });\n\n const byCollection = Object.entries(groupBy(fieldRelations, 'collection'));\n\n for (const [collection, fields] of byCollection) {\n this.addEdge(\n `collection|${collection}` as StringifiedEntityReference,\n EntitiesGraph.stringifyEntityReference(entity),\n {\n props: fields.map(({ field, hasMany, polymorphic }) => ({\n field,\n hasMany,\n polymorphic,\n })),\n },\n );\n }\n }\n}\n"],"names":["findFields","Graph","groupBy","isRelationshipOrUpload","field","type","createDependencyGraph","collections","globals","graph","EntitiesGraph","slug","fields","addRelations","parseEntityReference","entity","split","Error","stringifyEntityReference","getDependants","collection","collectionRelations","edgeProperties","get","Array","from","entries","map","relationFields","fieldRelations","flatMap","targets","isArray","relationTo","polymorphic","path","join","hasMany","byCollection","Object","addEdge","props"],"mappings":"AAAA,SAASA,UAAU,QAAQ,oCAAoC;AAC/D,SAASC,KAAK,QAAQ,uBAAuB;AAC7C,SAASC,OAAO,QAAQ,YAAY;AAUpC,MAAMC,yBAAyB,CAC7BC,QAEAA,MAAMC,IAAI,KAAK,kBAAkBD,MAAMC,IAAI,KAAK;AAElD,OAAO,SAASC,sBAAsB,EACpCC,cAAc,EAAE,EAChBC,UAAU,EAAE,EAC4B;IACxC,MAAMC,QAAQ,IAAIC;IAElB,KAAK,MAAM,EAAEC,IAAI,EAAEC,MAAM,EAAE,IAAIL,YAAa;QAC1CE,MAAMI,YAAY,CAChB;YAAER,MAAM;YAAcM,MAAMA;QAAuB,GACnDC;IAEJ;IAEA,KAAK,MAAM,EAAED,IAAI,EAAEC,MAAM,EAAE,IAAIJ,QAAS;QACtCC,MAAMI,YAAY,CAAC;YAAER,MAAM;YAAUM,MAAMA;QAAmB,GAAGC;IACnE;IAEA,OAAOH;AACT;AAgBA,OAAO,MAAMC,sBAAsBT;IAQjC,OAAOa,qBACLC,MAAkC,EACjB;QACjB,MAAM,CAACV,MAAMM,KAAK,GAAGI,OAAOC,KAAK,CAAC;QAIlC,OAAQX;YACN,KAAK;gBACH,OAAO;oBACLA,MAAM;oBACNM;gBACF;YACF,KAAK;gBACH,OAAO;oBACLN,MAAM;oBACNM;gBACF;YACF;gBACE,MAAM,IAAIM,MAAM,CAAC,0BAA0B,EAAEF,QAAQ;QACzD;IACF;IAEA,OAAOG,yBACLH,MAAuB,EACK;QAC5B,OAAQA,OAAOV,IAAI;YACjB,KAAK;gBACH,OAAO,CAAC,WAAW,EAAEU,OAAOJ,IAAI,EAAE;YACpC,KAAK;gBACH,OAAO,CAAC,OAAO,EAAEI,OAAOJ,IAAI,EAAE;QAClC;IACF;IAEAQ,cAAcC,UAA0B,EAAE;QACxC,MAAMC,sBAAsB,IAAI,CAACC,cAAc,CAACC,GAAG,CACjD,CAAC,WAAW,EAAEH,YAAY;QAE5B,OAAOI,MAAMC,IAAI,CAACJ,qBAAqBK,aAAa,EAAE,EAAEC,GAAG,CAGxD,CAAC,CAACZ,QAAQH,OAAO,GAAM,CAAA;gBACxBG,QAAQL,cAAcI,oBAAoB,CAACC;gBAC3CH;YACF,CAAA;IACF;IAEAC,aAAaE,MAAuB,EAAEH,MAAe,EAAE;QACrD,MAAMgB,iBAAiB5B,WAAWY,QAAQT;QAE1C,MAAM0B,iBAAiBD,eAAeE,OAAO,CAAC,CAAC1B;YAC7C,MAAM2B,UAAUP,MAAMQ,OAAO,CAAC5B,MAAM6B,UAAU,IAC1C7B,MAAM6B,UAAU,GAChB;gBAAC7B,MAAM6B,UAAU;aAAC;YACtB,MAAMC,cAAcV,MAAMQ,OAAO,CAAC5B,MAAM6B,UAAU;YAElD,OAAOF,QAAQJ,GAAG,CAAC,CAACP,aAAgB,CAAA;oBAClCA,YAAYA;oBACZhB,OAAOA,MAAM+B,IAAI,CAACC,IAAI,CAAC;oBACvBC,SAASjC,MAAMiC,OAAO,IAAI;oBAC1BH;gBACF,CAAA;QACF;QAEA,MAAMI,eAAeC,OAAOb,OAAO,CAACxB,QAAQ2B,gBAAgB;QAE5D,KAAK,MAAM,CAACT,YAAYR,OAAO,IAAI0B,aAAc;YAC/C,IAAI,CAACE,OAAO,CACV,CAAC,WAAW,EAAEpB,YAAY,EAC1BV,cAAcQ,wBAAwB,CAACH,SACvC;gBACE0B,OAAO7B,OAAOe,GAAG,CAAC,CAAC,EAAEvB,KAAK,EAAEiC,OAAO,EAAEH,WAAW,EAAE,GAAM,CAAA;wBACtD9B;wBACAiC;wBACAH;oBACF,CAAA;YACF;QAEJ;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"tracked-collections.d.ts","sourceRoot":"","sources":["../../src/utils/tracked-collections.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AACzE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAErD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,qBAAqB,CAAC,aAAa,GAAG,SAAS,CAAC,EACzD,EACE,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,UAAU,GACpB,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAAC,CAAC,GACnD,GAAG,CAAC,cAAc,CAAC,CA+CrB"}
1
+ {"version":3,"file":"tracked-collections.d.ts","sourceRoot":"","sources":["../../src/utils/tracked-collections.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AACzE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEtD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,qBAAqB,CAAC,aAAa,GAAG,SAAS,CAAC,EACzD,EACE,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,UAAU,GACpB,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAAC,CAAC,GACnD,GAAG,CAAC,cAAc,CAAC,CA+CrB"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/tracked-collections.ts"],"sourcesContent":["import { findFields } from '@davincicoding/payload-plugin-kit';\nimport type { CollectionSlug, Config, Field, GlobalSlug } from 'payload';\nimport type { ResolvedPluginOptions } from '@/types';\n\nexport function getTrackedCollections(\n options: ResolvedPluginOptions<'collections' | 'globals'>,\n {\n collections: allCollections,\n globals: allGlobals,\n }: Required<Pick<Config, 'collections' | 'globals'>>,\n): Set<CollectionSlug> {\n const tracked = new Set<CollectionSlug>();\n\n for (const slug of options.globals) {\n processGlobal(slug);\n }\n\n for (const slug of options.collections) {\n processCollection(slug);\n }\n\n return tracked;\n\n function processGlobal(slug: GlobalSlug) {\n const global = allGlobals.find((g) => g.slug === slug);\n if (!global)\n return console.warn(\n `[payload-smart-cache] Global to track changes for not found: ${slug}`,\n );\n\n const nestedCollections = findRelationships(global.fields);\n for (const nestedSlug of nestedCollections) {\n processCollection(nestedSlug);\n }\n }\n\n function processCollection(slug: CollectionSlug) {\n if (tracked.has(slug)) return;\n const collection = allCollections.find((c) => c.slug === slug);\n if (!collection)\n return console.warn(\n `[payload-smart-cache] Collection to track changes for not found: ${slug}`,\n );\n tracked.add(slug);\n\n const nestedCollections = findRelationships(collection.fields);\n for (const nestedSlug of nestedCollections) {\n processCollection(nestedSlug);\n }\n }\n\n function findRelationships(fields: Field[]): CollectionSlug[] {\n return findFields(fields, (field) => 'relationTo' in field).flatMap(\n ({ relationTo }) =>\n Array.isArray(relationTo) ? relationTo : [relationTo],\n );\n }\n}\n"],"names":["findFields","getTrackedCollections","options","collections","allCollections","globals","allGlobals","tracked","Set","slug","processGlobal","processCollection","global","find","g","console","warn","nestedCollections","findRelationships","fields","nestedSlug","has","collection","c","add","field","flatMap","relationTo","Array","isArray"],"mappings":"AAAA,SAASA,UAAU,QAAQ,oCAAoC;AAI/D,OAAO,SAASC,sBACdC,OAAyD,EACzD,EACEC,aAAaC,cAAc,EAC3BC,SAASC,UAAU,EAC+B;IAEpD,MAAMC,UAAU,IAAIC;IAEpB,KAAK,MAAMC,QAAQP,QAAQG,OAAO,CAAE;QAClCK,cAAcD;IAChB;IAEA,KAAK,MAAMA,QAAQP,QAAQC,WAAW,CAAE;QACtCQ,kBAAkBF;IACpB;IAEA,OAAOF;IAEP,SAASG,cAAcD,IAAgB;QACrC,MAAMG,SAASN,WAAWO,IAAI,CAAC,CAACC,IAAMA,EAAEL,IAAI,KAAKA;QACjD,IAAI,CAACG,QACH,OAAOG,QAAQC,IAAI,CACjB,CAAC,6DAA6D,EAAEP,MAAM;QAG1E,MAAMQ,oBAAoBC,kBAAkBN,OAAOO,MAAM;QACzD,KAAK,MAAMC,cAAcH,kBAAmB;YAC1CN,kBAAkBS;QACpB;IACF;IAEA,SAAST,kBAAkBF,IAAoB;QAC7C,IAAIF,QAAQc,GAAG,CAACZ,OAAO;QACvB,MAAMa,aAAalB,eAAeS,IAAI,CAAC,CAACU,IAAMA,EAAEd,IAAI,KAAKA;QACzD,IAAI,CAACa,YACH,OAAOP,QAAQC,IAAI,CACjB,CAAC,iEAAiE,EAAEP,MAAM;QAE9EF,QAAQiB,GAAG,CAACf;QAEZ,MAAMQ,oBAAoBC,kBAAkBI,WAAWH,MAAM;QAC7D,KAAK,MAAMC,cAAcH,kBAAmB;YAC1CN,kBAAkBS;QACpB;IACF;IAEA,SAASF,kBAAkBC,MAAe;QACxC,OAAOnB,WAAWmB,QAAQ,CAACM,QAAU,gBAAgBA,OAAOC,OAAO,CACjE,CAAC,EAAEC,UAAU,EAAE,GACbC,MAAMC,OAAO,CAACF,cAAcA,aAAa;gBAACA;aAAW;IAE3D;AACF"}
1
+ {"version":3,"sources":["../../src/utils/tracked-collections.ts"],"sourcesContent":["import { findFields } from '@davincicoding/payload-plugin-kit';\nimport type { CollectionSlug, Config, Field, GlobalSlug } from 'payload';\nimport type { ResolvedPluginOptions } from '../types';\n\nexport function getTrackedCollections(\n options: ResolvedPluginOptions<'collections' | 'globals'>,\n {\n collections: allCollections,\n globals: allGlobals,\n }: Required<Pick<Config, 'collections' | 'globals'>>,\n): Set<CollectionSlug> {\n const tracked = new Set<CollectionSlug>();\n\n for (const slug of options.globals) {\n processGlobal(slug);\n }\n\n for (const slug of options.collections) {\n processCollection(slug);\n }\n\n return tracked;\n\n function processGlobal(slug: GlobalSlug) {\n const global = allGlobals.find((g) => g.slug === slug);\n if (!global)\n return console.warn(\n `[payload-smart-cache] Global to track changes for not found: ${slug}`,\n );\n\n const nestedCollections = findRelationships(global.fields);\n for (const nestedSlug of nestedCollections) {\n processCollection(nestedSlug);\n }\n }\n\n function processCollection(slug: CollectionSlug) {\n if (tracked.has(slug)) return;\n const collection = allCollections.find((c) => c.slug === slug);\n if (!collection)\n return console.warn(\n `[payload-smart-cache] Collection to track changes for not found: ${slug}`,\n );\n tracked.add(slug);\n\n const nestedCollections = findRelationships(collection.fields);\n for (const nestedSlug of nestedCollections) {\n processCollection(nestedSlug);\n }\n }\n\n function findRelationships(fields: Field[]): CollectionSlug[] {\n return findFields(fields, (field) => 'relationTo' in field).flatMap(\n ({ relationTo }) =>\n Array.isArray(relationTo) ? relationTo : [relationTo],\n );\n }\n}\n"],"names":["findFields","getTrackedCollections","options","collections","allCollections","globals","allGlobals","tracked","Set","slug","processGlobal","processCollection","global","find","g","console","warn","nestedCollections","findRelationships","fields","nestedSlug","has","collection","c","add","field","flatMap","relationTo","Array","isArray"],"mappings":"AAAA,SAASA,UAAU,QAAQ,oCAAoC;AAI/D,OAAO,SAASC,sBACdC,OAAyD,EACzD,EACEC,aAAaC,cAAc,EAC3BC,SAASC,UAAU,EAC+B;IAEpD,MAAMC,UAAU,IAAIC;IAEpB,KAAK,MAAMC,QAAQP,QAAQG,OAAO,CAAE;QAClCK,cAAcD;IAChB;IAEA,KAAK,MAAMA,QAAQP,QAAQC,WAAW,CAAE;QACtCQ,kBAAkBF;IACpB;IAEA,OAAOF;IAEP,SAASG,cAAcD,IAAgB;QACrC,MAAMG,SAASN,WAAWO,IAAI,CAAC,CAACC,IAAMA,EAAEL,IAAI,KAAKA;QACjD,IAAI,CAACG,QACH,OAAOG,QAAQC,IAAI,CACjB,CAAC,6DAA6D,EAAEP,MAAM;QAG1E,MAAMQ,oBAAoBC,kBAAkBN,OAAOO,MAAM;QACzD,KAAK,MAAMC,cAAcH,kBAAmB;YAC1CN,kBAAkBS;QACpB;IACF;IAEA,SAAST,kBAAkBF,IAAoB;QAC7C,IAAIF,QAAQc,GAAG,CAACZ,OAAO;QACvB,MAAMa,aAAalB,eAAeS,IAAI,CAAC,CAACU,IAAMA,EAAEd,IAAI,KAAKA;QACzD,IAAI,CAACa,YACH,OAAOP,QAAQC,IAAI,CACjB,CAAC,iEAAiE,EAAEP,MAAM;QAE9EF,QAAQiB,GAAG,CAACf;QAEZ,MAAMQ,oBAAoBC,kBAAkBI,WAAWH,MAAM;QAC7D,KAAK,MAAMC,cAAcH,kBAAmB;YAC1CN,kBAAkBS;QACpB;IACF;IAEA,SAASF,kBAAkBC,MAAe;QACxC,OAAOnB,WAAWmB,QAAQ,CAACM,QAAU,gBAAgBA,OAAOC,OAAO,CACjE,CAAC,EAAEC,UAAU,EAAE,GACbC,MAAMC,OAAO,CAACF,cAAcA,aAAa;gBAACA;aAAW;IAE3D;AACF"}
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "payload-smart-cache",
3
- "version": "1.1.10",
3
+ "version": "1.2.1",
4
4
  "description": "Payload Plugin for Cached Data",
5
5
  "keywords": [
6
6
  "payload",
7
7
  "cached",
8
8
  "cache",
9
- "react",
10
9
  "next.js"
11
10
  ],
12
11
  "repository": {
@@ -22,18 +21,7 @@
22
21
  "types": "./dist/index.d.ts",
23
22
  "import": "./dist/index.js",
24
23
  "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
- "./client": {
32
- "types": "./dist/exports/client.d.ts",
33
- "import": "./dist/exports/client.js",
34
- "default": "./dist/exports/client.js"
35
- },
36
- "./styles.css": "./dist/styles.css"
24
+ }
37
25
  },
38
26
  "main": "./dist/index.js",
39
27
  "types": "./dist/index.d.ts",
@@ -43,28 +31,20 @@
43
31
  "dependencies": {
44
32
  "graph-data-structure": "^4.5.0",
45
33
  "lodash-es": "^4.17.21",
46
- "zod": "4.3.5",
47
- "@davincicoding/payload-plugin-kit": "0.0.4"
34
+ "@davincicoding/payload-plugin-kit": "0.0.5"
48
35
  },
49
36
  "devDependencies": {
50
- "@payloadcms/ui": "3.72.0",
51
37
  "@types/lodash-es": "^4.17.12",
52
38
  "@types/node": "^22.5.4",
53
- "@types/react": "19.2.1",
54
- "@types/react-dom": "19.2.1",
55
39
  "next": "15.5.9",
56
40
  "payload": "3.72.0",
57
- "react": "19.2.1",
58
- "react-dom": "19.2.1",
59
41
  "typescript": "5.7.3",
60
42
  "vite": "7.0.6",
61
43
  "vitest": "3.2.3"
62
44
  },
63
45
  "peerDependencies": {
64
- "@payloadcms/next": "3.72.0",
65
- "@payloadcms/ui": ">=3.72.0",
66
- "next": "15.5.9",
67
- "payload": "3.72.0"
46
+ "next": ">=15.5.9",
47
+ "payload": ">=3.72.0"
68
48
  },
69
49
  "engines": {
70
50
  "node": "^18.20.2 || >=20.9.0",
@@ -77,7 +57,7 @@
77
57
  "prebuild": "pnpm check:types",
78
58
  "build": "plugin-build",
79
59
  "check:types": "tsc --noEmit",
80
- "dev": "next dev dev",
60
+ "dev": "cd dev && pnpm dev",
81
61
  "dev:build": "plugin-build --watch",
82
62
  "generate:types": "generate-types",
83
63
  "lint": "biome check .",
@@ -1,2 +0,0 @@
1
- export declare function PublishButton(): import("react/jsx-runtime").JSX.Element | null;
2
- //# sourceMappingURL=PublishButton.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PublishButton.d.ts","sourceRoot":"","sources":["../../src/components/PublishButton.tsx"],"names":[],"mappings":"AAOA,wBAAgB,aAAa,mDAmD5B"}
@@ -1,52 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx } from "react/jsx-runtime";
3
- import { Button, toast, useConfig, useDocumentEvents } from '@payloadcms/ui';
4
- import { formatAdminURL } from 'payload/shared';
5
- import { useEffect, useState } from 'react';
6
- import { ENDPOINTS } from '../const';
7
- export function PublishButton() {
8
- const { config: { routes: { api: apiRoute } } } = useConfig();
9
- const { mostRecentUpdate } = useDocumentEvents();
10
- const [hasChanges, setHasChanges] = useState(false);
11
- const [isPublishing, setIsPublishing] = useState(false);
12
- const apiUrl = formatAdminURL({
13
- apiRoute
14
- });
15
- useEffect(()=>{
16
- ENDPOINTS.checkChanges.call(apiUrl).then(({ hasChanges })=>setHasChanges(hasChanges)).catch(()=>setHasChanges(true));
17
- }, [
18
- apiUrl
19
- ]);
20
- useEffect(()=>{
21
- if (!mostRecentUpdate) return;
22
- setHasChanges(true);
23
- }, [
24
- mostRecentUpdate
25
- ]);
26
- const handlePublish = async ()=>{
27
- setIsPublishing(true);
28
- const toastId = toast.loading('Publishing changes...');
29
- try {
30
- await ENDPOINTS.publishChanges.call(apiUrl);
31
- toast.success('Changes published successfully!', {
32
- id: toastId
33
- });
34
- setHasChanges(false);
35
- } catch (_error) {
36
- const message = _error instanceof Error ? _error.message : 'Failed to publish changes';
37
- toast.error(message, {
38
- id: toastId
39
- });
40
- } finally{
41
- setIsPublishing(false);
42
- }
43
- };
44
- if (!hasChanges) return null;
45
- return /*#__PURE__*/ _jsx(Button, {
46
- disabled: isPublishing,
47
- onClick: handlePublish,
48
- children: "Publish Changes"
49
- });
50
- }
51
-
52
- //# sourceMappingURL=PublishButton.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/components/PublishButton.tsx"],"sourcesContent":["'use client';\n\nimport { Button, toast, useConfig, useDocumentEvents } from '@payloadcms/ui';\nimport { formatAdminURL } from 'payload/shared';\nimport { useEffect, useState } from 'react';\nimport { ENDPOINTS } from '@/const';\n\nexport function PublishButton() {\n const {\n config: {\n routes: { api: apiRoute },\n },\n } = useConfig();\n const { mostRecentUpdate } = useDocumentEvents();\n\n const [hasChanges, setHasChanges] = useState(false);\n const [isPublishing, setIsPublishing] = useState(false);\n const apiUrl = formatAdminURL({ apiRoute });\n\n useEffect(() => {\n ENDPOINTS.checkChanges\n .call(apiUrl)\n .then(({ hasChanges }) => setHasChanges(hasChanges))\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 try {\n await ENDPOINTS.publishChanges.call(apiUrl);\n toast.success('Changes published successfully!', {\n id: toastId,\n });\n setHasChanges(false);\n } catch (_error) {\n const message =\n _error instanceof Error ? _error.message : 'Failed to publish changes';\n toast.error(message, {\n id: toastId,\n });\n } finally {\n setIsPublishing(false);\n }\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":["Button","toast","useConfig","useDocumentEvents","formatAdminURL","useEffect","useState","ENDPOINTS","PublishButton","config","routes","api","apiRoute","mostRecentUpdate","hasChanges","setHasChanges","isPublishing","setIsPublishing","apiUrl","checkChanges","call","then","catch","handlePublish","toastId","loading","publishChanges","success","id","_error","message","Error","error","disabled","onClick"],"mappings":"AAAA;;AAEA,SAASA,MAAM,EAAEC,KAAK,EAAEC,SAAS,EAAEC,iBAAiB,QAAQ,iBAAiB;AAC7E,SAASC,cAAc,QAAQ,iBAAiB;AAChD,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAQ;AAC5C,SAASC,SAAS,QAAQ,UAAU;AAEpC,OAAO,SAASC;IACd,MAAM,EACJC,QAAQ,EACNC,QAAQ,EAAEC,KAAKC,QAAQ,EAAE,EAC1B,EACF,GAAGV;IACJ,MAAM,EAAEW,gBAAgB,EAAE,GAAGV;IAE7B,MAAM,CAACW,YAAYC,cAAc,GAAGT,SAAS;IAC7C,MAAM,CAACU,cAAcC,gBAAgB,GAAGX,SAAS;IACjD,MAAMY,SAASd,eAAe;QAAEQ;IAAS;IAEzCP,UAAU;QACRE,UAAUY,YAAY,CACnBC,IAAI,CAACF,QACLG,IAAI,CAAC,CAAC,EAAEP,UAAU,EAAE,GAAKC,cAAcD,aACvCQ,KAAK,CAAC,IAAMP,cAAc;IAC/B,GAAG;QAACG;KAAO;IAEXb,UAAU;QACR,IAAI,CAACQ,kBAAkB;QACvBE,cAAc;IAChB,GAAG;QAACF;KAAiB;IAErB,MAAMU,gBAAgB;QACpBN,gBAAgB;QAChB,MAAMO,UAAUvB,MAAMwB,OAAO,CAAC;QAC9B,IAAI;YACF,MAAMlB,UAAUmB,cAAc,CAACN,IAAI,CAACF;YACpCjB,MAAM0B,OAAO,CAAC,mCAAmC;gBAC/CC,IAAIJ;YACN;YACAT,cAAc;QAChB,EAAE,OAAOc,QAAQ;YACf,MAAMC,UACJD,kBAAkBE,QAAQF,OAAOC,OAAO,GAAG;YAC7C7B,MAAM+B,KAAK,CAACF,SAAS;gBACnBF,IAAIJ;YACN;QACF,SAAU;YACRP,gBAAgB;QAClB;IACF;IAEA,IAAI,CAACH,YAAY,OAAO;IAExB,qBACE,KAACd;QAAOiC,UAAUjB;QAAckB,SAASX;kBAAe;;AAI5D"}
package/dist/const.d.ts DELETED
@@ -1,7 +0,0 @@
1
- export declare const ENDPOINTS: {
2
- publishChanges: import("@davincicoding/payload-plugin-kit").ProcedureBuilder<void>;
3
- checkChanges: import("@davincicoding/payload-plugin-kit").Procedure<void, {
4
- hasChanges: boolean;
5
- }>;
6
- };
7
- //# sourceMappingURL=const.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../src/const.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS;;;oBAQK,OAAO;;CACjC,CAAC"}
package/dist/const.js DELETED
@@ -1,13 +0,0 @@
1
- import { defineProcedure } from '@davincicoding/payload-plugin-kit';
2
- export const ENDPOINTS = {
3
- publishChanges: defineProcedure({
4
- path: '/smart-cache/publish',
5
- method: 'post'
6
- }),
7
- checkChanges: defineProcedure({
8
- path: '/smart-cache/check',
9
- method: 'get'
10
- }).returns()
11
- };
12
-
13
- //# sourceMappingURL=const.js.map
package/dist/const.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/const.ts"],"sourcesContent":["import { defineProcedure } from '@davincicoding/payload-plugin-kit';\n\nexport const ENDPOINTS = {\n publishChanges: defineProcedure({\n path: '/smart-cache/publish',\n method: 'post',\n }),\n checkChanges: defineProcedure({\n path: '/smart-cache/check',\n method: 'get',\n }).returns<{ hasChanges: boolean }>(),\n};\n"],"names":["defineProcedure","ENDPOINTS","publishChanges","path","method","checkChanges","returns"],"mappings":"AAAA,SAASA,eAAe,QAAQ,oCAAoC;AAEpE,OAAO,MAAMC,YAAY;IACvBC,gBAAgBF,gBAAgB;QAC9BG,MAAM;QACNC,QAAQ;IACV;IACAC,cAAcL,gBAAgB;QAC5BG,MAAM;QACNC,QAAQ;IACV,GAAGE,OAAO;AACZ,EAAE"}
@@ -1,3 +0,0 @@
1
- import type { Endpoint } from 'payload';
2
- export declare const checkEndpoint: Endpoint;
3
- //# sourceMappingURL=check.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/endpoints/check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAKxC,eAAO,MAAM,aAAa,EAAE,QAuB3B,CAAC"}
@@ -1,21 +0,0 @@
1
- import { APIError, headersWithCors } from 'payload';
2
- import { ENDPOINTS } from '../const';
3
- export const checkEndpoint = ENDPOINTS.checkChanges.endpoint(async (req)=>{
4
- if (!req.user) {
5
- throw new APIError('Unauthorized', 401);
6
- }
7
- const { totalDocs } = await req.payload.count({
8
- collection: 'publish-queue'
9
- });
10
- return Response.json({
11
- hasChanges: totalDocs > 0
12
- }, {
13
- status: 200,
14
- headers: headersWithCors({
15
- headers: new Headers(),
16
- req
17
- })
18
- });
19
- });
20
-
21
- //# sourceMappingURL=check.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/endpoints/check.ts"],"sourcesContent":["import type { Endpoint } from 'payload';\nimport { APIError, headersWithCors } from 'payload';\n\nimport { ENDPOINTS } from '@/const';\n\nexport const checkEndpoint: Endpoint = ENDPOINTS.checkChanges.endpoint(\n async (req) => {\n if (!req.user) {\n throw new APIError('Unauthorized', 401);\n }\n\n const { totalDocs } = await req.payload.count({\n collection: 'publish-queue',\n });\n\n return Response.json(\n {\n hasChanges: totalDocs > 0,\n },\n {\n status: 200,\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n },\n );\n },\n);\n"],"names":["APIError","headersWithCors","ENDPOINTS","checkEndpoint","checkChanges","endpoint","req","user","totalDocs","payload","count","collection","Response","json","hasChanges","status","headers","Headers"],"mappings":"AACA,SAASA,QAAQ,EAAEC,eAAe,QAAQ,UAAU;AAEpD,SAASC,SAAS,QAAQ,UAAU;AAEpC,OAAO,MAAMC,gBAA0BD,UAAUE,YAAY,CAACC,QAAQ,CACpE,OAAOC;IACL,IAAI,CAACA,IAAIC,IAAI,EAAE;QACb,MAAM,IAAIP,SAAS,gBAAgB;IACrC;IAEA,MAAM,EAAEQ,SAAS,EAAE,GAAG,MAAMF,IAAIG,OAAO,CAACC,KAAK,CAAC;QAC5CC,YAAY;IACd;IAEA,OAAOC,SAASC,IAAI,CAClB;QACEC,YAAYN,YAAY;IAC1B,GACA;QACEO,QAAQ;QACRC,SAASf,gBAAgB;YACvBe,SAAS,IAAIC;YACbX;QACF;IACF;AAEJ,GACA"}
@@ -1,4 +0,0 @@
1
- import type { Endpoint } from 'payload';
2
- import type { SmartCachePluginConfig } from '../index';
3
- export declare const createPublishChangesEndpoint: (publishHandler: SmartCachePluginConfig["publishHandler"]) => Endpoint;
4
- //# sourceMappingURL=publish.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/endpoints/publish.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAkB,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGxD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAKvD,eAAO,MAAM,4BAA4B,mBACvB,sBAAsB,CAAC,gBAAgB,CAAC,KACvD,QAoIC,CAAC"}
@@ -1,109 +0,0 @@
1
- import { revalidateTag } from 'next/cache';
2
- import { APIError, headersWithCors } from 'payload';
3
- import { ENDPOINTS } from '../const';
4
- import { CollectionChanges } from '../utils/collection-changes';
5
- import { createDependencyGraph } from '../utils/dependency-graph';
6
- export const createPublishChangesEndpoint = (publishHandler)=>ENDPOINTS.publishChanges.endpoint(async (req)=>{
7
- if (!req.user) {
8
- throw new APIError('Unauthorized', 401);
9
- }
10
- const { payload } = req;
11
- const { docs: changesToPublish } = await payload.find({
12
- collection: 'publish-queue',
13
- limit: 0,
14
- sort: '-updatedAt'
15
- });
16
- if (changesToPublish.length === 0) return Response.json({
17
- message: 'No changes to publish'
18
- });
19
- const tagsToInvalidate = new Set();
20
- const collectionChanges = new CollectionChanges();
21
- for (const change of changesToPublish){
22
- if (typeof change.entityId !== 'string') {
23
- tagsToInvalidate.add(change.entityType);
24
- }
25
- }
26
- collectionChanges.initialize(changesToPublish);
27
- const graph = createDependencyGraph(payload);
28
- async function trackAffectedItems(collection, ids, visited) {
29
- const dependents = graph.getDependants(collection);
30
- if (dependents.length === 0) return;
31
- for (const dependent of dependents){
32
- if (dependent.entity.type === 'global') {
33
- tagsToInvalidate.add(dependent.entity.slug);
34
- continue;
35
- }
36
- if (visited.has(dependent.entity.slug)) continue;
37
- // Query each field separately to avoid duplicate table alias errors
38
- // when multiple fields map to the same table (e.g., highlights.split-image-text.image
39
- // and architecture.split-image-text.image both use projects_blocks_split_image_text)
40
- const allAffectedItems = new Map();
41
- for (const field of dependent.fields){
42
- const { docs } = await payload.find({
43
- collection: dependent.entity.slug,
44
- where: field.polymorphic ? {
45
- and: [
46
- {
47
- [`${field.field}.relationTo`]: {
48
- equals: collection
49
- }
50
- },
51
- {
52
- [`${field.field}.value`]: {
53
- in: ids
54
- }
55
- }
56
- ]
57
- } : {
58
- [field.field]: {
59
- in: ids
60
- }
61
- }
62
- });
63
- // Use a Map keyed by ID to deduplicate results
64
- for (const item of docs){
65
- allAffectedItems.set(item.id.toString(), item);
66
- }
67
- }
68
- const affectedItems = Array.from(allAffectedItems.values());
69
- visited.add(dependent.entity.slug);
70
- if (affectedItems.length === 0) continue;
71
- for (const item of affectedItems){
72
- collectionChanges.addItem(dependent.entity.slug, item.id.toString());
73
- }
74
- await trackAffectedItems(dependent.entity.slug, affectedItems.map((item)=>item.id.toString()), visited);
75
- }
76
- }
77
- const initialCollections = Array.from(collectionChanges.entries()).map(([slug, ids])=>[
78
- slug,
79
- Array.from(ids)
80
- ]);
81
- for (const [collection, ids] of initialCollections){
82
- await trackAffectedItems(collection, ids, new Set());
83
- }
84
- for (const entity of collectionChanges.keys()){
85
- tagsToInvalidate.add(entity);
86
- }
87
- for (const tag of tagsToInvalidate){
88
- revalidateTag(tag);
89
- }
90
- await publishHandler?.(collectionChanges.serialize());
91
- await payload.delete({
92
- collection: 'publish-queue',
93
- where: {
94
- id: {
95
- in: changesToPublish.map((change)=>change.id)
96
- }
97
- }
98
- });
99
- return Response.json({
100
- message: 'OK'
101
- }, {
102
- headers: headersWithCors({
103
- headers: new Headers(),
104
- req
105
- })
106
- });
107
- });
108
-
109
- //# sourceMappingURL=publish.js.map