@brandlift/payload-loggs 1.2.0 → 1.3.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.
@@ -1,7 +1,7 @@
1
1
  import type { CollectionConfig } from 'payload';
2
2
  export type SiteActivityLogData = {
3
3
  title: string;
4
- operation: 'create' | 'update' | 'delete' | 'login' | 'logout' | 'publish' | 'unpublish';
4
+ operation: 'create' | 'update' | 'delete' | 'login' | 'logout' | 'publish' | 'unpublish' | 'draft_saved';
5
5
  resourceName?: string;
6
6
  resourceType: 'collection' | 'global';
7
7
  collectionLabel?: string;
@@ -56,6 +56,10 @@ export const SiteActivityCollection = {
56
56
  label: 'Unpublish',
57
57
  value: 'unpublish'
58
58
  },
59
+ {
60
+ label: 'Draft Saved',
61
+ value: 'draft_saved'
62
+ },
59
63
  {
60
64
  label: 'Login',
61
65
  value: 'login'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/collections/SiteActivityCollection.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload';\n\nexport type SiteActivityLogData = {\n title: string;\n operation: 'create' | 'update' | 'delete' | 'login' | 'logout' | 'publish' | 'unpublish';\n resourceName?: string;\n resourceType: 'collection' | 'global';\n collectionLabel?: string;\n slug: string;\n documentId?: string;\n locale?: string;\n user?: string | number;\n userEmail?: string;\n userDisplay?: string;\n createdAt?: string;\n};\n\nexport const SITE_ACTIVITY_SLUG = 'site-activity';\n\nexport const SiteActivityCollection: CollectionConfig = {\n slug: SITE_ACTIVITY_SLUG,\n labels: {\n plural: 'Site Activities',\n singular: 'Site Activity',\n },\n admin: {\n defaultColumns: ['title', 'operation', 'resourceName', 'collectionLabel', 'userDisplay', 'createdAt'],\n useAsTitle: 'title',\n },\n access: {\n read: ({ req }) => Boolean(req.user),\n create: () => false,\n update: () => false,\n delete: () => false,\n },\n fields: [\n {\n name: 'title',\n type: 'text',\n required: true,\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'operation',\n type: 'select',\n required: true,\n options: [\n { label: 'Create', value: 'create' },\n { label: 'Update', value: 'update' },\n { label: 'Delete', value: 'delete' },\n { label: 'Publish', value: 'publish' },\n { label: 'Unpublish', value: 'unpublish' },\n { label: 'Login', value: 'login' },\n { label: 'Logout', value: 'logout' },\n ],\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'resourceName',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'resourceType',\n type: 'select',\n required: true,\n options: [\n { label: 'Collection', value: 'collection' },\n { label: 'Global', value: 'global' },\n ],\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'collectionLabel',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'slug',\n type: 'text',\n required: true,\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'documentId',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'locale',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'user',\n type: 'relationship',\n relationTo: 'users',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'userEmail',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'userDisplay',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'createdAt',\n type: 'date',\n admin: {\n readOnly: true,\n },\n defaultValue: () => new Date().toISOString(),\n required: true,\n },\n ],\n timestamps: false,\n};\n\nexport default SiteActivityCollection;\n"],"names":["SITE_ACTIVITY_SLUG","SiteActivityCollection","slug","labels","plural","singular","admin","defaultColumns","useAsTitle","access","read","req","Boolean","user","create","update","delete","fields","name","type","required","readOnly","options","label","value","relationTo","defaultValue","Date","toISOString","timestamps"],"mappings":"AAiBA,OAAO,MAAMA,qBAAqB,gBAAgB;AAElD,OAAO,MAAMC,yBAA2C;IACtDC,MAAMF;IACNG,QAAQ;QACNC,QAAQ;QACRC,UAAU;IACZ;IACAC,OAAO;QACLC,gBAAgB;YAAC;YAAS;YAAa;YAAgB;YAAmB;YAAe;SAAY;QACrGC,YAAY;IACd;IACAC,QAAQ;QACNC,MAAM,CAAC,EAAEC,GAAG,EAAE,GAAKC,QAAQD,IAAIE,IAAI;QACnCC,QAAQ,IAAM;QACdC,QAAQ,IAAM;QACdC,QAAQ,IAAM;IAChB;IACAC,QAAQ;QACN;YACEC,MAAM;YACNC,MAAM;YACNC,UAAU;YACVd,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,UAAU;YACVE,SAAS;gBACP;oBAAEC,OAAO;oBAAUC,OAAO;gBAAS;gBACnC;oBAAED,OAAO;oBAAUC,OAAO;gBAAS;gBACnC;oBAAED,OAAO;oBAAUC,OAAO;gBAAS;gBACnC;oBAAED,OAAO;oBAAWC,OAAO;gBAAU;gBACrC;oBAAED,OAAO;oBAAaC,OAAO;gBAAY;gBACzC;oBAAED,OAAO;oBAASC,OAAO;gBAAQ;gBACjC;oBAAED,OAAO;oBAAUC,OAAO;gBAAS;aACpC;YACDlB,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,UAAU;YACVE,SAAS;gBACP;oBAAEC,OAAO;oBAAcC,OAAO;gBAAa;gBAC3C;oBAAED,OAAO;oBAAUC,OAAO;gBAAS;aACpC;YACDlB,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,UAAU;YACVd,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNM,YAAY;YACZnB,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;YACAK,cAAc,IAAM,IAAIC,OAAOC,WAAW;YAC1CR,UAAU;QACZ;KACD;IACDS,YAAY;AACd,EAAE;AAEF,eAAe5B,uBAAuB"}
1
+ {"version":3,"sources":["../../src/collections/SiteActivityCollection.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload';\n\nexport type SiteActivityLogData = {\n title: string;\n operation: 'create' | 'update' | 'delete' | 'login' | 'logout' | 'publish' | 'unpublish' | 'draft_saved';\n resourceName?: string;\n resourceType: 'collection' | 'global';\n collectionLabel?: string;\n slug: string;\n documentId?: string;\n locale?: string;\n user?: string | number;\n userEmail?: string;\n userDisplay?: string;\n createdAt?: string;\n};\n\nexport const SITE_ACTIVITY_SLUG = 'site-activity';\n\nexport const SiteActivityCollection: CollectionConfig = {\n slug: SITE_ACTIVITY_SLUG,\n labels: {\n plural: 'Site Activities',\n singular: 'Site Activity',\n },\n admin: {\n defaultColumns: ['title', 'operation', 'resourceName', 'collectionLabel', 'userDisplay', 'createdAt'],\n useAsTitle: 'title',\n },\n access: {\n read: ({ req }) => Boolean(req.user),\n create: () => false,\n update: () => false,\n delete: () => false,\n },\n fields: [\n {\n name: 'title',\n type: 'text',\n required: true,\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'operation',\n type: 'select',\n required: true,\n options: [\n { label: 'Create', value: 'create' },\n { label: 'Update', value: 'update' },\n { label: 'Delete', value: 'delete' },\n { label: 'Publish', value: 'publish' },\n { label: 'Unpublish', value: 'unpublish' },\n { label: 'Draft Saved', value: 'draft_saved' },\n { label: 'Login', value: 'login' },\n { label: 'Logout', value: 'logout' },\n ],\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'resourceName',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'resourceType',\n type: 'select',\n required: true,\n options: [\n { label: 'Collection', value: 'collection' },\n { label: 'Global', value: 'global' },\n ],\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'collectionLabel',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'slug',\n type: 'text',\n required: true,\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'documentId',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'locale',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'user',\n type: 'relationship',\n relationTo: 'users',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'userEmail',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'userDisplay',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'createdAt',\n type: 'date',\n admin: {\n readOnly: true,\n },\n defaultValue: () => new Date().toISOString(),\n required: true,\n },\n ],\n timestamps: false,\n};\n\nexport default SiteActivityCollection;\n"],"names":["SITE_ACTIVITY_SLUG","SiteActivityCollection","slug","labels","plural","singular","admin","defaultColumns","useAsTitle","access","read","req","Boolean","user","create","update","delete","fields","name","type","required","readOnly","options","label","value","relationTo","defaultValue","Date","toISOString","timestamps"],"mappings":"AAiBA,OAAO,MAAMA,qBAAqB,gBAAgB;AAElD,OAAO,MAAMC,yBAA2C;IACtDC,MAAMF;IACNG,QAAQ;QACNC,QAAQ;QACRC,UAAU;IACZ;IACAC,OAAO;QACLC,gBAAgB;YAAC;YAAS;YAAa;YAAgB;YAAmB;YAAe;SAAY;QACrGC,YAAY;IACd;IACAC,QAAQ;QACNC,MAAM,CAAC,EAAEC,GAAG,EAAE,GAAKC,QAAQD,IAAIE,IAAI;QACnCC,QAAQ,IAAM;QACdC,QAAQ,IAAM;QACdC,QAAQ,IAAM;IAChB;IACAC,QAAQ;QACN;YACEC,MAAM;YACNC,MAAM;YACNC,UAAU;YACVd,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,UAAU;YACVE,SAAS;gBACP;oBAAEC,OAAO;oBAAUC,OAAO;gBAAS;gBACnC;oBAAED,OAAO;oBAAUC,OAAO;gBAAS;gBACnC;oBAAED,OAAO;oBAAUC,OAAO;gBAAS;gBACnC;oBAAED,OAAO;oBAAWC,OAAO;gBAAU;gBACrC;oBAAED,OAAO;oBAAaC,OAAO;gBAAY;gBACzC;oBAAED,OAAO;oBAAeC,OAAO;gBAAc;gBAC7C;oBAAED,OAAO;oBAASC,OAAO;gBAAQ;gBACjC;oBAAED,OAAO;oBAAUC,OAAO;gBAAS;aACpC;YACDlB,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,UAAU;YACVE,SAAS;gBACP;oBAAEC,OAAO;oBAAcC,OAAO;gBAAa;gBAC3C;oBAAED,OAAO;oBAAUC,OAAO;gBAAS;aACpC;YACDlB,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNC,UAAU;YACVd,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNM,YAAY;YACZnB,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;QACF;QACA;YACEH,MAAM;YACNC,MAAM;YACNb,OAAO;gBACLe,UAAU;YACZ;YACAK,cAAc,IAAM,IAAIC,OAAOC,WAAW;YAC1CR,UAAU;QACZ;KACD;IACDS,YAAY;AACd,EAAE;AAEF,eAAe5B,uBAAuB"}
@@ -1,15 +1,33 @@
1
+ import { ActivityEvent } from '../types/events.js';
1
2
  import { getResourceTitle } from '../pluginUtils/getResourceTitle.js';
2
3
  import { formatUserDisplay } from '../pluginUtils/formatUserDisplay.js';
3
4
  import { getCollectionLabel } from '../pluginUtils/getCollectionLabel.js';
4
5
  import { SITE_ACTIVITY_SLUG } from '../collections/SiteActivityCollection.js';
5
- import { getCollectionActivityDetails } from '../pluginUtils/getActivityDetails.js';
6
+ import { getActivityLabel, getCollectionActivityDetails } from '../pluginUtils/getActivityDetails.js';
7
+ function isDuplicateEvent(req, collectionSlug, docId, eventKey) {
8
+ if (!req || !req.context) {
9
+ return false;
10
+ }
11
+ const loggedEvents = req.context._loggedActivityEvents || new Set();
12
+ const fullKey = `${collectionSlug}:${docId}:${eventKey}`;
13
+ if (loggedEvents.has(fullKey)) {
14
+ return true;
15
+ }
16
+ loggedEvents.add(fullKey);
17
+ req.context._loggedActivityEvents = loggedEvents;
18
+ return false;
19
+ }
6
20
  export const createCollectionAfterChangeHook = (collection, payloadConfig, _pluginConfig)=>{
7
21
  return async ({ doc, previousDoc, operation, req })=>{
8
22
  if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {
9
23
  return doc;
10
24
  }
11
25
  try {
12
- const { title, operation: opType } = getCollectionActivityDetails(collection, operation, doc, previousDoc);
26
+ const { event, title, operation: opType } = getCollectionActivityDetails(collection, operation, doc, previousDoc, req);
27
+ const docId = doc?.id ? String(doc.id) : 'new';
28
+ if (isDuplicateEvent(req, collection.slug, docId, event)) {
29
+ return doc;
30
+ }
13
31
  const label = getCollectionLabel(collection);
14
32
  const resourceName = getResourceTitle(doc, doc?.id);
15
33
  const isLocalizationEnabled = Boolean(payloadConfig.localization);
@@ -60,8 +78,12 @@ export const createCollectionAfterDeleteHook = (collection, payloadConfig, _plug
60
78
  return doc;
61
79
  }
62
80
  try {
81
+ const docId = id ? String(id) : 'unknown';
82
+ if (isDuplicateEvent(req, collection.slug, docId, ActivityEvent.DELETED)) {
83
+ return doc;
84
+ }
63
85
  const label = getCollectionLabel(collection);
64
- const title = `${label} deleted`;
86
+ const title = getActivityLabel(ActivityEvent.DELETED, label);
65
87
  const resourceName = getResourceTitle(doc, id);
66
88
  const isLocalizationEnabled = Boolean(payloadConfig.localization);
67
89
  const locale = isLocalizationEnabled ? req.locale : undefined;
@@ -77,7 +99,7 @@ export const createCollectionAfterDeleteHook = (collection, payloadConfig, _plug
77
99
  resourceType: 'collection',
78
100
  collectionLabel: label,
79
101
  slug: collection.slug,
80
- documentId: id ? String(id) : undefined,
102
+ documentId: docId !== 'unknown' ? docId : undefined,
81
103
  ...locale ? {
82
104
  locale
83
105
  } : {},
@@ -111,10 +133,14 @@ export const createCollectionAfterLoginHook = (collection, _payloadConfig, _plug
111
133
  return user;
112
134
  }
113
135
  try {
136
+ const userId = user?.id ? String(user.id) : 'user';
137
+ if (isDuplicateEvent(req, collection.slug, userId, ActivityEvent.USER_LOGIN)) {
138
+ return user;
139
+ }
114
140
  const label = getCollectionLabel(collection);
115
141
  const userEmail = user?.email || req.user?.email;
116
142
  const userDisplay = formatUserDisplay(userEmail);
117
- const title = userDisplay ? `User ${userDisplay} logged in` : `${label} logged in`;
143
+ const title = getActivityLabel(ActivityEvent.USER_LOGIN, label);
118
144
  await req.payload.create({
119
145
  collection: SITE_ACTIVITY_SLUG,
120
146
  data: {
@@ -155,10 +181,14 @@ export const createCollectionAfterLogoutHook = (collection, _payloadConfig, _plu
155
181
  return;
156
182
  }
157
183
  try {
184
+ const userId = req.user?.id ? String(req.user.id) : 'user';
185
+ if (isDuplicateEvent(req, collection.slug, userId, ActivityEvent.USER_LOGOUT)) {
186
+ return;
187
+ }
158
188
  const label = getCollectionLabel(collection);
159
189
  const userEmail = req.user?.email;
160
190
  const userDisplay = formatUserDisplay(userEmail);
161
- const title = userDisplay ? `User ${userDisplay} logged out` : `${label} logged out`;
191
+ const title = getActivityLabel(ActivityEvent.USER_LOGOUT, label);
162
192
  await req.payload.create({
163
193
  collection: SITE_ACTIVITY_SLUG,
164
194
  data: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/collectionHooks.ts"],"sourcesContent":["import type { CollectionAfterChangeHook, CollectionAfterDeleteHook, CollectionAfterLoginHook, CollectionAfterLogoutHook, CollectionConfig, Config } from 'payload';\n\nimport type { PluginConfig } from '../types/config.js';\nimport { getResourceTitle } from '../pluginUtils/getResourceTitle.js';\nimport { formatUserDisplay } from '../pluginUtils/formatUserDisplay.js';\nimport { getCollectionLabel } from '../pluginUtils/getCollectionLabel.js';\nimport { SITE_ACTIVITY_SLUG } from '../collections/SiteActivityCollection.js';\nimport { getCollectionActivityDetails } from '../pluginUtils/getActivityDetails.js';\n\nexport const createCollectionAfterChangeHook = (\n collection: CollectionConfig,\n payloadConfig: Config,\n _pluginConfig?: PluginConfig,\n): CollectionAfterChangeHook => {\n return async ({ doc, previousDoc, operation, req }) => {\n if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {\n return doc;\n }\n\n try {\n const { title, operation: opType } = getCollectionActivityDetails(\n collection,\n operation as 'create' | 'update',\n doc as Record<string, unknown>,\n previousDoc as Record<string, unknown> | undefined,\n );\n const label = getCollectionLabel(collection);\n\n const resourceName = getResourceTitle(doc, doc?.id);\n const isLocalizationEnabled = Boolean(payloadConfig.localization);\n const locale = isLocalizationEnabled ? req.locale : undefined;\n\n const userEmail = req.user?.email || (doc && typeof doc === 'object' && 'email' in doc && typeof doc.email === 'string' ? doc.email : undefined);\n const userDisplay = formatUserDisplay(userEmail);\n const userId = req.user?.id || (doc && typeof doc === 'object' && 'id' in doc ? doc.id : undefined);\n\n await req.payload.create({\n collection: SITE_ACTIVITY_SLUG,\n data: {\n title,\n operation: opType,\n resourceName,\n resourceType: 'collection',\n collectionLabel: label,\n slug: collection.slug,\n documentId: doc?.id ? String(doc.id) : undefined,\n ...(locale ? { locale } : {}),\n ...(userId !== undefined && userId !== null ? { user: userId } : {}),\n ...(userEmail ? { userEmail } : {}),\n ...(userDisplay ? { userDisplay } : {}),\n },\n req,\n overrideAccess: true,\n context: {\n ...req.context,\n skipLogs: true,\n skipAuditorLogs: true,\n },\n });\n }\n catch (error) {\n req.payload?.logger?.error?.(`[payload-loggs] Error logging collection afterChange for ${collection.slug}: ${error}`);\n }\n\n return doc;\n };\n};\n\nexport const createCollectionAfterDeleteHook = (\n collection: CollectionConfig,\n payloadConfig: Config,\n _pluginConfig?: PluginConfig,\n): CollectionAfterDeleteHook => {\n return async ({ doc, id, req }) => {\n if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {\n return doc;\n }\n\n try {\n const label = getCollectionLabel(collection);\n const title = `${label} deleted`;\n\n const resourceName = getResourceTitle(doc, id);\n const isLocalizationEnabled = Boolean(payloadConfig.localization);\n const locale = isLocalizationEnabled ? req.locale : undefined;\n\n const userEmail = req.user?.email || (doc && typeof doc === 'object' && 'email' in doc && typeof doc.email === 'string' ? doc.email : undefined);\n const userDisplay = formatUserDisplay(userEmail);\n const userId = req.user?.id || (doc && typeof doc === 'object' && 'id' in doc ? doc.id : undefined);\n\n await req.payload.create({\n collection: SITE_ACTIVITY_SLUG,\n data: {\n title,\n operation: 'delete',\n resourceName,\n resourceType: 'collection',\n collectionLabel: label,\n slug: collection.slug,\n documentId: id ? String(id) : undefined,\n ...(locale ? { locale } : {}),\n ...(userId !== undefined && userId !== null ? { user: userId } : {}),\n ...(userEmail ? { userEmail } : {}),\n ...(userDisplay ? { userDisplay } : {}),\n },\n req,\n overrideAccess: true,\n context: {\n ...req.context,\n skipLogs: true,\n skipAuditorLogs: true,\n },\n });\n }\n catch (error) {\n req.payload?.logger?.error?.(`[payload-loggs] Error logging collection afterDelete for ${collection.slug}: ${error}`);\n }\n\n return doc;\n };\n};\n\nexport const createCollectionAfterLoginHook = (\n collection: CollectionConfig,\n _payloadConfig: Config,\n _pluginConfig?: PluginConfig,\n): CollectionAfterLoginHook => {\n return async ({ user, req }) => {\n if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {\n return user;\n }\n\n try {\n const label = getCollectionLabel(collection);\n const userEmail = user?.email || req.user?.email;\n const userDisplay = formatUserDisplay(userEmail);\n const title = userDisplay ? `User ${userDisplay} logged in` : `${label} logged in`;\n\n await req.payload.create({\n collection: SITE_ACTIVITY_SLUG,\n data: {\n title,\n operation: 'login',\n resourceName: userEmail || String(user?.id || 'User'),\n resourceType: 'collection',\n collectionLabel: label,\n slug: collection.slug,\n documentId: user?.id ? String(user.id) : undefined,\n ...(user?.id !== undefined && user?.id !== null ? { user: user.id } : {}),\n ...(userEmail ? { userEmail } : {}),\n ...(userDisplay ? { userDisplay } : {}),\n },\n req,\n overrideAccess: true,\n context: {\n ...req.context,\n skipLogs: true,\n skipAuditorLogs: true,\n },\n });\n }\n catch (error) {\n req.payload?.logger?.error?.(`[payload-loggs] Error logging afterLogin for ${collection.slug}: ${error}`);\n }\n\n return user;\n };\n};\n\nexport const createCollectionAfterLogoutHook = (\n collection: CollectionConfig,\n _payloadConfig: Config,\n _pluginConfig?: PluginConfig,\n): CollectionAfterLogoutHook => {\n return async ({ req }) => {\n if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {\n return;\n }\n\n try {\n const label = getCollectionLabel(collection);\n const userEmail = req.user?.email;\n const userDisplay = formatUserDisplay(userEmail);\n const title = userDisplay ? `User ${userDisplay} logged out` : `${label} logged out`;\n\n await req.payload.create({\n collection: SITE_ACTIVITY_SLUG,\n data: {\n title,\n operation: 'logout',\n resourceName: userEmail || String(req.user?.id || 'User'),\n resourceType: 'collection',\n collectionLabel: label,\n slug: collection.slug,\n documentId: req.user?.id ? String(req.user.id) : undefined,\n ...(req.user?.id !== undefined && req.user?.id !== null ? { user: req.user.id } : {}),\n ...(userEmail ? { userEmail } : {}),\n ...(userDisplay ? { userDisplay } : {}),\n },\n req,\n overrideAccess: true,\n context: {\n ...req.context,\n skipLogs: true,\n skipAuditorLogs: true,\n },\n });\n }\n catch (error) {\n req.payload?.logger?.error?.(`[payload-loggs] Error logging afterLogout for ${collection.slug}: ${error}`);\n }\n };\n};\n"],"names":["getResourceTitle","formatUserDisplay","getCollectionLabel","SITE_ACTIVITY_SLUG","getCollectionActivityDetails","createCollectionAfterChangeHook","collection","payloadConfig","_pluginConfig","doc","previousDoc","operation","req","context","skipLogs","skipAuditorLogs","title","opType","label","resourceName","id","isLocalizationEnabled","Boolean","localization","locale","undefined","userEmail","user","email","userDisplay","userId","payload","create","data","resourceType","collectionLabel","slug","documentId","String","overrideAccess","error","logger","createCollectionAfterDeleteHook","createCollectionAfterLoginHook","_payloadConfig","createCollectionAfterLogoutHook"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/hooks/collectionHooks.ts"],"sourcesContent":["import type { CollectionAfterChangeHook, CollectionAfterDeleteHook, CollectionAfterLoginHook, CollectionAfterLogoutHook, CollectionConfig, Config } from 'payload';\n\nimport { ActivityEvent } from '../types/events.js';\nimport type { PluginConfig } from '../types/config.js';\nimport { getResourceTitle } from '../pluginUtils/getResourceTitle.js';\nimport { formatUserDisplay } from '../pluginUtils/formatUserDisplay.js';\nimport { getCollectionLabel } from '../pluginUtils/getCollectionLabel.js';\nimport { SITE_ACTIVITY_SLUG } from '../collections/SiteActivityCollection.js';\nimport { getActivityLabel, getCollectionActivityDetails } from '../pluginUtils/getActivityDetails.js';\n\nfunction isDuplicateEvent(req: any, collectionSlug: string, docId: string, eventKey: string): boolean {\n if (!req || !req.context) {\n return false;\n }\n\n const loggedEvents: Set<string> = (req.context._loggedActivityEvents as Set<string>) || new Set<string>();\n const fullKey = `${collectionSlug}:${docId}:${eventKey}`;\n\n if (loggedEvents.has(fullKey)) {\n return true;\n }\n\n loggedEvents.add(fullKey);\n req.context._loggedActivityEvents = loggedEvents;\n return false;\n}\n\nexport const createCollectionAfterChangeHook = (\n collection: CollectionConfig,\n payloadConfig: Config,\n _pluginConfig?: PluginConfig,\n): CollectionAfterChangeHook => {\n return async ({ doc, previousDoc, operation, req }) => {\n if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {\n return doc;\n }\n\n try {\n const { event, title, operation: opType } = getCollectionActivityDetails(\n collection,\n operation as 'create' | 'update',\n doc as Record<string, unknown>,\n previousDoc as Record<string, unknown> | undefined,\n req,\n );\n\n const docId = doc?.id ? String(doc.id) : 'new';\n if (isDuplicateEvent(req, collection.slug, docId, event)) {\n return doc;\n }\n\n const label = getCollectionLabel(collection);\n const resourceName = getResourceTitle(doc, doc?.id);\n const isLocalizationEnabled = Boolean(payloadConfig.localization);\n const locale = isLocalizationEnabled ? req.locale : undefined;\n\n const userEmail = req.user?.email || (doc && typeof doc === 'object' && 'email' in doc && typeof doc.email === 'string' ? doc.email : undefined);\n const userDisplay = formatUserDisplay(userEmail);\n const userId = req.user?.id || (doc && typeof doc === 'object' && 'id' in doc ? doc.id : undefined);\n\n await req.payload.create({\n collection: SITE_ACTIVITY_SLUG,\n data: {\n title,\n operation: opType,\n resourceName,\n resourceType: 'collection',\n collectionLabel: label,\n slug: collection.slug,\n documentId: doc?.id ? String(doc.id) : undefined,\n ...(locale ? { locale } : {}),\n ...(userId !== undefined && userId !== null ? { user: userId } : {}),\n ...(userEmail ? { userEmail } : {}),\n ...(userDisplay ? { userDisplay } : {}),\n },\n req,\n overrideAccess: true,\n context: {\n ...req.context,\n skipLogs: true,\n skipAuditorLogs: true,\n },\n });\n }\n catch (error) {\n req.payload?.logger?.error?.(`[payload-loggs] Error logging collection afterChange for ${collection.slug}: ${error}`);\n }\n\n return doc;\n };\n};\n\nexport const createCollectionAfterDeleteHook = (\n collection: CollectionConfig,\n payloadConfig: Config,\n _pluginConfig?: PluginConfig,\n): CollectionAfterDeleteHook => {\n return async ({ doc, id, req }) => {\n if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {\n return doc;\n }\n\n try {\n const docId = id ? String(id) : 'unknown';\n if (isDuplicateEvent(req, collection.slug, docId, ActivityEvent.DELETED)) {\n return doc;\n }\n\n const label = getCollectionLabel(collection);\n const title = getActivityLabel(ActivityEvent.DELETED, label);\n\n const resourceName = getResourceTitle(doc, id);\n const isLocalizationEnabled = Boolean(payloadConfig.localization);\n const locale = isLocalizationEnabled ? req.locale : undefined;\n\n const userEmail = req.user?.email || (doc && typeof doc === 'object' && 'email' in doc && typeof doc.email === 'string' ? doc.email : undefined);\n const userDisplay = formatUserDisplay(userEmail);\n const userId = req.user?.id || (doc && typeof doc === 'object' && 'id' in doc ? doc.id : undefined);\n\n await req.payload.create({\n collection: SITE_ACTIVITY_SLUG,\n data: {\n title,\n operation: 'delete',\n resourceName,\n resourceType: 'collection',\n collectionLabel: label,\n slug: collection.slug,\n documentId: docId !== 'unknown' ? docId : undefined,\n ...(locale ? { locale } : {}),\n ...(userId !== undefined && userId !== null ? { user: userId } : {}),\n ...(userEmail ? { userEmail } : {}),\n ...(userDisplay ? { userDisplay } : {}),\n },\n req,\n overrideAccess: true,\n context: {\n ...req.context,\n skipLogs: true,\n skipAuditorLogs: true,\n },\n });\n }\n catch (error) {\n req.payload?.logger?.error?.(`[payload-loggs] Error logging collection afterDelete for ${collection.slug}: ${error}`);\n }\n\n return doc;\n };\n};\n\nexport const createCollectionAfterLoginHook = (\n collection: CollectionConfig,\n _payloadConfig: Config,\n _pluginConfig?: PluginConfig,\n): CollectionAfterLoginHook => {\n return async ({ user, req }) => {\n if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {\n return user;\n }\n\n try {\n const userId = user?.id ? String(user.id) : 'user';\n if (isDuplicateEvent(req, collection.slug, userId, ActivityEvent.USER_LOGIN)) {\n return user;\n }\n\n const label = getCollectionLabel(collection);\n const userEmail = user?.email || req.user?.email;\n const userDisplay = formatUserDisplay(userEmail);\n const title = getActivityLabel(ActivityEvent.USER_LOGIN, label);\n\n await req.payload.create({\n collection: SITE_ACTIVITY_SLUG,\n data: {\n title,\n operation: 'login',\n resourceName: userEmail || String(user?.id || 'User'),\n resourceType: 'collection',\n collectionLabel: label,\n slug: collection.slug,\n documentId: user?.id ? String(user.id) : undefined,\n ...(user?.id !== undefined && user?.id !== null ? { user: user.id } : {}),\n ...(userEmail ? { userEmail } : {}),\n ...(userDisplay ? { userDisplay } : {}),\n },\n req,\n overrideAccess: true,\n context: {\n ...req.context,\n skipLogs: true,\n skipAuditorLogs: true,\n },\n });\n }\n catch (error) {\n req.payload?.logger?.error?.(`[payload-loggs] Error logging afterLogin for ${collection.slug}: ${error}`);\n }\n\n return user;\n };\n};\n\nexport const createCollectionAfterLogoutHook = (\n collection: CollectionConfig,\n _payloadConfig: Config,\n _pluginConfig?: PluginConfig,\n): CollectionAfterLogoutHook => {\n return async ({ req }) => {\n if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {\n return;\n }\n\n try {\n const userId = req.user?.id ? String(req.user.id) : 'user';\n if (isDuplicateEvent(req, collection.slug, userId, ActivityEvent.USER_LOGOUT)) {\n return;\n }\n\n const label = getCollectionLabel(collection);\n const userEmail = req.user?.email;\n const userDisplay = formatUserDisplay(userEmail);\n const title = getActivityLabel(ActivityEvent.USER_LOGOUT, label);\n\n await req.payload.create({\n collection: SITE_ACTIVITY_SLUG,\n data: {\n title,\n operation: 'logout',\n resourceName: userEmail || String(req.user?.id || 'User'),\n resourceType: 'collection',\n collectionLabel: label,\n slug: collection.slug,\n documentId: req.user?.id ? String(req.user.id) : undefined,\n ...(req.user?.id !== undefined && req.user?.id !== null ? { user: req.user.id } : {}),\n ...(userEmail ? { userEmail } : {}),\n ...(userDisplay ? { userDisplay } : {}),\n },\n req,\n overrideAccess: true,\n context: {\n ...req.context,\n skipLogs: true,\n skipAuditorLogs: true,\n },\n });\n }\n catch (error) {\n req.payload?.logger?.error?.(`[payload-loggs] Error logging afterLogout for ${collection.slug}: ${error}`);\n }\n };\n};\n"],"names":["ActivityEvent","getResourceTitle","formatUserDisplay","getCollectionLabel","SITE_ACTIVITY_SLUG","getActivityLabel","getCollectionActivityDetails","isDuplicateEvent","req","collectionSlug","docId","eventKey","context","loggedEvents","_loggedActivityEvents","Set","fullKey","has","add","createCollectionAfterChangeHook","collection","payloadConfig","_pluginConfig","doc","previousDoc","operation","skipLogs","skipAuditorLogs","event","title","opType","id","String","slug","label","resourceName","isLocalizationEnabled","Boolean","localization","locale","undefined","userEmail","user","email","userDisplay","userId","payload","create","data","resourceType","collectionLabel","documentId","overrideAccess","error","logger","createCollectionAfterDeleteHook","DELETED","createCollectionAfterLoginHook","_payloadConfig","USER_LOGIN","createCollectionAfterLogoutHook","USER_LOGOUT"],"mappings":"AAEA,SAASA,aAAa,QAAQ,qBAAqB;AAEnD,SAASC,gBAAgB,QAAQ,qCAAqC;AACtE,SAASC,iBAAiB,QAAQ,sCAAsC;AACxE,SAASC,kBAAkB,QAAQ,uCAAuC;AAC1E,SAASC,kBAAkB,QAAQ,2CAA2C;AAC9E,SAASC,gBAAgB,EAAEC,4BAA4B,QAAQ,uCAAuC;AAEtG,SAASC,iBAAiBC,GAAQ,EAAEC,cAAsB,EAAEC,KAAa,EAAEC,QAAgB;IACzF,IAAI,CAACH,OAAO,CAACA,IAAII,OAAO,EAAE;QACxB,OAAO;IACT;IAEA,MAAMC,eAA4B,AAACL,IAAII,OAAO,CAACE,qBAAqB,IAAoB,IAAIC;IAC5F,MAAMC,UAAU,GAAGP,eAAe,CAAC,EAAEC,MAAM,CAAC,EAAEC,UAAU;IAExD,IAAIE,aAAaI,GAAG,CAACD,UAAU;QAC7B,OAAO;IACT;IAEAH,aAAaK,GAAG,CAACF;IACjBR,IAAII,OAAO,CAACE,qBAAqB,GAAGD;IACpC,OAAO;AACT;AAEA,OAAO,MAAMM,kCAAkC,CAC7CC,YACAC,eACAC;IAEA,OAAO,OAAO,EAAEC,GAAG,EAAEC,WAAW,EAAEC,SAAS,EAAEjB,GAAG,EAAE;QAChD,IAAI,CAACA,OAAOA,IAAII,OAAO,EAAEc,YAAYlB,IAAII,OAAO,EAAEe,iBAAiB;YACjE,OAAOJ;QACT;QAEA,IAAI;YACF,MAAM,EAAEK,KAAK,EAAEC,KAAK,EAAEJ,WAAWK,MAAM,EAAE,GAAGxB,6BAC1Cc,YACAK,WACAF,KACAC,aACAhB;YAGF,MAAME,QAAQa,KAAKQ,KAAKC,OAAOT,IAAIQ,EAAE,IAAI;YACzC,IAAIxB,iBAAiBC,KAAKY,WAAWa,IAAI,EAAEvB,OAAOkB,QAAQ;gBACxD,OAAOL;YACT;YAEA,MAAMW,QAAQ/B,mBAAmBiB;YACjC,MAAMe,eAAelC,iBAAiBsB,KAAKA,KAAKQ;YAChD,MAAMK,wBAAwBC,QAAQhB,cAAciB,YAAY;YAChE,MAAMC,SAASH,wBAAwB5B,IAAI+B,MAAM,GAAGC;YAEpD,MAAMC,YAAYjC,IAAIkC,IAAI,EAAEC,SAAUpB,CAAAA,OAAO,OAAOA,QAAQ,YAAY,WAAWA,OAAO,OAAOA,IAAIoB,KAAK,KAAK,WAAWpB,IAAIoB,KAAK,GAAGH,SAAQ;YAC9I,MAAMI,cAAc1C,kBAAkBuC;YACtC,MAAMI,SAASrC,IAAIkC,IAAI,EAAEX,MAAOR,CAAAA,OAAO,OAAOA,QAAQ,YAAY,QAAQA,MAAMA,IAAIQ,EAAE,GAAGS,SAAQ;YAEjG,MAAMhC,IAAIsC,OAAO,CAACC,MAAM,CAAC;gBACvB3B,YAAYhB;gBACZ4C,MAAM;oBACJnB;oBACAJ,WAAWK;oBACXK;oBACAc,cAAc;oBACdC,iBAAiBhB;oBACjBD,MAAMb,WAAWa,IAAI;oBACrBkB,YAAY5B,KAAKQ,KAAKC,OAAOT,IAAIQ,EAAE,IAAIS;oBACvC,GAAID,SAAS;wBAAEA;oBAAO,IAAI,CAAC,CAAC;oBAC5B,GAAIM,WAAWL,aAAaK,WAAW,OAAO;wBAAEH,MAAMG;oBAAO,IAAI,CAAC,CAAC;oBACnE,GAAIJ,YAAY;wBAAEA;oBAAU,IAAI,CAAC,CAAC;oBAClC,GAAIG,cAAc;wBAAEA;oBAAY,IAAI,CAAC,CAAC;gBACxC;gBACApC;gBACA4C,gBAAgB;gBAChBxC,SAAS;oBACP,GAAGJ,IAAII,OAAO;oBACdc,UAAU;oBACVC,iBAAiB;gBACnB;YACF;QACF,EACA,OAAO0B,OAAO;YACZ7C,IAAIsC,OAAO,EAAEQ,QAAQD,QAAQ,CAAC,yDAAyD,EAAEjC,WAAWa,IAAI,CAAC,EAAE,EAAEoB,OAAO;QACtH;QAEA,OAAO9B;IACT;AACF,EAAE;AAEF,OAAO,MAAMgC,kCAAkC,CAC7CnC,YACAC,eACAC;IAEA,OAAO,OAAO,EAAEC,GAAG,EAAEQ,EAAE,EAAEvB,GAAG,EAAE;QAC5B,IAAI,CAACA,OAAOA,IAAII,OAAO,EAAEc,YAAYlB,IAAII,OAAO,EAAEe,iBAAiB;YACjE,OAAOJ;QACT;QAEA,IAAI;YACF,MAAMb,QAAQqB,KAAKC,OAAOD,MAAM;YAChC,IAAIxB,iBAAiBC,KAAKY,WAAWa,IAAI,EAAEvB,OAAOV,cAAcwD,OAAO,GAAG;gBACxE,OAAOjC;YACT;YAEA,MAAMW,QAAQ/B,mBAAmBiB;YACjC,MAAMS,QAAQxB,iBAAiBL,cAAcwD,OAAO,EAAEtB;YAEtD,MAAMC,eAAelC,iBAAiBsB,KAAKQ;YAC3C,MAAMK,wBAAwBC,QAAQhB,cAAciB,YAAY;YAChE,MAAMC,SAASH,wBAAwB5B,IAAI+B,MAAM,GAAGC;YAEpD,MAAMC,YAAYjC,IAAIkC,IAAI,EAAEC,SAAUpB,CAAAA,OAAO,OAAOA,QAAQ,YAAY,WAAWA,OAAO,OAAOA,IAAIoB,KAAK,KAAK,WAAWpB,IAAIoB,KAAK,GAAGH,SAAQ;YAC9I,MAAMI,cAAc1C,kBAAkBuC;YACtC,MAAMI,SAASrC,IAAIkC,IAAI,EAAEX,MAAOR,CAAAA,OAAO,OAAOA,QAAQ,YAAY,QAAQA,MAAMA,IAAIQ,EAAE,GAAGS,SAAQ;YAEjG,MAAMhC,IAAIsC,OAAO,CAACC,MAAM,CAAC;gBACvB3B,YAAYhB;gBACZ4C,MAAM;oBACJnB;oBACAJ,WAAW;oBACXU;oBACAc,cAAc;oBACdC,iBAAiBhB;oBACjBD,MAAMb,WAAWa,IAAI;oBACrBkB,YAAYzC,UAAU,YAAYA,QAAQ8B;oBAC1C,GAAID,SAAS;wBAAEA;oBAAO,IAAI,CAAC,CAAC;oBAC5B,GAAIM,WAAWL,aAAaK,WAAW,OAAO;wBAAEH,MAAMG;oBAAO,IAAI,CAAC,CAAC;oBACnE,GAAIJ,YAAY;wBAAEA;oBAAU,IAAI,CAAC,CAAC;oBAClC,GAAIG,cAAc;wBAAEA;oBAAY,IAAI,CAAC,CAAC;gBACxC;gBACApC;gBACA4C,gBAAgB;gBAChBxC,SAAS;oBACP,GAAGJ,IAAII,OAAO;oBACdc,UAAU;oBACVC,iBAAiB;gBACnB;YACF;QACF,EACA,OAAO0B,OAAO;YACZ7C,IAAIsC,OAAO,EAAEQ,QAAQD,QAAQ,CAAC,yDAAyD,EAAEjC,WAAWa,IAAI,CAAC,EAAE,EAAEoB,OAAO;QACtH;QAEA,OAAO9B;IACT;AACF,EAAE;AAEF,OAAO,MAAMkC,iCAAiC,CAC5CrC,YACAsC,gBACApC;IAEA,OAAO,OAAO,EAAEoB,IAAI,EAAElC,GAAG,EAAE;QACzB,IAAI,CAACA,OAAOA,IAAII,OAAO,EAAEc,YAAYlB,IAAII,OAAO,EAAEe,iBAAiB;YACjE,OAAOe;QACT;QAEA,IAAI;YACF,MAAMG,SAASH,MAAMX,KAAKC,OAAOU,KAAKX,EAAE,IAAI;YAC5C,IAAIxB,iBAAiBC,KAAKY,WAAWa,IAAI,EAAEY,QAAQ7C,cAAc2D,UAAU,GAAG;gBAC5E,OAAOjB;YACT;YAEA,MAAMR,QAAQ/B,mBAAmBiB;YACjC,MAAMqB,YAAYC,MAAMC,SAASnC,IAAIkC,IAAI,EAAEC;YAC3C,MAAMC,cAAc1C,kBAAkBuC;YACtC,MAAMZ,QAAQxB,iBAAiBL,cAAc2D,UAAU,EAAEzB;YAEzD,MAAM1B,IAAIsC,OAAO,CAACC,MAAM,CAAC;gBACvB3B,YAAYhB;gBACZ4C,MAAM;oBACJnB;oBACAJ,WAAW;oBACXU,cAAcM,aAAaT,OAAOU,MAAMX,MAAM;oBAC9CkB,cAAc;oBACdC,iBAAiBhB;oBACjBD,MAAMb,WAAWa,IAAI;oBACrBkB,YAAYT,MAAMX,KAAKC,OAAOU,KAAKX,EAAE,IAAIS;oBACzC,GAAIE,MAAMX,OAAOS,aAAaE,MAAMX,OAAO,OAAO;wBAAEW,MAAMA,KAAKX,EAAE;oBAAC,IAAI,CAAC,CAAC;oBACxE,GAAIU,YAAY;wBAAEA;oBAAU,IAAI,CAAC,CAAC;oBAClC,GAAIG,cAAc;wBAAEA;oBAAY,IAAI,CAAC,CAAC;gBACxC;gBACApC;gBACA4C,gBAAgB;gBAChBxC,SAAS;oBACP,GAAGJ,IAAII,OAAO;oBACdc,UAAU;oBACVC,iBAAiB;gBACnB;YACF;QACF,EACA,OAAO0B,OAAO;YACZ7C,IAAIsC,OAAO,EAAEQ,QAAQD,QAAQ,CAAC,6CAA6C,EAAEjC,WAAWa,IAAI,CAAC,EAAE,EAAEoB,OAAO;QAC1G;QAEA,OAAOX;IACT;AACF,EAAE;AAEF,OAAO,MAAMkB,kCAAkC,CAC7CxC,YACAsC,gBACApC;IAEA,OAAO,OAAO,EAAEd,GAAG,EAAE;QACnB,IAAI,CAACA,OAAOA,IAAII,OAAO,EAAEc,YAAYlB,IAAII,OAAO,EAAEe,iBAAiB;YACjE;QACF;QAEA,IAAI;YACF,MAAMkB,SAASrC,IAAIkC,IAAI,EAAEX,KAAKC,OAAOxB,IAAIkC,IAAI,CAACX,EAAE,IAAI;YACpD,IAAIxB,iBAAiBC,KAAKY,WAAWa,IAAI,EAAEY,QAAQ7C,cAAc6D,WAAW,GAAG;gBAC7E;YACF;YAEA,MAAM3B,QAAQ/B,mBAAmBiB;YACjC,MAAMqB,YAAYjC,IAAIkC,IAAI,EAAEC;YAC5B,MAAMC,cAAc1C,kBAAkBuC;YACtC,MAAMZ,QAAQxB,iBAAiBL,cAAc6D,WAAW,EAAE3B;YAE1D,MAAM1B,IAAIsC,OAAO,CAACC,MAAM,CAAC;gBACvB3B,YAAYhB;gBACZ4C,MAAM;oBACJnB;oBACAJ,WAAW;oBACXU,cAAcM,aAAaT,OAAOxB,IAAIkC,IAAI,EAAEX,MAAM;oBAClDkB,cAAc;oBACdC,iBAAiBhB;oBACjBD,MAAMb,WAAWa,IAAI;oBACrBkB,YAAY3C,IAAIkC,IAAI,EAAEX,KAAKC,OAAOxB,IAAIkC,IAAI,CAACX,EAAE,IAAIS;oBACjD,GAAIhC,IAAIkC,IAAI,EAAEX,OAAOS,aAAahC,IAAIkC,IAAI,EAAEX,OAAO,OAAO;wBAAEW,MAAMlC,IAAIkC,IAAI,CAACX,EAAE;oBAAC,IAAI,CAAC,CAAC;oBACpF,GAAIU,YAAY;wBAAEA;oBAAU,IAAI,CAAC,CAAC;oBAClC,GAAIG,cAAc;wBAAEA;oBAAY,IAAI,CAAC,CAAC;gBACxC;gBACApC;gBACA4C,gBAAgB;gBAChBxC,SAAS;oBACP,GAAGJ,IAAII,OAAO;oBACdc,UAAU;oBACVC,iBAAiB;gBACnB;YACF;QACF,EACA,OAAO0B,OAAO;YACZ7C,IAAIsC,OAAO,EAAEQ,QAAQD,QAAQ,CAAC,8CAA8C,EAAEjC,WAAWa,IAAI,CAAC,EAAE,EAAEoB,OAAO;QAC3G;IACF;AACF,EAAE"}
@@ -3,13 +3,29 @@ import { formatUserDisplay } from '../pluginUtils/formatUserDisplay.js';
3
3
  import { getCollectionLabel } from '../pluginUtils/getCollectionLabel.js';
4
4
  import { SITE_ACTIVITY_SLUG } from '../collections/SiteActivityCollection.js';
5
5
  import { getGlobalActivityDetails } from '../pluginUtils/getActivityDetails.js';
6
+ function isDuplicateEvent(req, globalSlug, eventKey) {
7
+ if (!req || !req.context) {
8
+ return false;
9
+ }
10
+ const loggedEvents = req.context._loggedActivityEvents || new Set();
11
+ const fullKey = `global:${globalSlug}:${eventKey}`;
12
+ if (loggedEvents.has(fullKey)) {
13
+ return true;
14
+ }
15
+ loggedEvents.add(fullKey);
16
+ req.context._loggedActivityEvents = loggedEvents;
17
+ return false;
18
+ }
6
19
  export const createGlobalAfterChangeHook = (globalConfig, payloadConfig, _pluginConfig)=>{
7
20
  return async ({ doc, previousDoc, req })=>{
8
21
  if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {
9
22
  return doc;
10
23
  }
11
24
  try {
12
- const { title, operation: opType } = getGlobalActivityDetails(globalConfig, doc, previousDoc);
25
+ const { event, title, operation: opType } = getGlobalActivityDetails(globalConfig, doc, previousDoc, req);
26
+ if (isDuplicateEvent(req, globalConfig.slug, event)) {
27
+ return doc;
28
+ }
13
29
  const label = getCollectionLabel(globalConfig);
14
30
  const resourceName = getResourceTitle(doc) || label;
15
31
  const isLocalizationEnabled = Boolean(payloadConfig.localization);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/hooks/globalHooks.ts"],"sourcesContent":["import type { Config, GlobalAfterChangeHook, GlobalConfig } from 'payload';\n\nimport type { PluginConfig } from '../types/config.js';\nimport { getResourceTitle } from '../pluginUtils/getResourceTitle.js';\nimport { formatUserDisplay } from '../pluginUtils/formatUserDisplay.js';\nimport { getCollectionLabel } from '../pluginUtils/getCollectionLabel.js';\nimport { SITE_ACTIVITY_SLUG } from '../collections/SiteActivityCollection.js';\nimport { getGlobalActivityDetails } from '../pluginUtils/getActivityDetails.js';\n\nexport const createGlobalAfterChangeHook = (\n globalConfig: GlobalConfig,\n payloadConfig: Config,\n _pluginConfig?: PluginConfig,\n): GlobalAfterChangeHook => {\n return async ({ doc, previousDoc, req }: { doc: Record<string, unknown>; previousDoc?: Record<string, unknown>; req?: any }) => {\n if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {\n return doc;\n }\n\n try {\n const { title, operation: opType } = getGlobalActivityDetails(\n globalConfig,\n doc as Record<string, unknown>,\n previousDoc as Record<string, unknown> | undefined,\n );\n const label = getCollectionLabel(globalConfig);\n\n const resourceName = getResourceTitle(doc) || label;\n const isLocalizationEnabled = Boolean(payloadConfig.localization);\n const locale = isLocalizationEnabled ? req.locale : undefined;\n\n const userEmail = req.user?.email;\n const userDisplay = formatUserDisplay(userEmail);\n const userId = req.user?.id;\n\n await req.payload.create({\n collection: SITE_ACTIVITY_SLUG,\n data: {\n title,\n operation: opType,\n resourceName,\n resourceType: 'global',\n collectionLabel: label,\n slug: globalConfig.slug,\n ...(locale ? { locale } : {}),\n ...(userId !== undefined && userId !== null ? { user: userId } : {}),\n ...(userEmail ? { userEmail } : {}),\n ...(userDisplay ? { userDisplay } : {}),\n },\n req,\n overrideAccess: true,\n context: {\n ...req.context,\n skipLogs: true,\n skipAuditorLogs: true,\n },\n });\n }\n catch (error) {\n req.payload?.logger?.error?.(`[payload-loggs] Error logging global afterChange for ${globalConfig.slug}: ${error}`);\n }\n\n return doc;\n };\n};\n"],"names":["getResourceTitle","formatUserDisplay","getCollectionLabel","SITE_ACTIVITY_SLUG","getGlobalActivityDetails","createGlobalAfterChangeHook","globalConfig","payloadConfig","_pluginConfig","doc","previousDoc","req","context","skipLogs","skipAuditorLogs","title","operation","opType","label","resourceName","isLocalizationEnabled","Boolean","localization","locale","undefined","userEmail","user","email","userDisplay","userId","id","payload","create","collection","data","resourceType","collectionLabel","slug","overrideAccess","error","logger"],"mappings":"AAGA,SAASA,gBAAgB,QAAQ,qCAAqC;AACtE,SAASC,iBAAiB,QAAQ,sCAAsC;AACxE,SAASC,kBAAkB,QAAQ,uCAAuC;AAC1E,SAASC,kBAAkB,QAAQ,2CAA2C;AAC9E,SAASC,wBAAwB,QAAQ,uCAAuC;AAEhF,OAAO,MAAMC,8BAA8B,CACzCC,cACAC,eACAC;IAEA,OAAO,OAAO,EAAEC,GAAG,EAAEC,WAAW,EAAEC,GAAG,EAAsF;QACzH,IAAI,CAACA,OAAOA,IAAIC,OAAO,EAAEC,YAAYF,IAAIC,OAAO,EAAEE,iBAAiB;YACjE,OAAOL;QACT;QAEA,IAAI;YACF,MAAM,EAAEM,KAAK,EAAEC,WAAWC,MAAM,EAAE,GAAGb,yBACnCE,cACAG,KACAC;YAEF,MAAMQ,QAAQhB,mBAAmBI;YAEjC,MAAMa,eAAenB,iBAAiBS,QAAQS;YAC9C,MAAME,wBAAwBC,QAAQd,cAAce,YAAY;YAChE,MAAMC,SAASH,wBAAwBT,IAAIY,MAAM,GAAGC;YAEpD,MAAMC,YAAYd,IAAIe,IAAI,EAAEC;YAC5B,MAAMC,cAAc3B,kBAAkBwB;YACtC,MAAMI,SAASlB,IAAIe,IAAI,EAAEI;YAEzB,MAAMnB,IAAIoB,OAAO,CAACC,MAAM,CAAC;gBACvBC,YAAY9B;gBACZ+B,MAAM;oBACJnB;oBACAC,WAAWC;oBACXE;oBACAgB,cAAc;oBACdC,iBAAiBlB;oBACjBmB,MAAM/B,aAAa+B,IAAI;oBACvB,GAAId,SAAS;wBAAEA;oBAAO,IAAI,CAAC,CAAC;oBAC5B,GAAIM,WAAWL,aAAaK,WAAW,OAAO;wBAAEH,MAAMG;oBAAO,IAAI,CAAC,CAAC;oBACnE,GAAIJ,YAAY;wBAAEA;oBAAU,IAAI,CAAC,CAAC;oBAClC,GAAIG,cAAc;wBAAEA;oBAAY,IAAI,CAAC,CAAC;gBACxC;gBACAjB;gBACA2B,gBAAgB;gBAChB1B,SAAS;oBACP,GAAGD,IAAIC,OAAO;oBACdC,UAAU;oBACVC,iBAAiB;gBACnB;YACF;QACF,EACA,OAAOyB,OAAO;YACZ5B,IAAIoB,OAAO,EAAES,QAAQD,QAAQ,CAAC,qDAAqD,EAAEjC,aAAa+B,IAAI,CAAC,EAAE,EAAEE,OAAO;QACpH;QAEA,OAAO9B;IACT;AACF,EAAE"}
1
+ {"version":3,"sources":["../../src/hooks/globalHooks.ts"],"sourcesContent":["import type { Config, GlobalAfterChangeHook, GlobalConfig } from 'payload';\n\nimport type { PluginConfig } from '../types/config.js';\nimport { getResourceTitle } from '../pluginUtils/getResourceTitle.js';\nimport { formatUserDisplay } from '../pluginUtils/formatUserDisplay.js';\nimport { getCollectionLabel } from '../pluginUtils/getCollectionLabel.js';\nimport { SITE_ACTIVITY_SLUG } from '../collections/SiteActivityCollection.js';\nimport { getGlobalActivityDetails } from '../pluginUtils/getActivityDetails.js';\n\nfunction isDuplicateEvent(req: any, globalSlug: string, eventKey: string): boolean {\n if (!req || !req.context) {\n return false;\n }\n\n const loggedEvents: Set<string> = (req.context._loggedActivityEvents as Set<string>) || new Set<string>();\n const fullKey = `global:${globalSlug}:${eventKey}`;\n\n if (loggedEvents.has(fullKey)) {\n return true;\n }\n\n loggedEvents.add(fullKey);\n req.context._loggedActivityEvents = loggedEvents;\n return false;\n}\n\nexport const createGlobalAfterChangeHook = (\n globalConfig: GlobalConfig,\n payloadConfig: Config,\n _pluginConfig?: PluginConfig,\n): GlobalAfterChangeHook => {\n return async ({ doc, previousDoc, req }: { doc: Record<string, unknown>; previousDoc?: Record<string, unknown>; req?: any }) => {\n if (!req || req.context?.skipLogs || req.context?.skipAuditorLogs) {\n return doc;\n }\n\n try {\n const { event, title, operation: opType } = getGlobalActivityDetails(\n globalConfig,\n doc as Record<string, unknown>,\n previousDoc as Record<string, unknown> | undefined,\n req,\n );\n\n if (isDuplicateEvent(req, globalConfig.slug, event)) {\n return doc;\n }\n\n const label = getCollectionLabel(globalConfig);\n const resourceName = getResourceTitle(doc) || label;\n const isLocalizationEnabled = Boolean(payloadConfig.localization);\n const locale = isLocalizationEnabled ? req.locale : undefined;\n\n const userEmail = req.user?.email;\n const userDisplay = formatUserDisplay(userEmail);\n const userId = req.user?.id;\n\n await req.payload.create({\n collection: SITE_ACTIVITY_SLUG,\n data: {\n title,\n operation: opType,\n resourceName,\n resourceType: 'global',\n collectionLabel: label,\n slug: globalConfig.slug,\n ...(locale ? { locale } : {}),\n ...(userId !== undefined && userId !== null ? { user: userId } : {}),\n ...(userEmail ? { userEmail } : {}),\n ...(userDisplay ? { userDisplay } : {}),\n },\n req,\n overrideAccess: true,\n context: {\n ...req.context,\n skipLogs: true,\n skipAuditorLogs: true,\n },\n });\n }\n catch (error) {\n req.payload?.logger?.error?.(`[payload-loggs] Error logging global afterChange for ${globalConfig.slug}: ${error}`);\n }\n\n return doc;\n };\n};\n"],"names":["getResourceTitle","formatUserDisplay","getCollectionLabel","SITE_ACTIVITY_SLUG","getGlobalActivityDetails","isDuplicateEvent","req","globalSlug","eventKey","context","loggedEvents","_loggedActivityEvents","Set","fullKey","has","add","createGlobalAfterChangeHook","globalConfig","payloadConfig","_pluginConfig","doc","previousDoc","skipLogs","skipAuditorLogs","event","title","operation","opType","slug","label","resourceName","isLocalizationEnabled","Boolean","localization","locale","undefined","userEmail","user","email","userDisplay","userId","id","payload","create","collection","data","resourceType","collectionLabel","overrideAccess","error","logger"],"mappings":"AAGA,SAASA,gBAAgB,QAAQ,qCAAqC;AACtE,SAASC,iBAAiB,QAAQ,sCAAsC;AACxE,SAASC,kBAAkB,QAAQ,uCAAuC;AAC1E,SAASC,kBAAkB,QAAQ,2CAA2C;AAC9E,SAASC,wBAAwB,QAAQ,uCAAuC;AAEhF,SAASC,iBAAiBC,GAAQ,EAAEC,UAAkB,EAAEC,QAAgB;IACtE,IAAI,CAACF,OAAO,CAACA,IAAIG,OAAO,EAAE;QACxB,OAAO;IACT;IAEA,MAAMC,eAA4B,AAACJ,IAAIG,OAAO,CAACE,qBAAqB,IAAoB,IAAIC;IAC5F,MAAMC,UAAU,CAAC,OAAO,EAAEN,WAAW,CAAC,EAAEC,UAAU;IAElD,IAAIE,aAAaI,GAAG,CAACD,UAAU;QAC7B,OAAO;IACT;IAEAH,aAAaK,GAAG,CAACF;IACjBP,IAAIG,OAAO,CAACE,qBAAqB,GAAGD;IACpC,OAAO;AACT;AAEA,OAAO,MAAMM,8BAA8B,CACzCC,cACAC,eACAC;IAEA,OAAO,OAAO,EAAEC,GAAG,EAAEC,WAAW,EAAEf,GAAG,EAAsF;QACzH,IAAI,CAACA,OAAOA,IAAIG,OAAO,EAAEa,YAAYhB,IAAIG,OAAO,EAAEc,iBAAiB;YACjE,OAAOH;QACT;QAEA,IAAI;YACF,MAAM,EAAEI,KAAK,EAAEC,KAAK,EAAEC,WAAWC,MAAM,EAAE,GAAGvB,yBAC1Ca,cACAG,KACAC,aACAf;YAGF,IAAID,iBAAiBC,KAAKW,aAAaW,IAAI,EAAEJ,QAAQ;gBACnD,OAAOJ;YACT;YAEA,MAAMS,QAAQ3B,mBAAmBe;YACjC,MAAMa,eAAe9B,iBAAiBoB,QAAQS;YAC9C,MAAME,wBAAwBC,QAAQd,cAAce,YAAY;YAChE,MAAMC,SAASH,wBAAwBzB,IAAI4B,MAAM,GAAGC;YAEpD,MAAMC,YAAY9B,IAAI+B,IAAI,EAAEC;YAC5B,MAAMC,cAActC,kBAAkBmC;YACtC,MAAMI,SAASlC,IAAI+B,IAAI,EAAEI;YAEzB,MAAMnC,IAAIoC,OAAO,CAACC,MAAM,CAAC;gBACvBC,YAAYzC;gBACZ0C,MAAM;oBACJpB;oBACAC,WAAWC;oBACXG;oBACAgB,cAAc;oBACdC,iBAAiBlB;oBACjBD,MAAMX,aAAaW,IAAI;oBACvB,GAAIM,SAAS;wBAAEA;oBAAO,IAAI,CAAC,CAAC;oBAC5B,GAAIM,WAAWL,aAAaK,WAAW,OAAO;wBAAEH,MAAMG;oBAAO,IAAI,CAAC,CAAC;oBACnE,GAAIJ,YAAY;wBAAEA;oBAAU,IAAI,CAAC,CAAC;oBAClC,GAAIG,cAAc;wBAAEA;oBAAY,IAAI,CAAC,CAAC;gBACxC;gBACAjC;gBACA0C,gBAAgB;gBAChBvC,SAAS;oBACP,GAAGH,IAAIG,OAAO;oBACda,UAAU;oBACVC,iBAAiB;gBACnB;YACF;QACF,EACA,OAAO0B,OAAO;YACZ3C,IAAIoC,OAAO,EAAEQ,QAAQD,QAAQ,CAAC,qDAAqD,EAAEhC,aAAaW,IAAI,CAAC,EAAE,EAAEqB,OAAO;QACpH;QAEA,OAAO7B;IACT;AACF,EAAE"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { ActivityEvent } from './types/events.js';
1
2
  import { getResourceTitle } from './pluginUtils/getResourceTitle.js';
2
3
  import type { SiteActivityLog } from './collections/siteActivity.js';
3
4
  import { formatUserDisplay } from './pluginUtils/formatUserDisplay.js';
@@ -5,8 +6,10 @@ import { getCollectionLabel } from './pluginUtils/getCollectionLabel.js';
5
6
  import { payloadLoggsPlugin, siteActivity, siteActivityPlugin } from './plugin.js';
6
7
  import { siteActivity as siteActivityCollection } from './collections/siteActivity.js';
7
8
  import { SITE_ACTIVITY_SLUG, SiteActivityCollection } from './collections/SiteActivityCollection.js';
9
+ import { getActivityEvent, getActivityLabel, getCollectionActivityDetails, getGlobalActivityDetails } from './pluginUtils/getActivityDetails.js';
8
10
  export type { SiteActivityLogData } from './collections/SiteActivityCollection.js';
9
11
  export type { AutomationConfig, PluginConfig } from './types/config.js';
12
+ export type { ActivityClassificationParams, ActivityDetails } from './types/events.js';
10
13
  export type { SiteActivityLog };
11
- export { formatUserDisplay, getCollectionLabel, getResourceTitle, payloadLoggsPlugin, SITE_ACTIVITY_SLUG, siteActivity, SiteActivityCollection, siteActivityCollection, siteActivityPlugin, };
14
+ export { ActivityEvent, formatUserDisplay, getActivityEvent, getActivityLabel, getCollectionActivityDetails, getCollectionLabel, getGlobalActivityDetails, getResourceTitle, payloadLoggsPlugin, SITE_ACTIVITY_SLUG, siteActivity, SiteActivityCollection, siteActivityCollection, siteActivityPlugin, };
12
15
  export default siteActivity;
package/dist/index.js CHANGED
@@ -1,10 +1,12 @@
1
+ import { ActivityEvent } from './types/events.js';
1
2
  import { getResourceTitle } from './pluginUtils/getResourceTitle.js';
2
3
  import { formatUserDisplay } from './pluginUtils/formatUserDisplay.js';
3
4
  import { getCollectionLabel } from './pluginUtils/getCollectionLabel.js';
4
5
  import { payloadLoggsPlugin, siteActivity, siteActivityPlugin } from './plugin.js';
5
6
  import { siteActivity as siteActivityCollection } from './collections/siteActivity.js';
6
7
  import { SITE_ACTIVITY_SLUG, SiteActivityCollection } from './collections/SiteActivityCollection.js';
7
- export { formatUserDisplay, getCollectionLabel, getResourceTitle, payloadLoggsPlugin, SITE_ACTIVITY_SLUG, siteActivity, SiteActivityCollection, siteActivityCollection, siteActivityPlugin };
8
+ import { getActivityEvent, getActivityLabel, getCollectionActivityDetails, getGlobalActivityDetails } from './pluginUtils/getActivityDetails.js';
9
+ export { ActivityEvent, formatUserDisplay, getActivityEvent, getActivityLabel, getCollectionActivityDetails, getCollectionLabel, getGlobalActivityDetails, getResourceTitle, payloadLoggsPlugin, SITE_ACTIVITY_SLUG, siteActivity, SiteActivityCollection, siteActivityCollection, siteActivityPlugin };
8
10
  export default siteActivity;
9
11
 
10
12
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { getResourceTitle } from './pluginUtils/getResourceTitle.js';\nimport type { SiteActivityLog } from './collections/siteActivity.js';\nimport { formatUserDisplay } from './pluginUtils/formatUserDisplay.js';\nimport { getCollectionLabel } from './pluginUtils/getCollectionLabel.js';\nimport { payloadLoggsPlugin, siteActivity, siteActivityPlugin } from './plugin.js';\nimport { siteActivity as siteActivityCollection } from './collections/siteActivity.js';\nimport { SITE_ACTIVITY_SLUG, SiteActivityCollection } from './collections/SiteActivityCollection.js';\n\nexport type { SiteActivityLogData } from './collections/SiteActivityCollection.js';\nexport type { AutomationConfig, PluginConfig } from './types/config.js';\nexport type { SiteActivityLog };\n\nexport {\n formatUserDisplay,\n getCollectionLabel,\n getResourceTitle,\n payloadLoggsPlugin,\n SITE_ACTIVITY_SLUG,\n siteActivity,\n SiteActivityCollection,\n siteActivityCollection,\n siteActivityPlugin,\n};\n\nexport default siteActivity;\n"],"names":["getResourceTitle","formatUserDisplay","getCollectionLabel","payloadLoggsPlugin","siteActivity","siteActivityPlugin","siteActivityCollection","SITE_ACTIVITY_SLUG","SiteActivityCollection"],"mappings":"AAAA,SAASA,gBAAgB,QAAQ,oCAAoC;AAErE,SAASC,iBAAiB,QAAQ,qCAAqC;AACvE,SAASC,kBAAkB,QAAQ,sCAAsC;AACzE,SAASC,kBAAkB,EAAEC,YAAY,EAAEC,kBAAkB,QAAQ,cAAc;AACnF,SAASD,gBAAgBE,sBAAsB,QAAQ,gCAAgC;AACvF,SAASC,kBAAkB,EAAEC,sBAAsB,QAAQ,0CAA0C;AAMrG,SACEP,iBAAiB,EACjBC,kBAAkB,EAClBF,gBAAgB,EAChBG,kBAAkB,EAClBI,kBAAkB,EAClBH,YAAY,EACZI,sBAAsB,EACtBF,sBAAsB,EACtBD,kBAAkB,GAClB;AAEF,eAAeD,aAAa"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { ActivityEvent } from './types/events.js';\nimport { getResourceTitle } from './pluginUtils/getResourceTitle.js';\nimport type { SiteActivityLog } from './collections/siteActivity.js';\nimport { formatUserDisplay } from './pluginUtils/formatUserDisplay.js';\nimport { getCollectionLabel } from './pluginUtils/getCollectionLabel.js';\nimport { payloadLoggsPlugin, siteActivity, siteActivityPlugin } from './plugin.js';\nimport { siteActivity as siteActivityCollection } from './collections/siteActivity.js';\nimport { SITE_ACTIVITY_SLUG, SiteActivityCollection } from './collections/SiteActivityCollection.js';\nimport { getActivityEvent, getActivityLabel, getCollectionActivityDetails, getGlobalActivityDetails } from './pluginUtils/getActivityDetails.js';\n\nexport type { SiteActivityLogData } from './collections/SiteActivityCollection.js';\nexport type { AutomationConfig, PluginConfig } from './types/config.js';\nexport type { ActivityClassificationParams, ActivityDetails } from './types/events.js';\nexport type { SiteActivityLog };\n\nexport {\n ActivityEvent,\n formatUserDisplay,\n getActivityEvent,\n getActivityLabel,\n getCollectionActivityDetails,\n getCollectionLabel,\n getGlobalActivityDetails,\n getResourceTitle,\n payloadLoggsPlugin,\n SITE_ACTIVITY_SLUG,\n siteActivity,\n SiteActivityCollection,\n siteActivityCollection,\n siteActivityPlugin,\n};\n\nexport default siteActivity;\n"],"names":["ActivityEvent","getResourceTitle","formatUserDisplay","getCollectionLabel","payloadLoggsPlugin","siteActivity","siteActivityPlugin","siteActivityCollection","SITE_ACTIVITY_SLUG","SiteActivityCollection","getActivityEvent","getActivityLabel","getCollectionActivityDetails","getGlobalActivityDetails"],"mappings":"AAAA,SAASA,aAAa,QAAQ,oBAAoB;AAClD,SAASC,gBAAgB,QAAQ,oCAAoC;AAErE,SAASC,iBAAiB,QAAQ,qCAAqC;AACvE,SAASC,kBAAkB,QAAQ,sCAAsC;AACzE,SAASC,kBAAkB,EAAEC,YAAY,EAAEC,kBAAkB,QAAQ,cAAc;AACnF,SAASD,gBAAgBE,sBAAsB,QAAQ,gCAAgC;AACvF,SAASC,kBAAkB,EAAEC,sBAAsB,QAAQ,0CAA0C;AACrG,SAASC,gBAAgB,EAAEC,gBAAgB,EAAEC,4BAA4B,EAAEC,wBAAwB,QAAQ,sCAAsC;AAOjJ,SACEb,aAAa,EACbE,iBAAiB,EACjBQ,gBAAgB,EAChBC,gBAAgB,EAChBC,4BAA4B,EAC5BT,kBAAkB,EAClBU,wBAAwB,EACxBZ,gBAAgB,EAChBG,kBAAkB,EAClBI,kBAAkB,EAClBH,YAAY,EACZI,sBAAsB,EACtBF,sBAAsB,EACtBD,kBAAkB,GAClB;AAEF,eAAeD,aAAa"}
@@ -1,8 +1,9 @@
1
1
  import type { CollectionConfig, GlobalConfig } from 'payload';
2
+ import { ActivityEvent } from '../types/events.js';
2
3
  import type { SiteActivityLogData } from '../collections/SiteActivityCollection.js';
3
- export interface ActivityDetails {
4
- title: string;
5
- operation: SiteActivityLogData['operation'];
6
- }
7
- export declare function getCollectionActivityDetails(collection: CollectionConfig, operation: 'create' | 'update', doc: Record<string, unknown> | undefined, previousDoc?: Record<string, unknown>): ActivityDetails;
8
- export declare function getGlobalActivityDetails(globalConfig: GlobalConfig, doc: Record<string, unknown> | undefined, previousDoc?: Record<string, unknown>): ActivityDetails;
4
+ import type { ActivityClassificationParams, ActivityDetails } from '../types/events.js';
5
+ export declare function getActivityLabel(event: ActivityEvent, resourceLabel: string, isGlobal?: boolean): string;
6
+ export declare function eventToOperation(event: ActivityEvent): SiteActivityLogData['operation'];
7
+ export declare function getActivityEvent(params: ActivityClassificationParams): ActivityEvent;
8
+ export declare function getCollectionActivityDetails(collection: CollectionConfig, operation: 'create' | 'update', doc: Record<string, unknown> | undefined, previousDoc?: Record<string, unknown>, req?: any): ActivityDetails;
9
+ export declare function getGlobalActivityDetails(globalConfig: GlobalConfig, doc: Record<string, unknown> | undefined, previousDoc?: Record<string, unknown>, req?: any): ActivityDetails;
@@ -1,88 +1,131 @@
1
+ import { ActivityEvent } from '../types/events.js';
1
2
  import { getCollectionLabel } from './getCollectionLabel.js';
2
- export function getCollectionActivityDetails(collection, operation, doc, previousDoc) {
3
- const label = getCollectionLabel(collection);
4
- const isCreate = operation === 'create' || !previousDoc;
5
- const currentStatus = doc && typeof doc === 'object' && '_status' in doc && typeof doc._status === 'string' ? doc._status : undefined;
6
- const prevStatus = previousDoc && typeof previousDoc === 'object' && '_status' in previousDoc && typeof previousDoc._status === 'string' ? previousDoc._status : undefined;
7
- if (currentStatus) {
8
- if (isCreate) {
9
- if (currentStatus === 'draft') {
10
- return {
11
- title: `${label} created as draft`,
12
- operation: 'create'
13
- };
14
- }
15
- if (currentStatus === 'published') {
16
- return {
17
- title: `${label} published`,
18
- operation: 'publish'
19
- };
20
- }
21
- } else {
22
- if (prevStatus === 'draft' && currentStatus === 'published') {
23
- return {
24
- title: `${label} published`,
25
- operation: 'publish'
26
- };
27
- }
28
- if (prevStatus === 'published' && currentStatus === 'draft') {
29
- return {
30
- title: `${label} unpublished`,
31
- operation: 'unpublish'
32
- };
33
- }
34
- if (currentStatus === 'draft') {
35
- return {
36
- title: `${label} draft updated`,
37
- operation: 'update'
38
- };
39
- }
40
- if (currentStatus === 'published') {
41
- return {
42
- title: `${label} modified`,
43
- operation: 'update'
44
- };
45
- }
46
- }
3
+ export function getActivityLabel(event, resourceLabel, isGlobal = false) {
4
+ const prefix = isGlobal ? `Global ${resourceLabel}` : resourceLabel;
5
+ switch(event){
6
+ case ActivityEvent.CREATED:
7
+ return `${prefix} Created`;
8
+ case ActivityEvent.UPDATED:
9
+ return `${prefix} Updated`;
10
+ case ActivityEvent.DELETED:
11
+ return `${prefix} Deleted`;
12
+ case ActivityEvent.PUBLISHED:
13
+ return `${prefix} Published`;
14
+ case ActivityEvent.UNPUBLISHED:
15
+ return `${prefix} Unpublished`;
16
+ case ActivityEvent.DRAFT_SAVED:
17
+ return resourceLabel.toLowerCase() === 'page' ? 'Changes Saved as Draft' : `${prefix} Changes Saved as Draft`;
18
+ case ActivityEvent.USER_LOGIN:
19
+ return 'User Logged In';
20
+ case ActivityEvent.USER_LOGOUT:
21
+ return 'User Logged Out';
22
+ case ActivityEvent.USER_LOGIN_FAILED:
23
+ return 'Failed Login';
24
+ case ActivityEvent.USER_SESSION_EXPIRED:
25
+ return 'Session Expired';
26
+ case ActivityEvent.RESTORED:
27
+ return `${prefix} Restored`;
28
+ case ActivityEvent.DUPLICATED:
29
+ return `${prefix} Duplicated`;
30
+ default:
31
+ return `${prefix} Updated`;
47
32
  }
48
- return {
49
- title: isCreate ? `${label} created` : `${label} modified`,
50
- operation: isCreate ? 'create' : 'update'
51
- };
52
33
  }
53
- export function getGlobalActivityDetails(globalConfig, doc, previousDoc) {
54
- const label = getCollectionLabel(globalConfig);
34
+ export function eventToOperation(event) {
35
+ switch(event){
36
+ case ActivityEvent.CREATED:
37
+ return 'create';
38
+ case ActivityEvent.UPDATED:
39
+ return 'update';
40
+ case ActivityEvent.DELETED:
41
+ return 'delete';
42
+ case ActivityEvent.PUBLISHED:
43
+ return 'publish';
44
+ case ActivityEvent.UNPUBLISHED:
45
+ return 'unpublish';
46
+ case ActivityEvent.DRAFT_SAVED:
47
+ return 'draft_saved';
48
+ case ActivityEvent.USER_LOGIN:
49
+ return 'login';
50
+ case ActivityEvent.USER_LOGOUT:
51
+ return 'logout';
52
+ default:
53
+ return 'update';
54
+ }
55
+ }
56
+ export function getActivityEvent(params) {
57
+ const { operation, previousDoc, doc, req, context } = params;
58
+ if (operation === 'login') {
59
+ return ActivityEvent.USER_LOGIN;
60
+ }
61
+ if (operation === 'logout') {
62
+ return ActivityEvent.USER_LOGOUT;
63
+ }
64
+ if (operation === 'delete') {
65
+ return ActivityEvent.DELETED;
66
+ }
67
+ // Explicit activity event override passed in request or context
68
+ const reqContext = req?.context || context;
69
+ if (reqContext?.activityEvent && typeof reqContext.activityEvent === 'string') {
70
+ const explicitEvent = reqContext.activityEvent;
71
+ if (Object.values(ActivityEvent).includes(explicitEvent)) {
72
+ return explicitEvent;
73
+ }
74
+ }
55
75
  const currentStatus = doc && typeof doc === 'object' && '_status' in doc && typeof doc._status === 'string' ? doc._status : undefined;
56
76
  const prevStatus = previousDoc && typeof previousDoc === 'object' && '_status' in previousDoc && typeof previousDoc._status === 'string' ? previousDoc._status : undefined;
77
+ const isCreate = operation === 'create' || !previousDoc && operation !== 'update';
57
78
  if (currentStatus) {
79
+ if (isCreate) {
80
+ // Creation of a document with draft or published status
81
+ return ActivityEvent.CREATED;
82
+ }
83
+ // Check transition states for existing document update
58
84
  if (prevStatus === 'draft' && currentStatus === 'published') {
59
- return {
60
- title: `Global ${label} published`,
61
- operation: 'publish'
62
- };
85
+ return ActivityEvent.PUBLISHED;
63
86
  }
64
87
  if (prevStatus === 'published' && currentStatus === 'draft') {
65
- return {
66
- title: `Global ${label} unpublished`,
67
- operation: 'unpublish'
68
- };
88
+ // Distinguish explicit unpublish vs saving draft of published page
89
+ const isExplicitUnpublish = Boolean(reqContext?.unpublish || reqContext?._payloadUnpublish || reqContext?.isUnpublishing || req?.url?.includes('/unpublish') || req?.route?.path?.includes('/unpublish'));
90
+ return isExplicitUnpublish ? ActivityEvent.UNPUBLISHED : ActivityEvent.DRAFT_SAVED;
69
91
  }
70
92
  if (currentStatus === 'draft') {
71
- return {
72
- title: `Global ${label} draft updated`,
73
- operation: 'update'
74
- };
93
+ return ActivityEvent.DRAFT_SAVED;
75
94
  }
76
95
  if (currentStatus === 'published') {
77
- return {
78
- title: `Global ${label} updated`,
79
- operation: 'update'
80
- };
96
+ return ActivityEvent.UPDATED;
81
97
  }
82
98
  }
99
+ return isCreate ? ActivityEvent.CREATED : ActivityEvent.UPDATED;
100
+ }
101
+ export function getCollectionActivityDetails(collection, operation, doc, previousDoc, req) {
102
+ const label = getCollectionLabel(collection);
103
+ const event = getActivityEvent({
104
+ operation,
105
+ doc,
106
+ previousDoc,
107
+ req,
108
+ collectionSlug: collection.slug
109
+ });
110
+ return {
111
+ event,
112
+ title: getActivityLabel(event, label, false),
113
+ operation: eventToOperation(event)
114
+ };
115
+ }
116
+ export function getGlobalActivityDetails(globalConfig, doc, previousDoc, req) {
117
+ const label = getCollectionLabel(globalConfig);
118
+ const event = getActivityEvent({
119
+ operation: 'update',
120
+ doc,
121
+ previousDoc,
122
+ req,
123
+ collectionSlug: globalConfig.slug
124
+ });
83
125
  return {
84
- title: `Global ${label} updated`,
85
- operation: 'update'
126
+ event,
127
+ title: getActivityLabel(event, label, true),
128
+ operation: eventToOperation(event)
86
129
  };
87
130
  }
88
131
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pluginUtils/getActivityDetails.ts"],"sourcesContent":["import type { CollectionConfig, GlobalConfig } from 'payload';\n\nimport { getCollectionLabel } from './getCollectionLabel.js';\nimport type { SiteActivityLogData } from '../collections/SiteActivityCollection.js';\n\nexport interface ActivityDetails {\n title: string;\n operation: SiteActivityLogData['operation'];\n}\n\nexport function getCollectionActivityDetails(\n collection: CollectionConfig,\n operation: 'create' | 'update',\n doc: Record<string, unknown> | undefined,\n previousDoc?: Record<string, unknown>,\n): ActivityDetails {\n const label = getCollectionLabel(collection);\n const isCreate = operation === 'create' || !previousDoc;\n\n const currentStatus = doc && typeof doc === 'object' && '_status' in doc && typeof doc._status === 'string'\n ? doc._status\n : undefined;\n const prevStatus = previousDoc && typeof previousDoc === 'object' && '_status' in previousDoc && typeof previousDoc._status === 'string'\n ? previousDoc._status\n : undefined;\n\n if (currentStatus) {\n if (isCreate) {\n if (currentStatus === 'draft') {\n return {\n title: `${label} created as draft`,\n operation: 'create',\n };\n }\n if (currentStatus === 'published') {\n return {\n title: `${label} published`,\n operation: 'publish',\n };\n }\n }\n else {\n if (prevStatus === 'draft' && currentStatus === 'published') {\n return {\n title: `${label} published`,\n operation: 'publish',\n };\n }\n if (prevStatus === 'published' && currentStatus === 'draft') {\n return {\n title: `${label} unpublished`,\n operation: 'unpublish',\n };\n }\n if (currentStatus === 'draft') {\n return {\n title: `${label} draft updated`,\n operation: 'update',\n };\n }\n if (currentStatus === 'published') {\n return {\n title: `${label} modified`,\n operation: 'update',\n };\n }\n }\n }\n\n return {\n title: isCreate ? `${label} created` : `${label} modified`,\n operation: isCreate ? 'create' : 'update',\n };\n}\n\nexport function getGlobalActivityDetails(\n globalConfig: GlobalConfig,\n doc: Record<string, unknown> | undefined,\n previousDoc?: Record<string, unknown>,\n): ActivityDetails {\n const label = getCollectionLabel(globalConfig);\n\n const currentStatus = doc && typeof doc === 'object' && '_status' in doc && typeof doc._status === 'string'\n ? doc._status\n : undefined;\n const prevStatus = previousDoc && typeof previousDoc === 'object' && '_status' in previousDoc && typeof previousDoc._status === 'string'\n ? previousDoc._status\n : undefined;\n\n if (currentStatus) {\n if (prevStatus === 'draft' && currentStatus === 'published') {\n return {\n title: `Global ${label} published`,\n operation: 'publish',\n };\n }\n if (prevStatus === 'published' && currentStatus === 'draft') {\n return {\n title: `Global ${label} unpublished`,\n operation: 'unpublish',\n };\n }\n if (currentStatus === 'draft') {\n return {\n title: `Global ${label} draft updated`,\n operation: 'update',\n };\n }\n if (currentStatus === 'published') {\n return {\n title: `Global ${label} updated`,\n operation: 'update',\n };\n }\n }\n\n return {\n title: `Global ${label} updated`,\n operation: 'update',\n };\n}\n"],"names":["getCollectionLabel","getCollectionActivityDetails","collection","operation","doc","previousDoc","label","isCreate","currentStatus","_status","undefined","prevStatus","title","getGlobalActivityDetails","globalConfig"],"mappings":"AAEA,SAASA,kBAAkB,QAAQ,0BAA0B;AAQ7D,OAAO,SAASC,6BACdC,UAA4B,EAC5BC,SAA8B,EAC9BC,GAAwC,EACxCC,WAAqC;IAErC,MAAMC,QAAQN,mBAAmBE;IACjC,MAAMK,WAAWJ,cAAc,YAAY,CAACE;IAE5C,MAAMG,gBAAgBJ,OAAO,OAAOA,QAAQ,YAAY,aAAaA,OAAO,OAAOA,IAAIK,OAAO,KAAK,WAC/FL,IAAIK,OAAO,GACXC;IACJ,MAAMC,aAAaN,eAAe,OAAOA,gBAAgB,YAAY,aAAaA,eAAe,OAAOA,YAAYI,OAAO,KAAK,WAC5HJ,YAAYI,OAAO,GACnBC;IAEJ,IAAIF,eAAe;QACjB,IAAID,UAAU;YACZ,IAAIC,kBAAkB,SAAS;gBAC7B,OAAO;oBACLI,OAAO,GAAGN,MAAM,iBAAiB,CAAC;oBAClCH,WAAW;gBACb;YACF;YACA,IAAIK,kBAAkB,aAAa;gBACjC,OAAO;oBACLI,OAAO,GAAGN,MAAM,UAAU,CAAC;oBAC3BH,WAAW;gBACb;YACF;QACF,OACK;YACH,IAAIQ,eAAe,WAAWH,kBAAkB,aAAa;gBAC3D,OAAO;oBACLI,OAAO,GAAGN,MAAM,UAAU,CAAC;oBAC3BH,WAAW;gBACb;YACF;YACA,IAAIQ,eAAe,eAAeH,kBAAkB,SAAS;gBAC3D,OAAO;oBACLI,OAAO,GAAGN,MAAM,YAAY,CAAC;oBAC7BH,WAAW;gBACb;YACF;YACA,IAAIK,kBAAkB,SAAS;gBAC7B,OAAO;oBACLI,OAAO,GAAGN,MAAM,cAAc,CAAC;oBAC/BH,WAAW;gBACb;YACF;YACA,IAAIK,kBAAkB,aAAa;gBACjC,OAAO;oBACLI,OAAO,GAAGN,MAAM,SAAS,CAAC;oBAC1BH,WAAW;gBACb;YACF;QACF;IACF;IAEA,OAAO;QACLS,OAAOL,WAAW,GAAGD,MAAM,QAAQ,CAAC,GAAG,GAAGA,MAAM,SAAS,CAAC;QAC1DH,WAAWI,WAAW,WAAW;IACnC;AACF;AAEA,OAAO,SAASM,yBACdC,YAA0B,EAC1BV,GAAwC,EACxCC,WAAqC;IAErC,MAAMC,QAAQN,mBAAmBc;IAEjC,MAAMN,gBAAgBJ,OAAO,OAAOA,QAAQ,YAAY,aAAaA,OAAO,OAAOA,IAAIK,OAAO,KAAK,WAC/FL,IAAIK,OAAO,GACXC;IACJ,MAAMC,aAAaN,eAAe,OAAOA,gBAAgB,YAAY,aAAaA,eAAe,OAAOA,YAAYI,OAAO,KAAK,WAC5HJ,YAAYI,OAAO,GACnBC;IAEJ,IAAIF,eAAe;QACjB,IAAIG,eAAe,WAAWH,kBAAkB,aAAa;YAC3D,OAAO;gBACLI,OAAO,CAAC,OAAO,EAAEN,MAAM,UAAU,CAAC;gBAClCH,WAAW;YACb;QACF;QACA,IAAIQ,eAAe,eAAeH,kBAAkB,SAAS;YAC3D,OAAO;gBACLI,OAAO,CAAC,OAAO,EAAEN,MAAM,YAAY,CAAC;gBACpCH,WAAW;YACb;QACF;QACA,IAAIK,kBAAkB,SAAS;YAC7B,OAAO;gBACLI,OAAO,CAAC,OAAO,EAAEN,MAAM,cAAc,CAAC;gBACtCH,WAAW;YACb;QACF;QACA,IAAIK,kBAAkB,aAAa;YACjC,OAAO;gBACLI,OAAO,CAAC,OAAO,EAAEN,MAAM,QAAQ,CAAC;gBAChCH,WAAW;YACb;QACF;IACF;IAEA,OAAO;QACLS,OAAO,CAAC,OAAO,EAAEN,MAAM,QAAQ,CAAC;QAChCH,WAAW;IACb;AACF"}
1
+ {"version":3,"sources":["../../src/pluginUtils/getActivityDetails.ts"],"sourcesContent":["import type { CollectionConfig, GlobalConfig } from 'payload';\n\nimport { ActivityEvent } from '../types/events.js';\nimport { getCollectionLabel } from './getCollectionLabel.js';\nimport type { SiteActivityLogData } from '../collections/SiteActivityCollection.js';\nimport type { ActivityClassificationParams, ActivityDetails } from '../types/events.js';\n\nexport function getActivityLabel(\n event: ActivityEvent,\n resourceLabel: string,\n isGlobal = false,\n): string {\n const prefix = isGlobal ? `Global ${resourceLabel}` : resourceLabel;\n\n switch (event) {\n case ActivityEvent.CREATED:\n return `${prefix} Created`;\n case ActivityEvent.UPDATED:\n return `${prefix} Updated`;\n case ActivityEvent.DELETED:\n return `${prefix} Deleted`;\n case ActivityEvent.PUBLISHED:\n return `${prefix} Published`;\n case ActivityEvent.UNPUBLISHED:\n return `${prefix} Unpublished`;\n case ActivityEvent.DRAFT_SAVED:\n return resourceLabel.toLowerCase() === 'page'\n ? 'Changes Saved as Draft'\n : `${prefix} Changes Saved as Draft`;\n case ActivityEvent.USER_LOGIN:\n return 'User Logged In';\n case ActivityEvent.USER_LOGOUT:\n return 'User Logged Out';\n case ActivityEvent.USER_LOGIN_FAILED:\n return 'Failed Login';\n case ActivityEvent.USER_SESSION_EXPIRED:\n return 'Session Expired';\n case ActivityEvent.RESTORED:\n return `${prefix} Restored`;\n case ActivityEvent.DUPLICATED:\n return `${prefix} Duplicated`;\n default:\n return `${prefix} Updated`;\n }\n}\n\nexport function eventToOperation(event: ActivityEvent): SiteActivityLogData['operation'] {\n switch (event) {\n case ActivityEvent.CREATED:\n return 'create';\n case ActivityEvent.UPDATED:\n return 'update';\n case ActivityEvent.DELETED:\n return 'delete';\n case ActivityEvent.PUBLISHED:\n return 'publish';\n case ActivityEvent.UNPUBLISHED:\n return 'unpublish';\n case ActivityEvent.DRAFT_SAVED:\n return 'draft_saved';\n case ActivityEvent.USER_LOGIN:\n return 'login';\n case ActivityEvent.USER_LOGOUT:\n return 'logout';\n default:\n return 'update';\n }\n}\n\nexport function getActivityEvent(params: ActivityClassificationParams): ActivityEvent {\n const { operation, previousDoc, doc, req, context } = params;\n\n if (operation === 'login') {\n return ActivityEvent.USER_LOGIN;\n }\n if (operation === 'logout') {\n return ActivityEvent.USER_LOGOUT;\n }\n if (operation === 'delete') {\n return ActivityEvent.DELETED;\n }\n\n // Explicit activity event override passed in request or context\n const reqContext = req?.context || context;\n if (reqContext?.activityEvent && typeof reqContext.activityEvent === 'string') {\n const explicitEvent = reqContext.activityEvent as ActivityEvent;\n if (Object.values(ActivityEvent).includes(explicitEvent)) {\n return explicitEvent;\n }\n }\n\n const currentStatus = doc && typeof doc === 'object' && '_status' in doc && typeof doc._status === 'string'\n ? doc._status\n : undefined;\n const prevStatus = previousDoc && typeof previousDoc === 'object' && '_status' in previousDoc && typeof previousDoc._status === 'string'\n ? previousDoc._status\n : undefined;\n\n const isCreate = operation === 'create' || (!previousDoc && operation !== 'update');\n\n if (currentStatus) {\n if (isCreate) {\n // Creation of a document with draft or published status\n return ActivityEvent.CREATED;\n }\n\n // Check transition states for existing document update\n if (prevStatus === 'draft' && currentStatus === 'published') {\n return ActivityEvent.PUBLISHED;\n }\n\n if (prevStatus === 'published' && currentStatus === 'draft') {\n // Distinguish explicit unpublish vs saving draft of published page\n const isExplicitUnpublish = Boolean(\n reqContext?.unpublish\n || reqContext?._payloadUnpublish\n || reqContext?.isUnpublishing\n || req?.url?.includes('/unpublish')\n || req?.route?.path?.includes('/unpublish'),\n );\n\n return isExplicitUnpublish ? ActivityEvent.UNPUBLISHED : ActivityEvent.DRAFT_SAVED;\n }\n\n if (currentStatus === 'draft') {\n return ActivityEvent.DRAFT_SAVED;\n }\n\n if (currentStatus === 'published') {\n return ActivityEvent.UPDATED;\n }\n }\n\n return isCreate ? ActivityEvent.CREATED : ActivityEvent.UPDATED;\n}\n\nexport function getCollectionActivityDetails(\n collection: CollectionConfig,\n operation: 'create' | 'update',\n doc: Record<string, unknown> | undefined,\n previousDoc?: Record<string, unknown>,\n req?: any,\n): ActivityDetails {\n const label = getCollectionLabel(collection);\n const event = getActivityEvent({\n operation,\n doc,\n previousDoc,\n req,\n collectionSlug: collection.slug,\n });\n\n return {\n event,\n title: getActivityLabel(event, label, false),\n operation: eventToOperation(event),\n };\n}\n\nexport function getGlobalActivityDetails(\n globalConfig: GlobalConfig,\n doc: Record<string, unknown> | undefined,\n previousDoc?: Record<string, unknown>,\n req?: any,\n): ActivityDetails {\n const label = getCollectionLabel(globalConfig);\n const event = getActivityEvent({\n operation: 'update',\n doc,\n previousDoc,\n req,\n collectionSlug: globalConfig.slug,\n });\n\n return {\n event,\n title: getActivityLabel(event, label, true),\n operation: eventToOperation(event),\n };\n}\n"],"names":["ActivityEvent","getCollectionLabel","getActivityLabel","event","resourceLabel","isGlobal","prefix","CREATED","UPDATED","DELETED","PUBLISHED","UNPUBLISHED","DRAFT_SAVED","toLowerCase","USER_LOGIN","USER_LOGOUT","USER_LOGIN_FAILED","USER_SESSION_EXPIRED","RESTORED","DUPLICATED","eventToOperation","getActivityEvent","params","operation","previousDoc","doc","req","context","reqContext","activityEvent","explicitEvent","Object","values","includes","currentStatus","_status","undefined","prevStatus","isCreate","isExplicitUnpublish","Boolean","unpublish","_payloadUnpublish","isUnpublishing","url","route","path","getCollectionActivityDetails","collection","label","collectionSlug","slug","title","getGlobalActivityDetails","globalConfig"],"mappings":"AAEA,SAASA,aAAa,QAAQ,qBAAqB;AACnD,SAASC,kBAAkB,QAAQ,0BAA0B;AAI7D,OAAO,SAASC,iBACdC,KAAoB,EACpBC,aAAqB,EACrBC,WAAW,KAAK;IAEhB,MAAMC,SAASD,WAAW,CAAC,OAAO,EAAED,eAAe,GAAGA;IAEtD,OAAQD;QACN,KAAKH,cAAcO,OAAO;YACxB,OAAO,GAAGD,OAAO,QAAQ,CAAC;QAC5B,KAAKN,cAAcQ,OAAO;YACxB,OAAO,GAAGF,OAAO,QAAQ,CAAC;QAC5B,KAAKN,cAAcS,OAAO;YACxB,OAAO,GAAGH,OAAO,QAAQ,CAAC;QAC5B,KAAKN,cAAcU,SAAS;YAC1B,OAAO,GAAGJ,OAAO,UAAU,CAAC;QAC9B,KAAKN,cAAcW,WAAW;YAC5B,OAAO,GAAGL,OAAO,YAAY,CAAC;QAChC,KAAKN,cAAcY,WAAW;YAC5B,OAAOR,cAAcS,WAAW,OAAO,SACnC,2BACA,GAAGP,OAAO,uBAAuB,CAAC;QACxC,KAAKN,cAAcc,UAAU;YAC3B,OAAO;QACT,KAAKd,cAAce,WAAW;YAC5B,OAAO;QACT,KAAKf,cAAcgB,iBAAiB;YAClC,OAAO;QACT,KAAKhB,cAAciB,oBAAoB;YACrC,OAAO;QACT,KAAKjB,cAAckB,QAAQ;YACzB,OAAO,GAAGZ,OAAO,SAAS,CAAC;QAC7B,KAAKN,cAAcmB,UAAU;YAC3B,OAAO,GAAGb,OAAO,WAAW,CAAC;QAC/B;YACE,OAAO,GAAGA,OAAO,QAAQ,CAAC;IAC9B;AACF;AAEA,OAAO,SAASc,iBAAiBjB,KAAoB;IACnD,OAAQA;QACN,KAAKH,cAAcO,OAAO;YACxB,OAAO;QACT,KAAKP,cAAcQ,OAAO;YACxB,OAAO;QACT,KAAKR,cAAcS,OAAO;YACxB,OAAO;QACT,KAAKT,cAAcU,SAAS;YAC1B,OAAO;QACT,KAAKV,cAAcW,WAAW;YAC5B,OAAO;QACT,KAAKX,cAAcY,WAAW;YAC5B,OAAO;QACT,KAAKZ,cAAcc,UAAU;YAC3B,OAAO;QACT,KAAKd,cAAce,WAAW;YAC5B,OAAO;QACT;YACE,OAAO;IACX;AACF;AAEA,OAAO,SAASM,iBAAiBC,MAAoC;IACnE,MAAM,EAAEC,SAAS,EAAEC,WAAW,EAAEC,GAAG,EAAEC,GAAG,EAAEC,OAAO,EAAE,GAAGL;IAEtD,IAAIC,cAAc,SAAS;QACzB,OAAOvB,cAAcc,UAAU;IACjC;IACA,IAAIS,cAAc,UAAU;QAC1B,OAAOvB,cAAce,WAAW;IAClC;IACA,IAAIQ,cAAc,UAAU;QAC1B,OAAOvB,cAAcS,OAAO;IAC9B;IAEA,gEAAgE;IAChE,MAAMmB,aAAaF,KAAKC,WAAWA;IACnC,IAAIC,YAAYC,iBAAiB,OAAOD,WAAWC,aAAa,KAAK,UAAU;QAC7E,MAAMC,gBAAgBF,WAAWC,aAAa;QAC9C,IAAIE,OAAOC,MAAM,CAAChC,eAAeiC,QAAQ,CAACH,gBAAgB;YACxD,OAAOA;QACT;IACF;IAEA,MAAMI,gBAAgBT,OAAO,OAAOA,QAAQ,YAAY,aAAaA,OAAO,OAAOA,IAAIU,OAAO,KAAK,WAC/FV,IAAIU,OAAO,GACXC;IACJ,MAAMC,aAAab,eAAe,OAAOA,gBAAgB,YAAY,aAAaA,eAAe,OAAOA,YAAYW,OAAO,KAAK,WAC5HX,YAAYW,OAAO,GACnBC;IAEJ,MAAME,WAAWf,cAAc,YAAa,CAACC,eAAeD,cAAc;IAE1E,IAAIW,eAAe;QACjB,IAAII,UAAU;YACZ,wDAAwD;YACxD,OAAOtC,cAAcO,OAAO;QAC9B;QAEA,uDAAuD;QACvD,IAAI8B,eAAe,WAAWH,kBAAkB,aAAa;YAC3D,OAAOlC,cAAcU,SAAS;QAChC;QAEA,IAAI2B,eAAe,eAAeH,kBAAkB,SAAS;YAC3D,mEAAmE;YACnE,MAAMK,sBAAsBC,QAC1BZ,YAAYa,aACTb,YAAYc,qBACZd,YAAYe,kBACZjB,KAAKkB,KAAKX,SAAS,iBACnBP,KAAKmB,OAAOC,MAAMb,SAAS;YAGhC,OAAOM,sBAAsBvC,cAAcW,WAAW,GAAGX,cAAcY,WAAW;QACpF;QAEA,IAAIsB,kBAAkB,SAAS;YAC7B,OAAOlC,cAAcY,WAAW;QAClC;QAEA,IAAIsB,kBAAkB,aAAa;YACjC,OAAOlC,cAAcQ,OAAO;QAC9B;IACF;IAEA,OAAO8B,WAAWtC,cAAcO,OAAO,GAAGP,cAAcQ,OAAO;AACjE;AAEA,OAAO,SAASuC,6BACdC,UAA4B,EAC5BzB,SAA8B,EAC9BE,GAAwC,EACxCD,WAAqC,EACrCE,GAAS;IAET,MAAMuB,QAAQhD,mBAAmB+C;IACjC,MAAM7C,QAAQkB,iBAAiB;QAC7BE;QACAE;QACAD;QACAE;QACAwB,gBAAgBF,WAAWG,IAAI;IACjC;IAEA,OAAO;QACLhD;QACAiD,OAAOlD,iBAAiBC,OAAO8C,OAAO;QACtC1B,WAAWH,iBAAiBjB;IAC9B;AACF;AAEA,OAAO,SAASkD,yBACdC,YAA0B,EAC1B7B,GAAwC,EACxCD,WAAqC,EACrCE,GAAS;IAET,MAAMuB,QAAQhD,mBAAmBqD;IACjC,MAAMnD,QAAQkB,iBAAiB;QAC7BE,WAAW;QACXE;QACAD;QACAE;QACAwB,gBAAgBI,aAAaH,IAAI;IACnC;IAEA,OAAO;QACLhD;QACAiD,OAAOlD,iBAAiBC,OAAO8C,OAAO;QACtC1B,WAAWH,iBAAiBjB;IAC9B;AACF"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ export declare enum ActivityEvent {
2
+ USER_LOGIN = "USER_LOGIN",
3
+ USER_LOGOUT = "USER_LOGOUT",
4
+ USER_LOGIN_FAILED = "USER_LOGIN_FAILED",
5
+ USER_SESSION_EXPIRED = "USER_SESSION_EXPIRED",
6
+ CREATED = "CREATED",
7
+ UPDATED = "UPDATED",
8
+ DELETED = "DELETED",
9
+ DRAFT_SAVED = "DRAFT_SAVED",
10
+ PUBLISHED = "PUBLISHED",
11
+ UNPUBLISHED = "UNPUBLISHED",
12
+ RESTORED = "RESTORED",
13
+ DUPLICATED = "DUPLICATED"
14
+ }
15
+ export interface ActivityClassificationParams {
16
+ operation: 'create' | 'update' | 'delete' | 'login' | 'logout';
17
+ collectionSlug?: string;
18
+ previousDoc?: Record<string, unknown>;
19
+ doc?: Record<string, unknown>;
20
+ req?: any;
21
+ context?: Record<string, unknown>;
22
+ }
23
+ export interface ActivityDetails {
24
+ event: ActivityEvent;
25
+ title: string;
26
+ operation: 'create' | 'update' | 'delete' | 'login' | 'logout' | 'publish' | 'unpublish' | 'draft_saved';
27
+ }
@@ -0,0 +1,17 @@
1
+ export var ActivityEvent = /*#__PURE__*/ function(ActivityEvent) {
2
+ ActivityEvent["USER_LOGIN"] = "USER_LOGIN";
3
+ ActivityEvent["USER_LOGOUT"] = "USER_LOGOUT";
4
+ ActivityEvent["USER_LOGIN_FAILED"] = "USER_LOGIN_FAILED";
5
+ ActivityEvent["USER_SESSION_EXPIRED"] = "USER_SESSION_EXPIRED";
6
+ ActivityEvent["CREATED"] = "CREATED";
7
+ ActivityEvent["UPDATED"] = "UPDATED";
8
+ ActivityEvent["DELETED"] = "DELETED";
9
+ ActivityEvent["DRAFT_SAVED"] = "DRAFT_SAVED";
10
+ ActivityEvent["PUBLISHED"] = "PUBLISHED";
11
+ ActivityEvent["UNPUBLISHED"] = "UNPUBLISHED";
12
+ ActivityEvent["RESTORED"] = "RESTORED";
13
+ ActivityEvent["DUPLICATED"] = "DUPLICATED";
14
+ return ActivityEvent;
15
+ }({});
16
+
17
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types/events.ts"],"sourcesContent":["export enum ActivityEvent {\n USER_LOGIN = 'USER_LOGIN',\n USER_LOGOUT = 'USER_LOGOUT',\n USER_LOGIN_FAILED = 'USER_LOGIN_FAILED',\n USER_SESSION_EXPIRED = 'USER_SESSION_EXPIRED',\n\n CREATED = 'CREATED',\n UPDATED = 'UPDATED',\n DELETED = 'DELETED',\n\n DRAFT_SAVED = 'DRAFT_SAVED',\n PUBLISHED = 'PUBLISHED',\n UNPUBLISHED = 'UNPUBLISHED',\n\n RESTORED = 'RESTORED',\n DUPLICATED = 'DUPLICATED',\n}\n\nexport interface ActivityClassificationParams {\n operation: 'create' | 'update' | 'delete' | 'login' | 'logout';\n collectionSlug?: string;\n previousDoc?: Record<string, unknown>;\n doc?: Record<string, unknown>;\n req?: any;\n context?: Record<string, unknown>;\n}\n\nexport interface ActivityDetails {\n event: ActivityEvent;\n title: string;\n operation: 'create' | 'update' | 'delete' | 'login' | 'logout' | 'publish' | 'unpublish' | 'draft_saved';\n}\n"],"names":["ActivityEvent"],"mappings":"AAAA,OAAO,IAAA,AAAKA,uCAAAA;;;;;;;;;;;;;WAAAA;MAgBX"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@brandlift/payload-loggs",
3
3
  "type": "module",
4
- "version": "1.2.0",
4
+ "version": "1.3.0",
5
5
  "packageManager": "pnpm@10.2.0",
6
6
  "description": "Zero-config activity feed, audit logging, and security tracking plugin for Payload CMS",
7
7
  "author": {