@singi-labs/sifa-sdk 0.19.36 → 0.19.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/{index-zH6rKRMx.d.ts → index-D9GC0u__.d.ts} +2 -0
  2. package/dist/{index-YuN--u4s.d.cts → index-DmlIG8sJ.d.cts} +2 -0
  3. package/dist/index.cjs +53 -1
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +33 -8
  6. package/dist/index.d.ts +33 -8
  7. package/dist/index.js +49 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/jsonld/index.d.cts +1 -1
  10. package/dist/jsonld/index.d.ts +1 -1
  11. package/dist/{network-map-DzUZbvNV.d.cts → network-map-B0bp4-ex.d.cts} +50 -4
  12. package/dist/{network-map-CjsywYe3.d.ts → network-map-C-y5XxLI.d.ts} +50 -4
  13. package/dist/{org-dzSDMm8B.d.ts → org-BCrvebcf.d.ts} +2 -2
  14. package/dist/{org-Bgi06A5c.d.cts → org-DC_FpoTY.d.cts} +2 -2
  15. package/dist/{profile-investment-BdN_H620.d.cts → profile-investment-BiHM7C5q.d.cts} +1 -0
  16. package/dist/{profile-investment-BdN_H620.d.ts → profile-investment-BiHM7C5q.d.ts} +1 -0
  17. package/dist/{profile-summary-BpsM-qn7.d.cts → profile-summary-C_wdHGj6.d.cts} +1 -1
  18. package/dist/{profile-summary-BZK3QP-a.d.ts → profile-summary-Qtfk-52i.d.ts} +1 -1
  19. package/dist/query/fetchers/index.cjs +30 -0
  20. package/dist/query/fetchers/index.cjs.map +1 -1
  21. package/dist/query/fetchers/index.d.cts +6 -6
  22. package/dist/query/fetchers/index.d.ts +6 -6
  23. package/dist/query/fetchers/index.js +28 -1
  24. package/dist/query/fetchers/index.js.map +1 -1
  25. package/dist/query/hooks/index.d.cts +4 -4
  26. package/dist/query/hooks/index.d.ts +4 -4
  27. package/dist/query/index.cjs +30 -0
  28. package/dist/query/index.cjs.map +1 -1
  29. package/dist/query/index.d.cts +9 -9
  30. package/dist/query/index.d.ts +9 -9
  31. package/dist/query/index.js +28 -1
  32. package/dist/query/index.js.map +1 -1
  33. package/dist/resume/index.d.cts +1 -1
  34. package/dist/resume/index.d.ts +1 -1
  35. package/dist/rpg/index.cjs +122 -0
  36. package/dist/rpg/index.cjs.map +1 -0
  37. package/dist/rpg/index.d.cts +74 -0
  38. package/dist/rpg/index.d.ts +74 -0
  39. package/dist/rpg/index.js +117 -0
  40. package/dist/rpg/index.js.map +1 -0
  41. package/dist/schemas/index.cjs +2 -0
  42. package/dist/schemas/index.cjs.map +1 -1
  43. package/dist/schemas/index.d.cts +1 -1
  44. package/dist/schemas/index.d.ts +1 -1
  45. package/dist/schemas/index.js +2 -0
  46. package/dist/schemas/index.js.map +1 -1
  47. package/dist/schemas/write/index.cjs +1 -0
  48. package/dist/schemas/write/index.cjs.map +1 -1
  49. package/dist/schemas/write/index.d.cts +1 -0
  50. package/dist/schemas/write/index.d.ts +1 -0
  51. package/dist/schemas/write/index.js +1 -0
  52. package/dist/schemas/write/index.js.map +1 -1
  53. package/dist/{types-7-Jq6p_Z.d.cts → types-CK8KgdqA.d.ts} +3 -1
  54. package/dist/{types-BYiUBDvk.d.ts → types-DAGqE0b9.d.cts} +3 -1
  55. package/dist/{use-org-notification-emails-DVEluUaC.d.ts → use-org-notification-emails-0hjt-dEw.d.ts} +3 -3
  56. package/dist/{use-org-notification-emails-D87skWDq.d.cts → use-org-notification-emails-DOyAF0C_.d.cts} +3 -3
  57. package/package.json +11 -1
