@dappermountain/payload-plugin-achievements 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +319 -0
- package/dist/access/helpers/index.d.ts +9 -0
- package/dist/access/helpers/index.d.ts.map +1 -0
- package/dist/access/helpers/index.js +25 -0
- package/dist/access/index.d.ts +3 -0
- package/dist/access/index.d.ts.map +1 -0
- package/dist/access/index.js +2 -0
- package/dist/access/roles/index.d.ts +15 -0
- package/dist/access/roles/index.d.ts.map +1 -0
- package/dist/access/roles/index.js +55 -0
- package/dist/admin/ActorField.d.ts +9 -0
- package/dist/admin/ActorField.d.ts.map +1 -0
- package/dist/admin/ActorField.js +19 -0
- package/dist/admin/MetricChangeField.d.ts +9 -0
- package/dist/admin/MetricChangeField.d.ts.map +1 -0
- package/dist/admin/MetricChangeField.js +21 -0
- package/dist/admin/MetricField.d.ts +9 -0
- package/dist/admin/MetricField.d.ts.map +1 -0
- package/dist/admin/MetricField.js +23 -0
- package/dist/admin/useEventTypeFlags.d.ts +7 -0
- package/dist/admin/useEventTypeFlags.d.ts.map +1 -0
- package/dist/admin/useEventTypeFlags.js +68 -0
- package/dist/catalog.d.ts +21 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +9 -0
- package/dist/collections/AchievementRequests/access/index.d.ts +3 -0
- package/dist/collections/AchievementRequests/access/index.d.ts.map +1 -0
- package/dist/collections/AchievementRequests/access/index.js +8 -0
- package/dist/collections/AchievementRequests/hooks/index.d.ts +3 -0
- package/dist/collections/AchievementRequests/hooks/index.d.ts.map +1 -0
- package/dist/collections/AchievementRequests/hooks/index.js +5 -0
- package/dist/collections/AchievementRequests/hooks/prepareAchievementRequest.d.ts +12 -0
- package/dist/collections/AchievementRequests/hooks/prepareAchievementRequest.d.ts.map +1 -0
- package/dist/collections/AchievementRequests/hooks/prepareAchievementRequest.js +105 -0
- package/dist/collections/AchievementRequests/index.d.ts +3 -0
- package/dist/collections/AchievementRequests/index.d.ts.map +1 -0
- package/dist/collections/AchievementRequests/index.js +39 -0
- package/dist/collections/Achievements/access/index.d.ts +3 -0
- package/dist/collections/Achievements/access/index.d.ts.map +1 -0
- package/dist/collections/Achievements/access/index.js +2 -0
- package/dist/collections/Achievements/hooks/index.d.ts +3 -0
- package/dist/collections/Achievements/hooks/index.d.ts.map +1 -0
- package/dist/collections/Achievements/hooks/index.js +4 -0
- package/dist/collections/Achievements/hooks/validateEligibilityRules.d.ts +3 -0
- package/dist/collections/Achievements/hooks/validateEligibilityRules.d.ts.map +1 -0
- package/dist/collections/Achievements/hooks/validateEligibilityRules.js +8 -0
- package/dist/collections/Achievements/index.d.ts +3 -0
- package/dist/collections/Achievements/index.d.ts.map +1 -0
- package/dist/collections/Achievements/index.js +62 -0
- package/dist/collections/EventTypes/access/index.d.ts +12 -0
- package/dist/collections/EventTypes/access/index.d.ts.map +1 -0
- package/dist/collections/EventTypes/access/index.js +2 -0
- package/dist/collections/EventTypes/hooks/index.d.ts +3 -0
- package/dist/collections/EventTypes/hooks/index.d.ts.map +1 -0
- package/dist/collections/EventTypes/hooks/index.js +6 -0
- package/dist/collections/EventTypes/index.d.ts +3 -0
- package/dist/collections/EventTypes/index.d.ts.map +1 -0
- package/dist/collections/EventTypes/index.js +67 -0
- package/dist/collections/Grants/access/index.d.ts +3 -0
- package/dist/collections/Grants/access/index.d.ts.map +1 -0
- package/dist/collections/Grants/access/index.js +8 -0
- package/dist/collections/Grants/hooks/ensureUniqueGrant.d.ts +4 -0
- package/dist/collections/Grants/hooks/ensureUniqueGrant.d.ts.map +1 -0
- package/dist/collections/Grants/hooks/ensureUniqueGrant.js +34 -0
- package/dist/collections/Grants/hooks/index.d.ts +3 -0
- package/dist/collections/Grants/hooks/index.d.ts.map +1 -0
- package/dist/collections/Grants/hooks/index.js +7 -0
- package/dist/collections/Grants/hooks/setGrantTitle.d.ts +4 -0
- package/dist/collections/Grants/hooks/setGrantTitle.d.ts.map +1 -0
- package/dist/collections/Grants/hooks/setGrantTitle.js +47 -0
- package/dist/collections/Grants/index.d.ts +3 -0
- package/dist/collections/Grants/index.d.ts.map +1 -0
- package/dist/collections/Grants/index.js +62 -0
- package/dist/collections/Logs/access/index.d.ts +3 -0
- package/dist/collections/Logs/access/index.d.ts.map +1 -0
- package/dist/collections/Logs/access/index.js +8 -0
- package/dist/collections/Logs/fields/validators.d.ts +5 -0
- package/dist/collections/Logs/fields/validators.d.ts.map +1 -0
- package/dist/collections/Logs/fields/validators.js +44 -0
- package/dist/collections/Logs/hooks/ensureTypeRequirements.d.ts +3 -0
- package/dist/collections/Logs/hooks/ensureTypeRequirements.d.ts.map +1 -0
- package/dist/collections/Logs/hooks/ensureTypeRequirements.js +35 -0
- package/dist/collections/Logs/hooks/index.d.ts +3 -0
- package/dist/collections/Logs/hooks/index.d.ts.map +1 -0
- package/dist/collections/Logs/hooks/index.js +4 -0
- package/dist/collections/Logs/index.d.ts +4 -0
- package/dist/collections/Logs/index.d.ts.map +1 -0
- package/dist/collections/Logs/index.js +113 -0
- package/dist/collections/Metrics/access/index.d.ts +12 -0
- package/dist/collections/Metrics/access/index.d.ts.map +1 -0
- package/dist/collections/Metrics/access/index.js +2 -0
- package/dist/collections/Metrics/hooks/index.d.ts +3 -0
- package/dist/collections/Metrics/hooks/index.d.ts.map +1 -0
- package/dist/collections/Metrics/hooks/index.js +6 -0
- package/dist/collections/Metrics/index.d.ts +3 -0
- package/dist/collections/Metrics/index.d.ts.map +1 -0
- package/dist/collections/Metrics/index.js +35 -0
- package/dist/collections/Tiers/access/index.d.ts +3 -0
- package/dist/collections/Tiers/access/index.d.ts.map +1 -0
- package/dist/collections/Tiers/access/index.js +2 -0
- package/dist/collections/Tiers/hooks/index.d.ts +3 -0
- package/dist/collections/Tiers/hooks/index.d.ts.map +1 -0
- package/dist/collections/Tiers/hooks/index.js +4 -0
- package/dist/collections/Tiers/hooks/validateUnlockRules.d.ts +3 -0
- package/dist/collections/Tiers/hooks/validateUnlockRules.d.ts.map +1 -0
- package/dist/collections/Tiers/hooks/validateUnlockRules.js +7 -0
- package/dist/collections/Tiers/index.d.ts +3 -0
- package/dist/collections/Tiers/index.d.ts.map +1 -0
- package/dist/collections/Tiers/index.js +81 -0
- package/dist/collections/access/definitions.d.ts +5 -0
- package/dist/collections/access/definitions.d.ts.map +1 -0
- package/dist/collections/access/definitions.js +11 -0
- package/dist/collections/applyOverrides.d.ts +9 -0
- package/dist/collections/applyOverrides.d.ts.map +1 -0
- package/dist/collections/applyOverrides.js +34 -0
- package/dist/collections/fields/catalogFilter.d.ts +8 -0
- package/dist/collections/fields/catalogFilter.d.ts.map +1 -0
- package/dist/collections/fields/catalogFilter.js +10 -0
- package/dist/collections/fields/index.d.ts +6 -0
- package/dist/collections/fields/index.d.ts.map +1 -0
- package/dist/collections/fields/index.js +5 -0
- package/dist/collections/fields/localizedText.d.ts +10 -0
- package/dist/collections/fields/localizedText.d.ts.map +1 -0
- package/dist/collections/fields/localizedText.js +20 -0
- package/dist/collections/fields/ruleFields.d.ts +8 -0
- package/dist/collections/fields/ruleFields.d.ts.map +1 -0
- package/dist/collections/fields/ruleFields.js +123 -0
- package/dist/collections/fields/scopeField.d.ts +7 -0
- package/dist/collections/fields/scopeField.d.ts.map +1 -0
- package/dist/collections/fields/scopeField.js +22 -0
- package/dist/collections/fields/userField.d.ts +4 -0
- package/dist/collections/fields/userField.d.ts.map +1 -0
- package/dist/collections/fields/userField.js +12 -0
- package/dist/collections/fields/usersAchievementsGroup.d.ts +8 -0
- package/dist/collections/fields/usersAchievementsGroup.d.ts.map +1 -0
- package/dist/collections/fields/usersAchievementsGroup.js +36 -0
- package/dist/collections/helpers.d.ts +16 -0
- package/dist/collections/helpers.d.ts.map +1 -0
- package/dist/collections/helpers.js +31 -0
- package/dist/collections/hooks/eachRuleLeaf.d.ts +3 -0
- package/dist/collections/hooks/eachRuleLeaf.d.ts.map +1 -0
- package/dist/collections/hooks/eachRuleLeaf.js +20 -0
- package/dist/collections/hooks/index.d.ts +4 -0
- package/dist/collections/hooks/index.d.ts.map +1 -0
- package/dist/collections/hooks/index.js +3 -0
- package/dist/collections/hooks/lockSystemCatalogFields.d.ts +7 -0
- package/dist/collections/hooks/lockSystemCatalogFields.d.ts.map +1 -0
- package/dist/collections/hooks/lockSystemCatalogFields.js +15 -0
- package/dist/collections/hooks/preventCatalogDelete.d.ts +5 -0
- package/dist/collections/hooks/preventCatalogDelete.d.ts.map +1 -0
- package/dist/collections/hooks/preventCatalogDelete.js +89 -0
- package/dist/collections/index.d.ts +4 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/collections/index.js +23 -0
- package/dist/collections/slugs.d.ts +22 -0
- package/dist/collections/slugs.d.ts.map +1 -0
- package/dist/collections/slugs.js +51 -0
- package/dist/defaults.d.ts +21 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +31 -0
- package/dist/enabled.d.ts +4 -0
- package/dist/enabled.d.ts.map +1 -0
- package/dist/enabled.js +9 -0
- package/dist/endpoints/index.d.ts +4 -0
- package/dist/endpoints/index.d.ts.map +1 -0
- package/dist/endpoints/index.js +6 -0
- package/dist/endpoints/me.d.ts +7 -0
- package/dist/endpoints/me.d.ts.map +1 -0
- package/dist/endpoints/me.js +50 -0
- package/dist/exports/client.d.ts +4 -0
- package/dist/exports/client.d.ts.map +1 -0
- package/dist/exports/client.js +3 -0
- package/dist/extensions/registry.d.ts +3 -0
- package/dist/extensions/registry.d.ts.map +1 -0
- package/dist/extensions/registry.js +12 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/options-store.d.ts +7 -0
- package/dist/options-store.d.ts.map +1 -0
- package/dist/options-store.js +15 -0
- package/dist/plugin.d.ts +8 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +31 -0
- package/dist/seed/index.d.ts +63 -0
- package/dist/seed/index.d.ts.map +1 -0
- package/dist/seed/index.js +375 -0
- package/dist/services/achievement/buildCatalogProgressGroups.d.ts +37 -0
- package/dist/services/achievement/buildCatalogProgressGroups.d.ts.map +1 -0
- package/dist/services/achievement/buildCatalogProgressGroups.js +70 -0
- package/dist/services/achievement/builtInRules.d.ts +3 -0
- package/dist/services/achievement/builtInRules.d.ts.map +1 -0
- package/dist/services/achievement/builtInRules.js +280 -0
- package/dist/services/achievement/evaluateRules.d.ts +48 -0
- package/dist/services/achievement/evaluateRules.d.ts.map +1 -0
- package/dist/services/achievement/evaluateRules.js +206 -0
- package/dist/services/achievement/eventTypeRequiresActor.d.ts +24 -0
- package/dist/services/achievement/eventTypeRequiresActor.d.ts.map +1 -0
- package/dist/services/achievement/eventTypeRequiresActor.js +46 -0
- package/dist/services/achievement/getUserProgress.d.ts +53 -0
- package/dist/services/achievement/getUserProgress.d.ts.map +1 -0
- package/dist/services/achievement/getUserProgress.js +163 -0
- package/dist/services/achievement/index.d.ts +14 -0
- package/dist/services/achievement/index.d.ts.map +1 -0
- package/dist/services/achievement/index.js +9 -0
- package/dist/services/achievement/recordEvent.d.ts +41 -0
- package/dist/services/achievement/recordEvent.d.ts.map +1 -0
- package/dist/services/achievement/recordEvent.js +126 -0
- package/dist/services/achievement/relationId.d.ts +3 -0
- package/dist/services/achievement/relationId.d.ts.map +1 -0
- package/dist/services/achievement/relationId.js +15 -0
- package/dist/services/achievement/resolveCatalog.d.ts +14 -0
- package/dist/services/achievement/resolveCatalog.d.ts.map +1 -0
- package/dist/services/achievement/resolveCatalog.js +34 -0
- package/dist/services/achievement/resolveCurrentTier.d.ts +21 -0
- package/dist/services/achievement/resolveCurrentTier.d.ts.map +1 -0
- package/dist/services/achievement/resolveCurrentTier.js +51 -0
- package/dist/services/achievement/resolveTierProgress.d.ts +35 -0
- package/dist/services/achievement/resolveTierProgress.d.ts.map +1 -0
- package/dist/services/achievement/resolveTierProgress.js +99 -0
- package/dist/services/achievement/reviewAchievementRequest.d.ts +11 -0
- package/dist/services/achievement/reviewAchievementRequest.d.ts.map +1 -0
- package/dist/services/achievement/reviewAchievementRequest.js +37 -0
- package/dist/services/achievement/submitAchievementRequest.d.ts +21 -0
- package/dist/services/achievement/submitAchievementRequest.d.ts.map +1 -0
- package/dist/services/achievement/submitAchievementRequest.js +126 -0
- package/dist/services/achievement/validateRules.d.ts +11 -0
- package/dist/services/achievement/validateRules.d.ts.map +1 -0
- package/dist/services/achievement/validateRules.js +74 -0
- package/dist/services/achievement/where.d.ts +9 -0
- package/dist/services/achievement/where.d.ts.map +1 -0
- package/dist/services/achievement/where.js +23 -0
- package/dist/types.d.ts +117 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reviewAchievementRequest.d.ts","sourceRoot":"","sources":["../../../src/services/achievement/reviewAchievementRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAO7C;;GAEG;AACH,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IACnD,GAAG,EAAE,cAAc,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,UAAU,GAAG,UAAU,CAAA;IACjC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,wEA+BA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { APIError } from 'payload';
|
|
2
|
+
import { collectionOf } from '../../collections/helpers';
|
|
3
|
+
import { getAchievementOptions } from '../../options-store';
|
|
4
|
+
import { relationId } from './relationId';
|
|
5
|
+
/**
|
|
6
|
+
* Approve or reject via collection update. Grant runs in afterChange when approved.
|
|
7
|
+
*/
|
|
8
|
+
export async function reviewAchievementRequest(args) {
|
|
9
|
+
if (!args.req.user)
|
|
10
|
+
throw new APIError('Unauthorized', 401);
|
|
11
|
+
const { canReview } = getAchievementOptions();
|
|
12
|
+
if (!canReview)
|
|
13
|
+
throw new APIError('Forbidden', 403);
|
|
14
|
+
const existing = (await args.req.payload.findByID({
|
|
15
|
+
collection: collectionOf('achievementRequests'),
|
|
16
|
+
id: args.requestId,
|
|
17
|
+
depth: 0,
|
|
18
|
+
overrideAccess: true,
|
|
19
|
+
req: args.req,
|
|
20
|
+
select: { scope: true },
|
|
21
|
+
}));
|
|
22
|
+
const scopeId = relationId(existing?.scope);
|
|
23
|
+
if (!(await canReview(args.req.user, scopeId))) {
|
|
24
|
+
throw new APIError('Forbidden', 403);
|
|
25
|
+
}
|
|
26
|
+
return args.req.payload.update({
|
|
27
|
+
collection: collectionOf('achievementRequests'),
|
|
28
|
+
id: args.requestId,
|
|
29
|
+
data: {
|
|
30
|
+
status: args.decision,
|
|
31
|
+
...(args.note !== undefined ? { note: args.note } : {}),
|
|
32
|
+
},
|
|
33
|
+
overrideAccess: false,
|
|
34
|
+
req: args.req,
|
|
35
|
+
user: args.req.user,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { PayloadRequest } from 'payload';
|
|
2
|
+
/**
|
|
3
|
+
* Create an achievement request (or auto-approved grant) via the collection.
|
|
4
|
+
* Hooks bind the requesting user, check eligibility, and grant when approved.
|
|
5
|
+
*/
|
|
6
|
+
export declare function submitAchievementRequest(args: {
|
|
7
|
+
req: PayloadRequest;
|
|
8
|
+
userId: string;
|
|
9
|
+
achievementId: string;
|
|
10
|
+
scopeId?: string | null;
|
|
11
|
+
note?: string;
|
|
12
|
+
}): Promise<import("payload").JsonObject & import("payload").TypeWithID>;
|
|
13
|
+
/** Create a grant row, emit achievement.granted, sync tier.changed when the ladder moves. */
|
|
14
|
+
export declare function grantAchievement(args: {
|
|
15
|
+
req: PayloadRequest;
|
|
16
|
+
userId: string;
|
|
17
|
+
achievementId: string;
|
|
18
|
+
scopeId?: string | null;
|
|
19
|
+
note?: string | null;
|
|
20
|
+
}): Promise<import("payload").JsonObject & import("payload").TypeWithID>;
|
|
21
|
+
//# sourceMappingURL=submitAchievementRequest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submitAchievementRequest.d.ts","sourceRoot":"","sources":["../../../src/services/achievement/submitAchievementRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAS,MAAM,SAAS,CAAA;AAMpD;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IACnD,GAAG,EAAE,cAAc,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,wEAeA;AAED,6FAA6F;AAC7F,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,EAAE,cAAc,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB,wEAqEA"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { collectionOf } from '../../collections/helpers';
|
|
2
|
+
import { evaluateRules, ruleGroupHasProgressRequirements } from './evaluateRules';
|
|
3
|
+
import { recordLog, syncTierChangedLog } from './recordEvent';
|
|
4
|
+
/**
|
|
5
|
+
* Create an achievement request (or auto-approved grant) via the collection.
|
|
6
|
+
* Hooks bind the requesting user, check eligibility, and grant when approved.
|
|
7
|
+
*/
|
|
8
|
+
export async function submitAchievementRequest(args) {
|
|
9
|
+
return args.req.payload.create({
|
|
10
|
+
collection: collectionOf('achievementRequests'),
|
|
11
|
+
data: {
|
|
12
|
+
// user is overwritten from req.user in beforeValidate
|
|
13
|
+
user: args.userId,
|
|
14
|
+
scope: args.scopeId ?? undefined,
|
|
15
|
+
achievement: args.achievementId,
|
|
16
|
+
note: args.note,
|
|
17
|
+
status: 'pending',
|
|
18
|
+
},
|
|
19
|
+
overrideAccess: false,
|
|
20
|
+
req: args.req,
|
|
21
|
+
user: args.req.user ?? undefined,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/** Create a grant row, emit achievement.granted, sync tier.changed when the ladder moves. */
|
|
25
|
+
export async function grantAchievement(args) {
|
|
26
|
+
const scopeId = args.scopeId ?? null;
|
|
27
|
+
const achievementId = args.achievementId;
|
|
28
|
+
const definition = (await args.req.payload.findByID({
|
|
29
|
+
collection: collectionOf('achievements'),
|
|
30
|
+
id: achievementId,
|
|
31
|
+
depth: 0,
|
|
32
|
+
overrideAccess: true,
|
|
33
|
+
req: args.req,
|
|
34
|
+
}));
|
|
35
|
+
const clauses = [
|
|
36
|
+
{ user: { equals: args.userId } },
|
|
37
|
+
{ achievement: { equals: achievementId } },
|
|
38
|
+
];
|
|
39
|
+
if (scopeId)
|
|
40
|
+
clauses.push({ scope: { equals: scopeId } });
|
|
41
|
+
else
|
|
42
|
+
clauses.push({ scope: { exists: false } });
|
|
43
|
+
const existing = await args.req.payload.find({
|
|
44
|
+
collection: collectionOf('grants'),
|
|
45
|
+
depth: 0,
|
|
46
|
+
limit: 1,
|
|
47
|
+
overrideAccess: true,
|
|
48
|
+
req: args.req,
|
|
49
|
+
where: { and: clauses },
|
|
50
|
+
});
|
|
51
|
+
if (existing.docs[0])
|
|
52
|
+
return existing.docs[0];
|
|
53
|
+
const result = await args.req.payload.create({
|
|
54
|
+
collection: collectionOf('grants'),
|
|
55
|
+
data: {
|
|
56
|
+
user: args.userId,
|
|
57
|
+
scope: scopeId ?? undefined,
|
|
58
|
+
achievement: achievementId,
|
|
59
|
+
completedAt: new Date().toISOString(),
|
|
60
|
+
...(args.note ? { note: args.note } : {}),
|
|
61
|
+
},
|
|
62
|
+
overrideAccess: true,
|
|
63
|
+
req: args.req,
|
|
64
|
+
});
|
|
65
|
+
await recordLog({
|
|
66
|
+
payload: args.req.payload,
|
|
67
|
+
req: args.req,
|
|
68
|
+
userId: args.userId,
|
|
69
|
+
scopeId,
|
|
70
|
+
type: 'achievement.granted',
|
|
71
|
+
data: {
|
|
72
|
+
achievement: achievementId,
|
|
73
|
+
...(definition?.slug ? { achievementSlug: definition.slug } : {}),
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
await syncCompositeGrants({
|
|
77
|
+
req: args.req,
|
|
78
|
+
userId: args.userId,
|
|
79
|
+
scopeId,
|
|
80
|
+
});
|
|
81
|
+
await syncTierChangedLog({
|
|
82
|
+
payload: args.req.payload,
|
|
83
|
+
req: args.req,
|
|
84
|
+
userId: args.userId,
|
|
85
|
+
scopeId,
|
|
86
|
+
});
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
async function syncCompositeGrants(args) {
|
|
90
|
+
const where = args.scopeId
|
|
91
|
+
? { or: [{ scope: { equals: args.scopeId } }, { scope: { exists: false } }] }
|
|
92
|
+
: undefined;
|
|
93
|
+
const catalog = await args.req.payload.find({
|
|
94
|
+
collection: collectionOf('achievements'),
|
|
95
|
+
depth: 0,
|
|
96
|
+
limit: 200,
|
|
97
|
+
pagination: false,
|
|
98
|
+
overrideAccess: true,
|
|
99
|
+
req: args.req,
|
|
100
|
+
...(where ? { where } : {}),
|
|
101
|
+
});
|
|
102
|
+
for (const doc of catalog.docs) {
|
|
103
|
+
const def = doc;
|
|
104
|
+
if (def.requiresReview !== false)
|
|
105
|
+
continue;
|
|
106
|
+
if (!ruleGroupHasProgressRequirements(def.completionRules))
|
|
107
|
+
continue;
|
|
108
|
+
if (String(def.id) === '')
|
|
109
|
+
continue;
|
|
110
|
+
const complete = await evaluateRules({
|
|
111
|
+
payload: args.req.payload,
|
|
112
|
+
req: args.req,
|
|
113
|
+
rules: def.completionRules,
|
|
114
|
+
userId: args.userId,
|
|
115
|
+
scopeId: args.scopeId,
|
|
116
|
+
});
|
|
117
|
+
if (!complete)
|
|
118
|
+
continue;
|
|
119
|
+
await grantAchievement({
|
|
120
|
+
req: args.req,
|
|
121
|
+
userId: args.userId,
|
|
122
|
+
achievementId: String(def.id),
|
|
123
|
+
scopeId: args.scopeId,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type RuleGroup } from './evaluateRules';
|
|
2
|
+
/**
|
|
3
|
+
* Validate a single rule node (leaf or group). Returns an error message or null.
|
|
4
|
+
* Built-in types require their fields; unknown types are left to host extensions.
|
|
5
|
+
*/
|
|
6
|
+
export declare function validateRuleNode(rule: Record<string, unknown>): string | null;
|
|
7
|
+
/** Walk a top-level rule group (or bare array) and return the first error, if any. */
|
|
8
|
+
export declare function validateRuleGroup(input: RuleGroup | Record<string, unknown>[] | null | undefined): string | null;
|
|
9
|
+
/** Throw {@link APIError} when rules are incomplete (for collection hooks). */
|
|
10
|
+
export declare function assertRuleGroupValid(input: RuleGroup | Record<string, unknown>[] | null | undefined, label: string): void;
|
|
11
|
+
//# sourceMappingURL=validateRules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateRules.d.ts","sourceRoot":"","sources":["../../../src/services/achievement/validateRules.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEpE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAuD7E;AAED,sFAAsF;AACtF,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,GAAG,SAAS,GAC9D,MAAM,GAAG,IAAI,CAOf;AAED,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,GAAG,SAAS,EAC/D,KAAK,EAAE,MAAM,GACZ,IAAI,CAKN"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { APIError } from 'payload';
|
|
2
|
+
import { relationId } from './relationId';
|
|
3
|
+
import { normalizeRuleGroup } from './evaluateRules';
|
|
4
|
+
/**
|
|
5
|
+
* Validate a single rule node (leaf or group). Returns an error message or null.
|
|
6
|
+
* Built-in types require their fields; unknown types are left to host extensions.
|
|
7
|
+
*/
|
|
8
|
+
export function validateRuleNode(rule) {
|
|
9
|
+
const type = String(rule.type ?? '');
|
|
10
|
+
if (type === 'group') {
|
|
11
|
+
const children = Array.isArray(rule.rules) ? rule.rules : [];
|
|
12
|
+
if (children.length === 0) {
|
|
13
|
+
return 'A rule group needs at least one rule.';
|
|
14
|
+
}
|
|
15
|
+
for (const child of children) {
|
|
16
|
+
const err = validateRuleNode(child);
|
|
17
|
+
if (err)
|
|
18
|
+
return err;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
if (type === 'tier-at-least') {
|
|
23
|
+
if (!relationId(rule.tier) && typeof rule.tierSlug !== 'string') {
|
|
24
|
+
return 'Tier at least needs a tier.';
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
if (type === 'achievement-complete') {
|
|
29
|
+
if (!relationId(rule.achievement) && typeof rule.achievementSlug !== 'string') {
|
|
30
|
+
return 'Achievement complete needs an achievement.';
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (type === 'metric-minimum') {
|
|
35
|
+
if (!relationId(rule.metric) && typeof rule.metricSlug !== 'string') {
|
|
36
|
+
return 'Metric minimum needs a metric.';
|
|
37
|
+
}
|
|
38
|
+
if (typeof rule.minimum !== 'number' || Number.isNaN(rule.minimum)) {
|
|
39
|
+
return 'Metric minimum needs a numeric minimum.';
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
if (type === 'event-count') {
|
|
44
|
+
if (!relationId(rule.eventType) && typeof rule.eventTypeSlug !== 'string') {
|
|
45
|
+
return 'Event count needs an event type.';
|
|
46
|
+
}
|
|
47
|
+
if (typeof rule.count !== 'number' || Number.isNaN(rule.count)) {
|
|
48
|
+
return 'Event count needs a numeric count.';
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
if (!type) {
|
|
53
|
+
return 'Each rule needs a type.';
|
|
54
|
+
}
|
|
55
|
+
// Host extension types — no shared field schema to check.
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/** Walk a top-level rule group (or bare array) and return the first error, if any. */
|
|
59
|
+
export function validateRuleGroup(input) {
|
|
60
|
+
const group = normalizeRuleGroup(input);
|
|
61
|
+
for (const rule of group.rules) {
|
|
62
|
+
const err = validateRuleNode(rule);
|
|
63
|
+
if (err)
|
|
64
|
+
return err;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
/** Throw {@link APIError} when rules are incomplete (for collection hooks). */
|
|
69
|
+
export function assertRuleGroupValid(input, label) {
|
|
70
|
+
const err = validateRuleGroup(input);
|
|
71
|
+
if (err) {
|
|
72
|
+
throw new APIError(`${label}: ${err}`, 400);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Where } from 'payload';
|
|
2
|
+
/** User (+ optional scope) filter without optional keys that break Where typing. */
|
|
3
|
+
export declare function userScopeWhere(userId: string, scopeId: string | null): Where;
|
|
4
|
+
/**
|
|
5
|
+
* Like {@link userScopeWhere}, but when `scopeId` is set also includes logs with no scope
|
|
6
|
+
* (also matches rows with no scope — e.g. global events that still count toward a scoped ladder).
|
|
7
|
+
*/
|
|
8
|
+
export declare function userScopeIncludingUnscopedWhere(userId: string, scopeId: string | null): Where;
|
|
9
|
+
//# sourceMappingURL=where.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"where.d.ts","sourceRoot":"","sources":["../../../src/services/achievement/where.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,KAAK,CAI5E;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,KAAK,CAU7F"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** User (+ optional scope) filter without optional keys that break Where typing. */
|
|
2
|
+
export function userScopeWhere(userId, scopeId) {
|
|
3
|
+
const clauses = [{ user: { equals: userId } }];
|
|
4
|
+
if (scopeId)
|
|
5
|
+
clauses.push({ scope: { equals: scopeId } });
|
|
6
|
+
return { and: clauses };
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Like {@link userScopeWhere}, but when `scopeId` is set also includes logs with no scope
|
|
10
|
+
* (also matches rows with no scope — e.g. global events that still count toward a scoped ladder).
|
|
11
|
+
*/
|
|
12
|
+
export function userScopeIncludingUnscopedWhere(userId, scopeId) {
|
|
13
|
+
if (!scopeId)
|
|
14
|
+
return userScopeWhere(userId, null);
|
|
15
|
+
return {
|
|
16
|
+
and: [
|
|
17
|
+
{ user: { equals: userId } },
|
|
18
|
+
{
|
|
19
|
+
or: [{ scope: { equals: scopeId } }, { scope: { exists: false } }, { scope: { equals: null } }],
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { CollectionConfig, PayloadRequest, TypedUser } from 'payload';
|
|
2
|
+
export type AchievementScopeConfig = {
|
|
3
|
+
collection: string;
|
|
4
|
+
relationField?: string;
|
|
5
|
+
};
|
|
6
|
+
export type AchievementRuleEvalArgs = {
|
|
7
|
+
payload: PayloadRequest['payload'];
|
|
8
|
+
req: PayloadRequest;
|
|
9
|
+
rule: Record<string, unknown>;
|
|
10
|
+
userId: string;
|
|
11
|
+
scopeId: string | null;
|
|
12
|
+
/**
|
|
13
|
+
* Rank already unlocked while walking the tier ladder.
|
|
14
|
+
* `null` = none yet; omit when evaluating outside a ladder walk.
|
|
15
|
+
*/
|
|
16
|
+
ladderRank?: number | null;
|
|
17
|
+
/** Achievement ids already visited while rolling up nested `achievement-complete` progress. */
|
|
18
|
+
progressVisited?: Set<string>;
|
|
19
|
+
};
|
|
20
|
+
export type AchievementRuleType = {
|
|
21
|
+
type: string;
|
|
22
|
+
evaluate: (args: AchievementRuleEvalArgs) => Promise<boolean> | boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Optional fractional progress toward this leaf (0..1).
|
|
25
|
+
* When omitted, progress falls back to `evaluate` → 0 or 1.
|
|
26
|
+
* Used for next-tier ladder fill and host UIs — not for unlock boolean.
|
|
27
|
+
*/
|
|
28
|
+
progress?: (args: AchievementRuleEvalArgs) => Promise<number> | number;
|
|
29
|
+
/**
|
|
30
|
+
* `gate` rules (e.g. `tier-at-least`) are prerequisites, not progress.
|
|
31
|
+
* They are omitted from AND averages. Default: `requirement`.
|
|
32
|
+
*/
|
|
33
|
+
progressRole?: 'requirement' | 'gate';
|
|
34
|
+
};
|
|
35
|
+
/** Logical collection ids — map to configurable slugs via `collections`. */
|
|
36
|
+
export type AchievementCollectionKey = 'tiers' | 'achievements' | 'grants' | 'achievementRequests' | 'logs' | 'eventTypes' | 'metrics';
|
|
37
|
+
/**
|
|
38
|
+
* Host overrides layered onto a plugin collection (Form Builder–style).
|
|
39
|
+
* Access/admin merge shallowly; hook arrays are appended after plugin hooks.
|
|
40
|
+
*/
|
|
41
|
+
export type AchievementCollectionOverride = {
|
|
42
|
+
access?: CollectionConfig['access'];
|
|
43
|
+
admin?: CollectionConfig['admin'];
|
|
44
|
+
hooks?: CollectionConfig['hooks'];
|
|
45
|
+
labels?: CollectionConfig['labels'];
|
|
46
|
+
};
|
|
47
|
+
export type AchievementCollectionsOptions = {
|
|
48
|
+
/**
|
|
49
|
+
* Prefix applied to default slugs when no per-collection override is set.
|
|
50
|
+
* Drives collection slug, REST `/api/{slug}`, and DB table names.
|
|
51
|
+
* Default: `'achievement'` (e.g. `achievement-tiers`, `achievement-logs`).
|
|
52
|
+
* Always set so host collections are not clobbered. Admin nav grouping is separate (`adminGroup`).
|
|
53
|
+
*/
|
|
54
|
+
prefix?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Admin sidebar group for all plugin collections.
|
|
57
|
+
* Default: `'Achievements'`. Pass `false` to leave ungrouped.
|
|
58
|
+
*/
|
|
59
|
+
adminGroup?: string | false;
|
|
60
|
+
/** Absolute slug overrides (ignore `prefix` for that key). */
|
|
61
|
+
slugs?: Partial<Record<AchievementCollectionKey, string>>;
|
|
62
|
+
/**
|
|
63
|
+
* Per-collection overrides merged on top of plugin defaults.
|
|
64
|
+
* Hook arrays append after the plugin’s; access keys replace the matching operation.
|
|
65
|
+
*/
|
|
66
|
+
overrides?: Partial<Record<AchievementCollectionKey, AchievementCollectionOverride>>;
|
|
67
|
+
};
|
|
68
|
+
export type AchievementUsersOptions = {
|
|
69
|
+
/**
|
|
70
|
+
* Inject an `achievements` group on the users collection with joins to
|
|
71
|
+
* grants + requests (`user.achievements.grants` / `.requests`).
|
|
72
|
+
* Default: `true`. Pass `false` when the host owns that surface.
|
|
73
|
+
*/
|
|
74
|
+
includeJoins?: boolean;
|
|
75
|
+
};
|
|
76
|
+
export type AchievementEndpointsOptions = {
|
|
77
|
+
/**
|
|
78
|
+
* Root REST path for the current-user grants snapshot (`GET`).
|
|
79
|
+
* Default: `'/achievements/me'` → `/api/achievements/me`.
|
|
80
|
+
* Pass `false` to skip registering the endpoint.
|
|
81
|
+
*/
|
|
82
|
+
me?: string | false;
|
|
83
|
+
};
|
|
84
|
+
export type AchievementPluginOptions = {
|
|
85
|
+
/**
|
|
86
|
+
* Whether the user may review requests and manage achievement catalogs for a scope.
|
|
87
|
+
* Required for catalog edits and request approval. When omitted, those writes are denied.
|
|
88
|
+
*/
|
|
89
|
+
canReview?: (user: TypedUser, scopeId: string | null) => boolean | Promise<boolean>;
|
|
90
|
+
/** Collection slug / admin grouping config. */
|
|
91
|
+
collections?: AchievementCollectionsOptions;
|
|
92
|
+
enabled?: boolean;
|
|
93
|
+
/** Custom root API routes registered by the plugin. */
|
|
94
|
+
endpoints?: AchievementEndpointsOptions;
|
|
95
|
+
extensions?: {
|
|
96
|
+
/** Custom rule evaluators merged with built-ins. */
|
|
97
|
+
ruleTypes?: AchievementRuleType[];
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Host upload collection slug (e.g. `'media'`). When set, tiers gain an optional
|
|
101
|
+
* `image` upload field for ladder badges. Icon keys still work without this.
|
|
102
|
+
*/
|
|
103
|
+
mediaCollection?: string;
|
|
104
|
+
scope?: AchievementScopeConfig;
|
|
105
|
+
/**
|
|
106
|
+
* @deprecated Prefer `collections.prefix`.
|
|
107
|
+
* Still honored when `collections.prefix` is unset.
|
|
108
|
+
*/
|
|
109
|
+
slugPrefix?: string;
|
|
110
|
+
/** Users-collection joins / field injection. */
|
|
111
|
+
users?: AchievementUsersOptions;
|
|
112
|
+
usersCollectionSlug?: string;
|
|
113
|
+
};
|
|
114
|
+
export type BuiltInRuleType = 'achievement-complete' | 'event-count' | 'metric-minimum' | 'tier-at-least';
|
|
115
|
+
/** Engine log-type catalog slugs (seeded as system catalog rows). */
|
|
116
|
+
export type BuiltInEventType = 'achievement.granted' | 'metric.delta' | 'tier.changed';
|
|
117
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dappermountain/payload-plugin-achievements",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A robust, Admin-configured achievements engine for Payload: composable unlock rules, derived rank progress, request/review grants, metrics, and scoped multi-tenant support.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/DapperMountain/payload-plugin-achievements.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/DapperMountain/payload-plugin-achievements/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/DapperMountain/payload-plugin-achievements#readme",
|
|
15
|
+
"author": "Dapper Mountain",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"payload",
|
|
18
|
+
"payload-plugin",
|
|
19
|
+
"payloadcms",
|
|
20
|
+
"achievements",
|
|
21
|
+
"gamification",
|
|
22
|
+
"tiers",
|
|
23
|
+
"grants"
|
|
24
|
+
],
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js",
|
|
29
|
+
"default": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./types": {
|
|
32
|
+
"types": "./dist/types.d.ts",
|
|
33
|
+
"import": "./dist/types.js",
|
|
34
|
+
"default": "./dist/types.js"
|
|
35
|
+
},
|
|
36
|
+
"./client": {
|
|
37
|
+
"types": "./dist/exports/client.d.ts",
|
|
38
|
+
"import": "./dist/exports/client.js",
|
|
39
|
+
"default": "./dist/exports/client.js"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"main": "./dist/index.js",
|
|
43
|
+
"types": "./dist/index.d.ts",
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"LICENSE",
|
|
47
|
+
"README.md"
|
|
48
|
+
],
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public",
|
|
51
|
+
"registry": "https://registry.npmjs.org/"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsc -p tsconfig.build.json",
|
|
55
|
+
"prepare": "bun run build",
|
|
56
|
+
"lint": "tsc --noEmit",
|
|
57
|
+
"test": "bun test src",
|
|
58
|
+
"prepublishOnly": "bun run build",
|
|
59
|
+
"clean": "rm -rf dist *.tsbuildinfo",
|
|
60
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,md}\" \"*.md\"",
|
|
61
|
+
"agents:sync": "bunx @dappermountain/agent-payload sync",
|
|
62
|
+
"skills:install": "bunx skills add payloadcms/skills --skill payload -y --copy -a cursor",
|
|
63
|
+
"skills:update": "bunx skills update payload -y -p",
|
|
64
|
+
"skills:check": "bunx skills check -p"
|
|
65
|
+
},
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"@payloadcms/ui": "^3.88.0",
|
|
68
|
+
"payload": "^3.88.0",
|
|
69
|
+
"react": "^19.0.0"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@payloadcms/ui": "3.88.0",
|
|
73
|
+
"@types/react": "^19.0.0",
|
|
74
|
+
"payload": "3.88.0",
|
|
75
|
+
"react": "19.2.4",
|
|
76
|
+
"typescript": "5.9.2",
|
|
77
|
+
"prettier": "^3.6.2",
|
|
78
|
+
"@types/bun": "1.4.0",
|
|
79
|
+
"@dappermountain/agent-practices": "^0.1.0",
|
|
80
|
+
"@dappermountain/agent-payload": "^0.1.0"
|
|
81
|
+
},
|
|
82
|
+
"engines": {
|
|
83
|
+
"node": ">=20"
|
|
84
|
+
}
|
|
85
|
+
}
|