@learncard/claimable-boosts-plugin 1.1.24 → 1.1.25
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/dist/claimable-boosts-plugin.cjs.development.cjs +80 -80
- package/dist/claimable-boosts-plugin.cjs.development.cjs.map +1 -1
- package/dist/claimable-boosts-plugin.cjs.production.min.cjs.map +1 -1
- package/dist/claimable-boosts-plugin.esm.js +80 -80
- package/dist/claimable-boosts-plugin.esm.js.map +1 -1
- package/package.json +57 -55
- package/src/index.ts +127 -0
- package/src/test/index.test.ts +56 -0
- package/src/types.ts +50 -0
package/package.json
CHANGED
|
@@ -1,56 +1,58 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
2
|
+
"name": "@learncard/claimable-boosts-plugin",
|
|
3
|
+
"version": "1.1.25",
|
|
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": "workspace:*",
|
|
55
|
+
"@learncard/types": "workspace:*"
|
|
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
|
+
>;
|