@@ -1,4 +1,4 @@
1
- import { L as LocationValue, d as ProfilePosition, f as ProfileEducation, P as ProfileSkill, e as ProfileCertification, i as ProfileProject, j as ProfilePublication, J as ProfileVolunteering, g as ProfileHonor, h as ProfileLanguage, p as ExternalAccount } from '../index-YuN--u4s.cjs';
1
+ import { L as LocationValue, d as ProfilePosition, f as ProfileEducation, P as ProfileSkill, e as ProfileCertification, i as ProfileProject, j as ProfilePublication, J as ProfileVolunteering, g as ProfileHonor, h as ProfileLanguage, p as ExternalAccount } from '../index-DmlIG8sJ.cjs';
2
2
  import '../shared-v0vl5hov.cjs';
3
3
  import 'zod';
4
4
 
@@ -1,4 +1,4 @@
1
- import { L as LocationValue, d as ProfilePosition, f as ProfileEducation, P as ProfileSkill, e as ProfileCertification, i as ProfileProject, j as ProfilePublication, J as ProfileVolunteering, g as ProfileHonor, h as ProfileLanguage, p as ExternalAccount } from '../index-zH6rKRMx.js';
1
+ import { L as LocationValue, d as ProfilePosition, f as ProfileEducation, P as ProfileSkill, e as ProfileCertification, i as ProfileProject, j as ProfilePublication, J as ProfileVolunteering, g as ProfileHonor, h as ProfileLanguage, p as ExternalAccount } from '../index-D9GC0u__.js';
2
2
  import '../shared-v0vl5hov.js';
3
3
  import 'zod';
