@learncard/claimable-boosts-plugin 1.1.24 → 1.1.26

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/package.json CHANGED
@@ -1,56 +1,58 @@
1
1
  {
2
- "name": "@learncard/claimable-boosts-plugin",
3
- "version": "1.1.24",
4
- "description": "",
5
- "type": "module",
6
- "main": "./dist/index.cjs",
7
- "module": "./dist/claimable-boosts-plugin.esm.js",
8
- "exports": {
9
- ".": {
10
- "import": {
11
- "types": "./dist/index.d.ts",
12
- "default": "./dist/claimable-boosts-plugin.esm.js"
13
- },
14
- "require": {
15
- "types": "./dist/index.d.cts",
16
- "default": "./dist/index.cjs"
17
- }
18
- }
19
- },
20
- "files": [
21
- "dist"
22
- ],
23
- "author": "Learning Economy Foundation (www.learningeconomy.io)",
24
- "license": "MIT",
25
- "homepage": "https://github.com/learningeconomy/LearnCard/tree/main/packages/plugins/claimable-boosts/README.md",
26
- "repository": {
27
- "type": "git",
28
- "url": "https://github.com/learningeconomy/LearnCard"
29
- },
30
- "bugs": {
31
- "url": "https://github.com/learningeconomy/LearnCard/issues"
32
- },
33
- "devDependencies": {
34
- "@types/jest": "^29.2.2",
35
- "@types/node": "^17.0.31",
36
- "aqu": "0.4.3",
37
- "esbuild": "^0.27.1",
38
- "esbuild-jest": "^0.5.0",
39
- "esbuild-plugin-copy": "^1.3.0",
40
- "jest": "^29.3.0",
41
- "shx": "^0.3.4",
42
- "ts-jest": "^29.0.3"
43
- },
44
- "types": "./dist/index.d.ts",
45
- "dependencies": {
46
- "@learncard/core": "9.4.24",
47
- "@learncard/types": "5.17.4"
48
- },
49
- "sideEffects": false,
50
- "scripts": {
51
- "build": "node ./scripts/build.mjs && shx cp ./scripts/mixedEntypoint.js ./dist/index.cjs && tsc --p tsconfig.json && shx cp ./dist/index.d.ts ./dist/index.d.cts",
52
- "test": "jest --passWithNoTests",
53
- "test:watch": "jest --watch",
54
- "test:coverage": "jest --silent --ci --coverage --coverageReporters=\"text\" --coverageReporters=\"text-summary\""
55
- }
56
- }
2
+ "name": "@learncard/claimable-boosts-plugin",
3
+ "version": "1.1.26",
4
+ "description": "",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/claimable-boosts-plugin.esm.js",
8
+ "exports": {
9
+ ".": {
10
+ "development": "./src/index.ts",
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/claimable-boosts-plugin.esm.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "src"
24
+ ],
25
+ "scripts": {
26
+ "build": "node ./scripts/build.mjs && shx cp ./scripts/mixedEntypoint.js ./dist/index.cjs && tsc --p tsconfig.json && shx cp ./dist/index.d.ts ./dist/index.d.cts",
27
+ "test": "jest --passWithNoTests",
28
+ "test:watch": "jest --watch",
29
+ "test:coverage": "jest --silent --ci --coverage --coverageReporters=\"text\" --coverageReporters=\"text-summary\""
30
+ },
31
+ "author": "Learning Economy Foundation (www.learningeconomy.io)",
32
+ "license": "MIT",
33
+ "homepage": "https://github.com/learningeconomy/LearnCard/tree/main/packages/plugins/claimable-boosts/README.md",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/learningeconomy/LearnCard"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/learningeconomy/LearnCard/issues"
40
+ },
41
+ "devDependencies": {
42
+ "@types/jest": "^29.2.2",
43
+ "@types/node": "^17.0.31",
44
+ "aqu": "0.4.3",
45
+ "esbuild": "^0.27.1",
46
+ "esbuild-jest": "^0.5.0",
47
+ "esbuild-plugin-copy": "^1.3.0",
48
+ "jest": "^29.3.0",
49
+ "shx": "^0.3.4",
50
+ "ts-jest": "^29.0.3"
51
+ },
52
+ "types": "./dist/index.d.ts",
53
+ "dependencies": {
54
+ "@learncard/core": "9.4.26",
55
+ "@learncard/types": "5.17.5"
56
+ },
57
+ "sideEffects": false
58
+ }
package/src/index.ts ADDED
@@ -0,0 +1,127 @@
1
+ import { LCNBoostClaimLinkOptionsType } from '@learncard/types';
2
+ import {
3
+ ClaimableBoostsPlugin,
4
+ ClaimableBoostsPluginDependentMethods,
5
+ SigningAuthorityType,
6
+ } from './types';
7
+
8
+ import { LearnCard } from '@learncard/core';
9
+
10
+ export * from './types';
11
+
12
+ const DEFAULT_RELATIONSHIP_NAME = 'lca-sa';
13
+
14
+ /**
15
+ * @group Plugins
16
+ */
17
+ export const getClaimableBoostsPlugin = (
18
+ learnCard: LearnCard<any, any, ClaimableBoostsPluginDependentMethods>
19
+ ): ClaimableBoostsPlugin => {
20
+ return {
21
+ name: 'ClaimableBoosts',
22
+ displayName: 'Claimable Boosts',
23
+ description:
24
+ 'Simple claimable boost creation plugin that handles signing authority management.',
25
+ methods: {
26
+ generateBoostClaimLink: async (
27
+ _learnCard: LearnCard<any, any, ClaimableBoostsPluginDependentMethods>,
28
+ boostURI: string,
29
+ options?: LCNBoostClaimLinkOptionsType
30
+ ) => {
31
+ _learnCard.debug?.('Generating boost claim link...', boostURI, options);
32
+ return _generateBoostClaimLink(_learnCard, boostURI, options);
33
+ },
34
+ },
35
+ };
36
+ };
37
+
38
+ const _generateBoostClaimLink = async (
39
+ _learnCard: LearnCard<any, any, ClaimableBoostsPluginDependentMethods>,
40
+ boostURI: string,
41
+ options?: LCNBoostClaimLinkOptionsType
42
+ ): Promise<string> => {
43
+ try {
44
+ const rsas = await _learnCard.invoke.getRegisteredSigningAuthorities();
45
+ _learnCard.debug?.('Registered Signing Authorities', rsas);
46
+
47
+ if (rsas?.length > 0) {
48
+ const rsa = rsas[0];
49
+ _learnCard.debug?.('Using Existing Signing Authority', rsa);
50
+
51
+ // generate claim link with existing rsa
52
+ const _boostClaimLink = await _learnCard.invoke.generateClaimLink(
53
+ boostURI,
54
+ {
55
+ name: rsa?.relationship?.name || '',
56
+ endpoint: rsa?.signingAuthority?.endpoint || '',
57
+ },
58
+ options
59
+ );
60
+
61
+ if (!_boostClaimLink) {
62
+ throw new Error('Failed to generate claim link');
63
+ }
64
+
65
+ return `https://learncard.app/claim/boost?claim=true&boostUri=${_boostClaimLink.boostUri}&challenge=${_boostClaimLink.challenge}`;
66
+ }
67
+
68
+ // find existing signing authority
69
+ const signingAuthorities = await _learnCard.invoke.getSigningAuthorities();
70
+ _learnCard.debug?.('Existing Signing Authorities', signingAuthorities);
71
+
72
+ let sa: SigningAuthorityType | undefined;
73
+ if (signingAuthorities && Array.isArray(signingAuthorities)) {
74
+ sa = signingAuthorities.find(
75
+ (signingAuthority: SigningAuthorityType) =>
76
+ signingAuthority.name === DEFAULT_RELATIONSHIP_NAME
77
+ );
78
+ }
79
+
80
+ if (!sa) {
81
+ // create signing authority
82
+ const newSa = await _learnCard.invoke.createSigningAuthority(DEFAULT_RELATIONSHIP_NAME);
83
+ _learnCard.debug?.('Creating New Signing Authority', newSa);
84
+ if (!newSa) {
85
+ throw new Error('Failed to create signing authority');
86
+ }
87
+ sa = {
88
+ ownerDid: newSa.ownerDid,
89
+ name: DEFAULT_RELATIONSHIP_NAME,
90
+ endpoint: newSa.endpoint,
91
+ did: newSa.did,
92
+ };
93
+ }
94
+
95
+ // register signing authority
96
+ const rsa = await _learnCard.invoke.registerSigningAuthority(
97
+ sa?.endpoint || '',
98
+ sa?.name || '',
99
+ sa?.did || ''
100
+ );
101
+
102
+ _learnCard.debug?.('Registering Signing Authority with Network', sa);
103
+
104
+ if (!rsa) {
105
+ throw new Error('Failed to register signing authority');
106
+ }
107
+
108
+ const _boostClaimLink = await _learnCard.invoke.generateClaimLink(
109
+ boostURI,
110
+ {
111
+ name: sa?.name || '',
112
+ endpoint: sa?.endpoint || '',
113
+ },
114
+ options
115
+ );
116
+ _learnCard.debug?.('Generating Claim Link', _boostClaimLink);
117
+
118
+ if (!_boostClaimLink) {
119
+ throw new Error('Failed to generate claim link');
120
+ }
121
+
122
+ return `https://learncard.app/claim/boost?claim=true&boostUri=${_boostClaimLink.boostUri}&challenge=${_boostClaimLink.challenge}`;
123
+ } catch (error) {
124
+ _learnCard.debug?.('Error generateBoostClaimLink:', error);
125
+ throw new Error('Failed to generate boost claim link: ' + (error as Error).message);
126
+ }
127
+ };
@@ -0,0 +1,56 @@
1
+ import { getClaimableBoostsPlugin } from '../';
2
+
3
+ describe('Claimable Boosts Plugin', () => {
4
+ it('exposes a function', () => {
5
+ expect(getClaimableBoostsPlugin).toBeDefined();
6
+ });
7
+
8
+ it('returns a plugin', () => {
9
+ const plugin = getClaimableBoostsPlugin({
10
+ invoke: {
11
+ generateClaimLink: jest.fn(),
12
+ getRegisteredSigningAuthorities: jest.fn(),
13
+ },
14
+ } as any);
15
+ expect(plugin).toBeDefined();
16
+ });
17
+
18
+ it('returns a plugin with the correct name', () => {
19
+ const plugin = getClaimableBoostsPlugin({
20
+ invoke: {
21
+ generateClaimLink: jest.fn(),
22
+ getRegisteredSigningAuthorities: jest.fn(),
23
+ },
24
+ } as any);
25
+ expect(plugin.name).toBe('ClaimableBoosts');
26
+ });
27
+
28
+ it('generates a claim link for a boost', async () => {
29
+ const mockGenerateClaimLink = jest.fn().mockResolvedValue({
30
+ boostUri: 'test-uri',
31
+ challenge: 'test-challenge'
32
+ });
33
+ const mockGetRegisteredSigningAuthorities = jest.fn().mockResolvedValue([{
34
+ relationship: { name: 'test-name' },
35
+ signingAuthority: { endpoint: 'test-endpoint' }
36
+ }]);
37
+
38
+ const mockLearnCard = {
39
+ invoke: {
40
+ generateClaimLink: mockGenerateClaimLink,
41
+ getRegisteredSigningAuthorities: mockGetRegisteredSigningAuthorities,
42
+ },
43
+ };
44
+
45
+ const plugin = getClaimableBoostsPlugin(mockLearnCard as any);
46
+
47
+ const result = await plugin.methods.generateBoostClaimLink(mockLearnCard as any, 'test-boost-uri');
48
+ expect(result).toBe('https://learncard.app/claim/boost?claim=true&boostUri=test-uri&challenge=test-challenge');
49
+
50
+ expect(mockGetRegisteredSigningAuthorities).toHaveBeenCalled();
51
+ expect(mockGenerateClaimLink).toHaveBeenCalledWith('test-boost-uri', {
52
+ name: 'test-name',
53
+ endpoint: 'test-endpoint'
54
+ }, undefined);
55
+ });
56
+ });
package/src/types.ts ADDED
@@ -0,0 +1,50 @@
1
+ import { z } from 'zod';
2
+ import { Plugin } from '@learncard/core';
3
+ import { LCNBoostClaimLinkOptionsType } from '@learncard/types';
4
+ import { LCNSigningAuthorityForUserType } from '@learncard/types';
5
+
6
+ export const SigningAuthorityValidator = z.object({
7
+ _id: z.string().optional(),
8
+ ownerDid: z.string(),
9
+ name: z.string(),
10
+ did: z.string().optional(),
11
+ endpoint: z.string().optional(),
12
+ });
13
+
14
+ export type SigningAuthorityType = z.infer<typeof SigningAuthorityValidator>;
15
+
16
+ /** @group Claimable Boosts Plugin */
17
+ export type ClaimableBoostsPluginMethods = {
18
+ generateBoostClaimLink: (
19
+ boostURI: string,
20
+ options?: LCNBoostClaimLinkOptionsType
21
+ ) => Promise<string>;
22
+ };
23
+
24
+ /** @group Claimable Boosts Plugin */
25
+ export type ClaimableBoostsPluginDependentMethods = {
26
+ createSigningAuthority: (name: string) => Promise<SigningAuthorityType | false>;
27
+ getSigningAuthorities: () => Promise<SigningAuthorityType[] | false>;
28
+ getRegisteredSigningAuthorities: () => Promise<LCNSigningAuthorityForUserType[]>;
29
+ registerSigningAuthority: (endpoint: string, name: string, did: string) => Promise<boolean>;
30
+ generateClaimLink: (
31
+ boostUri: string,
32
+ claimLinkSA: {
33
+ name: string;
34
+ endpoint: string;
35
+ },
36
+ options?: LCNBoostClaimLinkOptionsType,
37
+ challenge?: string
38
+ ) => Promise<{
39
+ boostUri: string;
40
+ challenge: string;
41
+ }>;
42
+ };
43
+
44
+ export type ClaimableBoostsPlugin = Plugin<
45
+ 'ClaimableBoosts',
46
+ any,
47
+ ClaimableBoostsPluginMethods,
48
+ any,
49
+ ClaimableBoostsPluginDependentMethods
50
+ >;