4
4
 
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+
5
+ // src/rpg/catalog.ts
6
+ var RpgUnlockSchema = zod.z.discriminatedUnion("kind", [
7
+ zod.z.object({
8
+ kind: zod.z.literal("hasRecord"),
9
+ collection: zod.z.enum([
10
+ "id.sifa.profile.position",
11
+ "id.sifa.profile.volunteering",
12
+ "id.sifa.profile.presentation",
13
+ "id.sifa.profile.education"
14
+ ])
15
+ }),
16
+ zod.z.object({ kind: zod.z.literal("hasExternalAccount"), platforms: zod.z.array(zod.z.string()).min(1) }),
17
+ zod.z.object({ kind: zod.z.literal("usesApp"), appId: zod.z.string().min(1) }),
18
+ zod.z.object({ kind: zod.z.literal("hasDoctorate") })
19
+ ]);
20
+ var RpgItemSchema = zod.z.object({
21
+ /** Lowercase `[a-z0-9_]` only: the id is embedded in an AT Protocol record key. */
22
+ id: zod.z.string().min(1).max(50).regex(/^[a-z0-9_]+$/),
23
+ title: zod.z.string().max(100),
24
+ description: zod.z.string().max(500),
25
+ kind: zod.z.enum(["layer", "held"]),
26
+ category: zod.z.string().max(30),
27
+ unlock: zod.z.array(RpgUnlockSchema).min(1),
28
+ // ANY of these unlocks the item
29
+ enabled: zod.z.boolean()
30
+ });
31
+ var RPG_ITEMS = [
32
+ {
33
+ id: "sifa_power_suit",
34
+ title: "Power Suit",
35
+ description: "",
36
+ kind: "layer",
37
+ category: "tops",
38
+ enabled: true,
39
+ unlock: [{ kind: "hasRecord", collection: "id.sifa.profile.position" }]
40
+ },
41
+ {
42
+ id: "sifa_weekend_shirt",
43
+ title: "Weekend Shirt",
44
+ description: "",
45
+ kind: "layer",
46
+ category: "tops",
47
+ enabled: true,
48
+ unlock: [{ kind: "hasRecord", collection: "id.sifa.profile.volunteering" }]
49
+ },
50
+ {
51
+ id: "sifa_speaker_mic",
52
+ title: "Speaker Mic",
53
+ description: "",
54
+ kind: "held",
55
+ category: "righthand",
56
+ enabled: true,
57
+ unlock: [{ kind: "hasRecord", collection: "id.sifa.profile.presentation" }]
58
+ },
59
+ {
60
+ id: "sifa_school_books",
61
+ title: "School Books",
62
+ description: "",
63
+ kind: "held",
64
+ category: "lefthand",
65
+ enabled: true,
66
+ unlock: [{ kind: "hasRecord", collection: "id.sifa.profile.education" }]
67
+ },
68
+ {
69
+ id: "sifa_doctoral_cap",
70
+ title: "Doctoral Cap",
71
+ description: "",
72
+ kind: "layer",
73
+ category: "headwear",
74
+ enabled: false,
75
+ unlock: [{ kind: "hasDoctorate" }]
76
+ },
77
+ {
78
+ id: "sifa_lab_coat",
79
+ title: "Lab Coat",
80
+ description: "",
81
+ kind: "layer",
82
+ category: "tops",
83
+ enabled: true,
84
+ unlock: [{ kind: "hasExternalAccount", platforms: ["orcid"] }]
85
+ },
86
+ {
87
+ id: "sifa_dev_hoodie",
88
+ title: "Dev Hoodie",
89
+ description: "",
90
+ kind: "layer",
91
+ category: "tops",
92
+ enabled: true,
93
+ unlock: [
94
+ { kind: "hasExternalAccount", platforms: ["github"] },
95
+ { kind: "usesApp", appId: "tangled" }
96
+ ]
97
+ }
98
+ ];
99
+
100
+ // src/rpg/unlocks.ts
101
+ function matches(u, s) {
102
+ switch (u.kind) {
103
+ case "hasRecord":
104
+ return s.collections.includes(u.collection);
105
+ case "hasExternalAccount":
106
+ return u.platforms.some((p) => s.externalPlatforms.includes(p));
107
+ case "usesApp":
108
+ return s.activeAppIds.includes(u.appId);
109
+ case "hasDoctorate":
110
+ return s.hasDoctorate;
111
+ }
112
+ }
113
+ function evaluateRpgUnlocks(signals, items = RPG_ITEMS) {
114
+ return items.filter((item) => item.enabled).map((item) => ({ item, earned: item.unlock.some((u) => matches(u, signals)) }));
115
+ }
116
+
117
+ exports.RPG_ITEMS = RPG_ITEMS;
118
+ exports.RpgItemSchema = RpgItemSchema;
119
+ exports.RpgUnlockSchema = RpgUnlockSchema;
120
+ exports.evaluateRpgUnlocks = evaluateRpgUnlocks;
121
+ //# sourceMappingURL=index.cjs.map
122
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/rpg/catalog.ts","../../src/rpg/unlocks.ts"],"names":["z"],"mappings":"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","file":"index.cjs","sourcesContent":["import { z } from 'zod';\n\nexport const RpgUnlockSchema = z.discriminatedUnion('kind', [\n z.object({\n kind: z.literal('hasRecord'),\n collection: z.enum([\n 'id.sifa.profile.position',\n 'id.sifa.profile.volunteering',\n 'id.sifa.profile.presentation',\n 'id.sifa.profile.education',\n ]),\n }),\n z.object({ kind: z.literal('hasExternalAccount'), platforms: z.array(z.string()).min(1) }),\n z.object({ kind: z.literal('usesApp'), appId: z.string().min(1) }),\n z.object({ kind: z.literal('hasDoctorate') }),\n]);\n\nexport const RpgItemSchema = z.object({\n /** Lowercase `[a-z0-9_]` only: the id is embedded in an AT Protocol record key. */\n id: z\n .string()\n .min(1)\n .max(50)\n .regex(/^[a-z0-9_]+$/),\n title: z.string().max(100),\n description: z.string().max(500),\n kind: z.enum(['layer', 'held']),\n category: z.string().max(30),\n unlock: z.array(RpgUnlockSchema).min(1), // ANY of these unlocks the item\n enabled: z.boolean(),\n});\nexport type RpgItem = z.infer<typeof RpgItemSchema>;\nexport type RpgUnlock = z.infer<typeof RpgUnlockSchema>;\n\n/**\n * The Sifa item catalog for rpg.actor. PLACEHOLDER titles/categories until\n * rpg.actor transfers the real item cores.\n */\nexport const RPG_ITEMS: readonly RpgItem[] = [\n {\n id: 'sifa_power_suit',\n title: 'Power Suit',\n description: '',\n kind: 'layer',\n category: 'tops',\n enabled: true,\n unlock: [{ kind: 'hasRecord', collection: 'id.sifa.profile.position' }],\n },\n {\n id: 'sifa_weekend_shirt',\n title: 'Weekend Shirt',\n description: '',\n kind: 'layer',\n category: 'tops',\n enabled: true,\n unlock: [{ kind: 'hasRecord', collection: 'id.sifa.profile.volunteering' }],\n },\n {\n id: 'sifa_speaker_mic',\n title: 'Speaker Mic',\n description: '',\n kind: 'held',\n category: 'righthand',\n enabled: true,\n unlock: [{ kind: 'hasRecord', collection: 'id.sifa.profile.presentation' }],\n },\n {\n id: 'sifa_school_books',\n title: 'School Books',\n description: '',\n kind: 'held',\n category: 'lefthand',\n enabled: true,\n unlock: [{ kind: 'hasRecord', collection: 'id.sifa.profile.education' }],\n },\n {\n id: 'sifa_doctoral_cap',\n title: 'Doctoral Cap',\n description: '',\n kind: 'layer',\n category: 'headwear',\n enabled: false,\n unlock: [{ kind: 'hasDoctorate' }],\n },\n {\n id: 'sifa_lab_coat',\n title: 'Lab Coat',\n description: '',\n kind: 'layer',\n category: 'tops',\n enabled: true,\n unlock: [{ kind: 'hasExternalAccount', platforms: ['orcid'] }],\n },\n {\n id: 'sifa_dev_hoodie',\n title: 'Dev Hoodie',\n description: '',\n kind: 'layer',\n category: 'tops',\n enabled: true,\n unlock: [\n { kind: 'hasExternalAccount', platforms: ['github'] },\n { kind: 'usesApp', appId: 'tangled' },\n ],\n },\n];\n","import { RPG_ITEMS, type RpgItem, type RpgUnlock } from './catalog.js';\n\n/**\n * Profile signals the unlock rules are checked against. Callers must pass\n * lowercase platform codes (e.g. 'github', 'orcid') and registry app ids (e.g. 'tangled').\n */\nexport interface RpgUnlockSignals {\n collections: readonly string[];\n externalPlatforms: readonly string[];\n activeAppIds: readonly string[];\n hasDoctorate: boolean;\n}\n\n/** One enabled catalog item and whether the signals earn it. */\nexport interface RpgUnlockResult {\n item: RpgItem;\n earned: boolean;\n}\n\nfunction matches(u: RpgUnlock, s: RpgUnlockSignals): boolean {\n switch (u.kind) {\n case 'hasRecord':\n return s.collections.includes(u.collection);\n case 'hasExternalAccount':\n return u.platforms.some((p) => s.externalPlatforms.includes(p));\n case 'usesApp':\n return s.activeAppIds.includes(u.appId);\n case 'hasDoctorate':\n return s.hasDoctorate;\n }\n}\n\n/** Evaluate every enabled item (ANY matching unlock earns it); disabled items are omitted. */\nexport function evaluateRpgUnlocks(\n signals: RpgUnlockSignals,\n items: readonly RpgItem[] = RPG_ITEMS,\n): RpgUnlockResult[] {\n return items\n .filter((item) => item.enabled)\n .map((item) => ({ item, earned: item.unlock.some((u) => matches(u, signals)) }));\n}\n"]}
@@ -0,0 +1,74 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const RpgUnlockSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
4
+ kind: z.ZodLiteral<"hasRecord">;
5
+ collection: z.ZodEnum<{
6
+ "id.sifa.profile.position": "id.sifa.profile.position";
7
+ "id.sifa.profile.volunteering": "id.sifa.profile.volunteering";
8
+ "id.sifa.profile.presentation": "id.sifa.profile.presentation";
9
+ "id.sifa.profile.education": "id.sifa.profile.education";
10
+ }>;
11
+ }, z.core.$strip>, z.ZodObject<{
12
+ kind: z.ZodLiteral<"hasExternalAccount">;
13
+ platforms: z.ZodArray<z.ZodString>;
14
+ }, z.core.$strip>, z.ZodObject<{
15
+ kind: z.ZodLiteral<"usesApp">;
16
+ appId: z.ZodString;
17
+ }, z.core.$strip>, z.ZodObject<{
18
+ kind: z.ZodLiteral<"hasDoctorate">;
19
+ }, z.core.$strip>], "kind">;
20
+ declare const RpgItemSchema: z.ZodObject<{
21
+ id: z.ZodString;
22
+ title: z.ZodString;
23
+ description: z.ZodString;
24
+ kind: z.ZodEnum<{
25
+ layer: "layer";
26
+ held: "held";
27
+ }>;
28
+ category: z.ZodString;
29
+ unlock: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
30
+ kind: z.ZodLiteral<"hasRecord">;
31
+ collection: z.ZodEnum<{
32
+ "id.sifa.profile.position": "id.sifa.profile.position";
33
+ "id.sifa.profile.volunteering": "id.sifa.profile.volunteering";
34
+ "id.sifa.profile.presentation": "id.sifa.profile.presentation";
35
+ "id.sifa.profile.education": "id.sifa.profile.education";
36
+ }>;
37
+ }, z.core.$strip>, z.ZodObject<{
38
+ kind: z.ZodLiteral<"hasExternalAccount">;
39
+ platforms: z.ZodArray<z.ZodString>;
40
+ }, z.core.$strip>, z.ZodObject<{
41
+ kind: z.ZodLiteral<"usesApp">;
42
+ appId: z.ZodString;
43
+ }, z.core.$strip>, z.ZodObject<{
44
+ kind: z.ZodLiteral<"hasDoctorate">;
45
+ }, z.core.$strip>], "kind">>;
46
+ enabled: z.ZodBoolean;
47
+ }, z.core.$strip>;
48
+ type RpgItem = z.infer<typeof RpgItemSchema>;
49
+ type RpgUnlock = z.infer<typeof RpgUnlockSchema>;
50
+ /**
51
+ * The Sifa item catalog for rpg.actor. PLACEHOLDER titles/categories until
52
+ * rpg.actor transfers the real item cores.
53
+ */
54
+ declare const RPG_ITEMS: readonly RpgItem[];
55
+
56
+ /**
57
+ * Profile signals the unlock rules are checked against. Callers must pass
58
+ * lowercase platform codes (e.g. 'github', 'orcid') and registry app ids (e.g. 'tangled').
59
+ */
60
+ interface RpgUnlockSignals {
61
+ collections: readonly string[];
62
+ externalPlatforms: readonly string[];
63
+ activeAppIds: readonly string[];
64
+ hasDoctorate: boolean;
65
+ }
66
+ /** One enabled catalog item and whether the signals earn it. */
67
+ interface RpgUnlockResult {
68
+ item: RpgItem;
69
+ earned: boolean;
70
+ }
71
+ /** Evaluate every enabled item (ANY matching unlock earns it); disabled items are omitted. */
72
+ declare function evaluateRpgUnlocks(signals: RpgUnlockSignals, items?: readonly RpgItem[]): RpgUnlockResult[];
73
+
74
+ export { RPG_ITEMS, type RpgItem, RpgItemSchema, type RpgUnlock, type RpgUnlockResult, RpgUnlockSchema, type RpgUnlockSignals, evaluateRpgUnlocks };
@@ -0,0 +1,74 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const RpgUnlockSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
4
+ kind: z.ZodLiteral<"hasRecord">;
5
+ collection: z.ZodEnum<{
6
+ "id.sifa.profile.position": "id.sifa.profile.position";
7
+ "id.sifa.profile.volunteering": "id.sifa.profile.volunteering";
8
+ "id.sifa.profile.presentation": "id.sifa.profile.presentation";
9
+ "id.sifa.profile.education": "id.sifa.profile.education";
10
+ }>;
11
+ }, z.core.$strip>, z.ZodObject<{
12
+ kind: z.ZodLiteral<"hasExternalAccount">;
13
+ platforms: z.ZodArray<z.ZodString>;
14
+ }, z.core.$strip>, z.ZodObject<{
15
+ kind: z.ZodLiteral<"usesApp">;
16
+ appId: z.ZodString;
17
+ }, z.core.$strip>, z.ZodObject<{
18
+ kind: z.ZodLiteral<"hasDoctorate">;
19
+ }, z.core.$strip>], "kind">;
20
+ declare const RpgItemSchema: z.ZodObject<{
21
+ id: z.ZodString;
22
+ title: z.ZodString;
23
+ description: z.ZodString;
24
+ kind: z.ZodEnum<{
25
+ layer: "layer";
26
+ held: "held";
27
+ }>;
28
+ category: z.ZodString;
29
+ unlock: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
30
+ kind: z.ZodLiteral<"hasRecord">;
31
+ collection: z.ZodEnum<{
32
+ "id.sifa.profile.position": "id.sifa.profile.position";
33
+ "id.sifa.profile.volunteering": "id.sifa.profile.volunteering";
34
+ "id.sifa.profile.presentation": "id.sifa.profile.presentation";
35
+ "id.sifa.profile.education": "id.sifa.profile.education";
36
+ }>;
37
+ }, z.core.$strip>, z.ZodObject<{
38
+ kind: z.ZodLiteral<"hasExternalAccount">;
39
+ platforms: z.ZodArray<z.ZodString>;
40
+ }, z.core.$strip>, z.ZodObject<{
41
+ kind: z.ZodLiteral<"usesApp">;
42
+ appId: z.ZodString;
43
+ }, z.core.$strip>, z.ZodObject<{
44
+ kind: z.ZodLiteral<"hasDoctorate">;
45
+ }, z.core.$strip>], "kind">>;
46
+ enabled: z.ZodBoolean;
47
+ }, z.core.$strip>;
48
+ type RpgItem = z.infer<typeof RpgItemSchema>;
49
+ type RpgUnlock = z.infer<typeof RpgUnlockSchema>;
50
+ /**
51
+ * The Sifa item catalog for rpg.actor. PLACEHOLDER titles/categories until
52
+ * rpg.actor transfers the real item cores.
53
+ */
54
+ declare const RPG_ITEMS: readonly RpgItem[];
55
+
56
+ /**
57
+ * Profile signals the unlock rules are checked against. Callers must pass
58
+ * lowercase platform codes (e.g. 'github', 'orcid') and registry app ids (e.g. 'tangled').
59
+ */
60
+ interface RpgUnlockSignals {
61
+ collections: readonly string[];
62
+ externalPlatforms: readonly string[];
63
+ activeAppIds: readonly string[];
64
+ hasDoctorate: boolean;
65
+ }
66
+ /** One enabled catalog item and whether the signals earn it. */
67
+ interface RpgUnlockResult {
68
+ item: RpgItem;
69
+ earned: boolean;
70
+ }
71
+ /** Evaluate every enabled item (ANY matching unlock earns it); disabled items are omitted. */
72
+ declare function evaluateRpgUnlocks(signals: RpgUnlockSignals, items?: readonly RpgItem[]): RpgUnlockResult[];
73
+
74
+ export { RPG_ITEMS, type RpgItem, RpgItemSchema, type RpgUnlock, type RpgUnlockResult, RpgUnlockSchema, type RpgUnlockSignals, evaluateRpgUnlocks };
@@ -0,0 +1,117 @@
1
+ import { z } from 'zod';
2
+
3
+ // src/rpg/catalog.ts
4
+ var RpgUnlockSchema = z.discriminatedUnion("kind", [
5
+ z.object({
6
+ kind: z.literal("hasRecord"),
7
+ collection: z.enum([
8
+ "id.sifa.profile.position",
9
+ "id.sifa.profile.volunteering",
10
+ "id.sifa.profile.presentation",
11
+ "id.sifa.profile.education"
12
+ ])
13
+ }),
14
+ z.object({ kind: z.literal("hasExternalAccount"), platforms: z.array(z.string()).min(1) }),
15
+ z.object({ kind: z.literal("usesApp"), appId: z.string().min(1) }),
16
+ z.object({ kind: z.literal("hasDoctorate") })
17
+ ]);
18
+ var RpgItemSchema = z.object({
19
+ /** Lowercase `[a-z0-9_]` only: the id is embedded in an AT Protocol record key. */
20
+ id: z.string().min(1).max(50).regex(/^[a-z0-9_]+$/),
21
+ title: z.string().max(100),
22
+ description: z.string().max(500),
23
+ kind: z.enum(["layer", "held"]),
24
+ category: z.string().max(30),
25
+ unlock: z.array(RpgUnlockSchema).min(1),
26
+ // ANY of these unlocks the item
27
+ enabled: z.boolean()
28
+ });
29
+ var RPG_ITEMS = [
30
+ {
31
+ id: "sifa_power_suit",
32
+ title: "Power Suit",
33
+ description: "",
34
+ kind: "layer",
35
+ category: "tops",
36
+ enabled: true,
37
+ unlock: [{ kind: "hasRecord", collection: "id.sifa.profile.position" }]
38
+ },
39
+ {
40
+ id: "sifa_weekend_shirt",
41
+ title: "Weekend Shirt",
42
+ description: "",
43
+ kind: "layer",
44
+ category: "tops",
45
+ enabled: true,
46
+ unlock: [{ kind: "hasRecord", collection: "id.sifa.profile.volunteering" }]
47
+ },
48
+ {
49
+ id: "sifa_speaker_mic",
50
+ title: "Speaker Mic",
51
+ description: "",
52
+ kind: "held",
53
+ category: "righthand",
54
+ enabled: true,
55
+ unlock: [{ kind: "hasRecord", collection: "id.sifa.profile.presentation" }]
56
+ },
57
+ {
58
+ id: "sifa_school_books",
59
+ title: "School Books",
60
+ description: "",
61
+ kind: "held",
62
+ category: "lefthand",
63
+ enabled: true,
64
+ unlock: [{ kind: "hasRecord", collection: "id.sifa.profile.education" }]
65
+ },
66
+ {
67
+ id: "sifa_doctoral_cap",
68
+ title: "Doctoral Cap",
69
+ description: "",
70
+ kind: "layer",
71
+ category: "headwear",
72
+ enabled: false,
73
+ unlock: [{ kind: "hasDoctorate" }]
74
+ },
75
+ {
76
+ id: "sifa_lab_coat",
77
+ title: "Lab Coat",
78
+ description: "",
79
+ kind: "layer",
80
+ category: "tops",
81
+ enabled: true,
82
+ unlock: [{ kind: "hasExternalAccount", platforms: ["orcid"] }]
83
+ },
84
+ {
85
+ id: "sifa_dev_hoodie",
86
+ title: "Dev Hoodie",
87
+ description: "",
88
+ kind: "layer",
89
+ category: "tops",
90
+ enabled: true,
91
+ unlock: [
92
+ { kind: "hasExternalAccount", platforms: ["github"] },
93
+ { kind: "usesApp", appId: "tangled" }
94
+ ]
95
+ }
96
+ ];
97
+
98
+ // src/rpg/unlocks.ts
99
+ function matches(u, s) {
100
+ switch (u.kind) {
101
+ case "hasRecord":
102
+ return s.collections.includes(u.collection);
103
+ case "hasExternalAccount":
104
+ return u.platforms.some((p) => s.externalPlatforms.includes(p));
105
+ case "usesApp":
106
+ return s.activeAppIds.includes(u.appId);
107
+ case "hasDoctorate":
108
+ return s.hasDoctorate;
109
+ }
110
+ }
111
+ function evaluateRpgUnlocks(signals, items = RPG_ITEMS) {
112
+ return items.filter((item) => item.enabled).map((item) => ({ item, earned: item.unlock.some((u) => matches(u, signals)) }));
113
+ }
114
+
115
+ export { RPG_ITEMS, RpgItemSchema, RpgUnlockSchema, evaluateRpgUnlocks };
116
+ //# sourceMappingURL=index.js.map
117
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/rpg/catalog.ts","../../src/rpg/unlocks.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { z } from 'zod';\n\nexport const RpgUnlockSchema = z.discriminatedUnion('kind', [\n z.object({\n kind: z.literal('hasRecord'),\n collection: z.enum([\n 'id.sifa.profile.position',\n 'id.sifa.profile.volunteering',\n 'id.sifa.profile.presentation',\n 'id.sifa.profile.education',\n ]),\n }),\n z.object({ kind: z.literal('hasExternalAccount'), platforms: z.array(z.string()).min(1) }),\n z.object({ kind: z.literal('usesApp'), appId: z.string().min(1) }),\n z.object({ kind: z.literal('hasDoctorate') }),\n]);\n\nexport const RpgItemSchema = z.object({\n /** Lowercase `[a-z0-9_]` only: the id is embedded in an AT Protocol record key. */\n id: z\n .string()\n .min(1)\n .max(50)\n .regex(/^[a-z0-9_]+$/),\n title: z.string().max(100),\n description: z.string().max(500),\n kind: z.enum(['layer', 'held']),\n category: z.string().max(30),\n unlock: z.array(RpgUnlockSchema).min(1), // ANY of these unlocks the item\n enabled: z.boolean(),\n});\nexport type RpgItem = z.infer<typeof RpgItemSchema>;\nexport type RpgUnlock = z.infer<typeof RpgUnlockSchema>;\n\n/**\n * The Sifa item catalog for rpg.actor. PLACEHOLDER titles/categories until\n * rpg.actor transfers the real item cores.\n */\nexport const RPG_ITEMS: readonly RpgItem[] = [\n {\n id: 'sifa_power_suit',\n title: 'Power Suit',\n description: '',\n kind: 'layer',\n category: 'tops',\n enabled: true,\n unlock: [{ kind: 'hasRecord', collection: 'id.sifa.profile.position' }],\n },\n {\n id: 'sifa_weekend_shirt',\n title: 'Weekend Shirt',\n description: '',\n kind: 'layer',\n category: 'tops',\n enabled: true,\n unlock: [{ kind: 'hasRecord', collection: 'id.sifa.profile.volunteering' }],\n },\n {\n id: 'sifa_speaker_mic',\n title: 'Speaker Mic',\n description: '',\n kind: 'held',\n category: 'righthand',\n enabled: true,\n unlock: [{ kind: 'hasRecord', collection: 'id.sifa.profile.presentation' }],\n },\n {\n id: 'sifa_school_books',\n title: 'School Books',\n description: '',\n kind: 'held',\n category: 'lefthand',\n enabled: true,\n unlock: [{ kind: 'hasRecord', collection: 'id.sifa.profile.education' }],\n },\n {\n id: 'sifa_doctoral_cap',\n title: 'Doctoral Cap',\n description: '',\n kind: 'layer',\n category: 'headwear',\n enabled: false,\n unlock: [{ kind: 'hasDoctorate' }],\n },\n {\n id: 'sifa_lab_coat',\n title: 'Lab Coat',\n description: '',\n kind: 'layer',\n category: 'tops',\n enabled: true,\n unlock: [{ kind: 'hasExternalAccount', platforms: ['orcid'] }],\n },\n {\n id: 'sifa_dev_hoodie',\n title: 'Dev Hoodie',\n description: '',\n kind: 'layer',\n category: 'tops',\n enabled: true,\n unlock: [\n { kind: 'hasExternalAccount', platforms: ['github'] },\n { kind: 'usesApp', appId: 'tangled' },\n ],\n },\n];\n","import { RPG_ITEMS, type RpgItem, type RpgUnlock } from './catalog.js';\n\n/**\n * Profile signals the unlock rules are checked against. Callers must pass\n * lowercase platform codes (e.g. 'github', 'orcid') and registry app ids (e.g. 'tangled').\n */\nexport interface RpgUnlockSignals {\n collections: readonly string[];\n externalPlatforms: readonly string[];\n activeAppIds: readonly string[];\n hasDoctorate: boolean;\n}\n\n/** One enabled catalog item and whether the signals earn it. */\nexport interface RpgUnlockResult {\n item: RpgItem;\n earned: boolean;\n}\n\nfunction matches(u: RpgUnlock, s: RpgUnlockSignals): boolean {\n switch (u.kind) {\n case 'hasRecord':\n return s.collections.includes(u.collection);\n case 'hasExternalAccount':\n return u.platforms.some((p) => s.externalPlatforms.includes(p));\n case 'usesApp':\n return s.activeAppIds.includes(u.appId);\n case 'hasDoctorate':\n return s.hasDoctorate;\n }\n}\n\n/** Evaluate every enabled item (ANY matching unlock earns it); disabled items are omitted. */\nexport function evaluateRpgUnlocks(\n signals: RpgUnlockSignals,\n items: readonly RpgItem[] = RPG_ITEMS,\n): RpgUnlockResult[] {\n return items\n .filter((item) => item.enabled)\n .map((item) => ({ item, earned: item.unlock.some((u) => matches(u, signals)) }));\n}\n"]}
@@ -358,6 +358,8 @@ var ProfileEducationRecordSchema = zod.z.object({
358
358
  entityRef: zod.z.string().url().refine((s) => /^https?:\/\//i.test(s), { message: "entityRef must be an http(s) URL" }).max(2048).optional(),
359
359
  degree: zod.z.string().refine(maxGraphemes(100)).max(1e3).optional(),
360
360
  fieldOfStudy: zod.z.string().refine(maxGraphemes(100)).max(1e3).optional(),
361
+ // European Qualifications Framework level, 1 to 8 (8 = doctoral) (#594).
362
+ eqfLevel: zod.z.number().int().min(1).max(8).optional(),
361
363
  grade: zod.z.string().refine(maxGraphemes(50)).max(500).optional(),
362
364
  activities: zod.z.string().refine(maxGraphemes(1e3)).max(1e4).optional(),
363
365
  description: zod.z.string().refine(maxGraphemes(5e3)).max(5e4).optional(),