@learncard/lca-api-plugin 1.2.16 → 1.2.18

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.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,38 @@
1
+ import {
2
+ UnsignedVCValidator,
3
+ VC,
4
+ VCValidator,
5
+ UnsignedVPValidator,
6
+ VPValidator,
7
+ } from '@learncard/types';
8
+
9
+ import { initLCALearnCard, LCALearnCard } from '../';
10
+
11
+ let learnCards: Record<
12
+ string,
13
+ {
14
+ learnCard: LCALearnCard;
15
+ }
16
+ > = {};
17
+
18
+ const getLearnCard = async (seed = 'a'.repeat(64)) => {
19
+ if (!learnCards[seed]) {
20
+
21
+ const learnCard = await initLCALearnCard({ seed });
22
+ learnCards[seed] = { learnCard: learnCard };
23
+ }
24
+
25
+ return {
26
+ ...learnCards[seed].learnCard,
27
+ };
28
+ };
29
+
30
+ // Skipping until LCA is up.
31
+ describe.skip('LCA Plugin', () => {
32
+ describe('LCALearnCard', () => {
33
+ it('should work', async () => {
34
+ await expect(getLearnCard()).resolves.toBeDefined();
35
+ });
36
+ });
37
+ });
38
+
package/src/types.ts ADDED
@@ -0,0 +1,396 @@
1
+ import { z } from 'zod';
2
+ import {
3
+ JWE,
4
+ DidDocument,
5
+ JWKWithPrivateKey,
6
+ VP,
7
+ LCNNotificationTypeEnumValidator,
8
+ LCNNotificationValidator,
9
+ LCNProfile,
10
+ LCNVisibleProfile,
11
+ } from '@learncard/types';
12
+ import { Plugin } from '@learncard/core';
13
+ import { ProofOptions } from '@learncard/didkit-plugin';
14
+
15
+ export type BoostSkills = {
16
+ category: string;
17
+ skill: string;
18
+ subskills: string[];
19
+ };
20
+
21
+ export const ScoutsSSOResponseSchema = z.object({
22
+ access_token: z.string(),
23
+ expires_in: z.number(),
24
+ 'not-before-policy': z.number(),
25
+ refresh_expires_in: z.number(),
26
+ refresh_token: z.string(),
27
+ scope: z.string(),
28
+ session_state: z.string(),
29
+ token_type: z.string(),
30
+ error: z.string().optional(),
31
+ error_description: z.string().optional(),
32
+ });
33
+ export type ScoutSSOResponseType = z.infer<typeof ScoutsSSOResponseSchema>;
34
+
35
+ const UserRecordSchema = z.object({
36
+ uid: z.string(),
37
+ email: z.string().nullable(),
38
+ emailVerified: z.boolean(),
39
+ displayName: z.string().nullable(),
40
+ phoneNumber: z.string().nullable(),
41
+ photoURL: z.string().nullable(),
42
+ disabled: z.boolean(),
43
+ providerData: z.array(
44
+ z.object({
45
+ uid: z.string(),
46
+ displayName: z.string().nullable(),
47
+ email: z.string().nullable(),
48
+ phoneNumber: z.string().nullable(),
49
+ photoURL: z.string().nullable(),
50
+ providerId: z.string(),
51
+ })
52
+ ),
53
+ metadata: z.object({
54
+ creationTime: z.string(),
55
+ lastSignInTime: z.string().nullable(),
56
+ }),
57
+ customClaims: z.record(z.string(), z.any()).optional(),
58
+ });
59
+
60
+ export type UserRecordType = z.infer<typeof UserRecordSchema>;
61
+
62
+ // Zod Schema for Firebase Custom Token Response
63
+ const FirebaseCustomAuthResponseSchema = z.object({
64
+ firebaseToken: z.string(),
65
+ });
66
+
67
+ export type FirebaseCustomAuthResponse = z.infer<typeof FirebaseCustomAuthResponseSchema>;
68
+
69
+ // Zod Schema for Preferences
70
+ export enum ThemeEnum {
71
+ Colorful = 'colorful',
72
+ Formal = 'formal',
73
+ }
74
+
75
+ export const PreferencesValidator = z.object({
76
+ theme: z.enum([ThemeEnum.Colorful, ThemeEnum.Formal]).optional(),
77
+ aiEnabled: z.boolean().optional(),
78
+ aiAutoDisabled: z.boolean().optional(),
79
+ analyticsEnabled: z.boolean().optional(),
80
+ analyticsAutoDisabled: z.boolean().optional(),
81
+ bugReportsEnabled: z.boolean().optional(),
82
+ isMinor: z.boolean().optional(),
83
+ });
84
+
85
+ export type PreferencesType = z.infer<typeof PreferencesValidator>;
86
+ export type CreatePreferencesType = {
87
+ theme: ThemeEnum;
88
+ };
89
+
90
+ /** @group LCA API Plugin */
91
+ export const SigningAuthorityValidator = z.object({
92
+ _id: z.string().optional(),
93
+ ownerDid: z.string(),
94
+ name: z.string(),
95
+ did: z.string().optional(),
96
+ endpoint: z.string().optional(),
97
+ });
98
+
99
+ /** @group LCA API Plugin */
100
+ export type SigningAuthorityType = z.infer<typeof SigningAuthorityValidator>;
101
+
102
+ /** @group LCA API Plugin */
103
+ export type SigningAuthorityAuthorization = {
104
+ type: string;
105
+ boostUri: string;
106
+ };
107
+
108
+ /** These Types are Kept in Sync with LCA-API Service.
109
+ * TODO: Move into shared package
110
+ */
111
+
112
+ /** @group LCA API Plugin */
113
+ export const NotificationActionStatusEnumValidator = z.enum(['PENDING', 'COMPLETED', 'REJECTED']);
114
+
115
+ export type NotificationActionStatusEnumType = z.infer<
116
+ typeof NotificationActionStatusEnumValidator
117
+ >;
118
+
119
+ /** @group LCA API Plugin */
120
+ export const NotificationMetaValidator = z.object({
121
+ archived: z.boolean().optional(),
122
+ read: z.boolean().optional(),
123
+ actionStatus: NotificationActionStatusEnumValidator.optional(),
124
+ });
125
+
126
+ /** @group LCA API Plugin */
127
+ export type NotificationMetaType = z.infer<typeof NotificationMetaValidator>;
128
+
129
+ /** @group LCA API Plugin */
130
+ export const NotificationQueryFiltersValidator = NotificationMetaValidator.extend({
131
+ type: LCNNotificationTypeEnumValidator.optional(),
132
+ });
133
+
134
+ /** @group LCA API Plugin */
135
+ export type NotificationQueryFiltersType = z.infer<typeof NotificationQueryFiltersValidator>;
136
+
137
+ // Paginated Notifications
138
+ /** @group LCA API Plugin */
139
+ export const NotificationsSortEnumValidator = z.enum(['CHRONOLOGICAL', 'REVERSE_CHRONOLOGICAL']);
140
+
141
+ /** @group LCA API Plugin */
142
+ export type NotificationsSortEnum = z.infer<typeof NotificationsSortEnumValidator>;
143
+
144
+ /** @group LCA API Plugin */
145
+ export const PaginatedNotificationsOptionsValidator = z.object({
146
+ limit: z.number(),
147
+ cursor: z.string().optional(),
148
+ sort: NotificationsSortEnumValidator.default(
149
+ NotificationsSortEnumValidator.enum.REVERSE_CHRONOLOGICAL
150
+ ),
151
+ });
152
+
153
+ /** @group LCA API Plugin */
154
+ export type PaginatedNotificationsOptionsType = z.infer<
155
+ typeof PaginatedNotificationsOptionsValidator
156
+ >;
157
+
158
+ /** @group LCA API Plugin */
159
+ export const NotificationValidator = LCNNotificationValidator.extend({
160
+ _id: z.string().optional(),
161
+ read: z.boolean(),
162
+ archived: z.boolean(),
163
+ actionStatus: NotificationActionStatusEnumValidator.optional(),
164
+ });
165
+ /** @group LCA API Plugin */
166
+ export type NotificationType = z.infer<typeof NotificationValidator>;
167
+
168
+ export const PaginatedNotificationsValidator = z.object({
169
+ cursor: z.string().optional(),
170
+ hasMore: z.boolean(),
171
+ notifications: NotificationValidator.array(),
172
+ });
173
+
174
+ export type PaginatedNotificationsType = z.infer<typeof PaginatedNotificationsValidator>;
175
+
176
+ /** @group LCA API Plugin */
177
+ export const NotificationQueryInputValidator = z
178
+ .object({
179
+ type: LCNNotificationTypeEnumValidator.optional(),
180
+ 'from.did': z.string().optional(),
181
+ 'from.profileId': z.string().optional(),
182
+ 'data.vcUris': z.union([z.string(), z.array(z.string())]).optional(),
183
+ 'data.vpUris': z.union([z.string(), z.array(z.string())]).optional(),
184
+ 'data.metadata.listingId': z.string().optional(),
185
+ read: z.boolean().optional(),
186
+ archived: z.boolean().optional(),
187
+ actionStatus: NotificationActionStatusEnumValidator.optional(),
188
+ })
189
+ .strict();
190
+
191
+ /** @group LCA API Plugin */
192
+ export type NotificationQueryInputType = z.infer<typeof NotificationQueryInputValidator>;
193
+ /** END Synced Types**/
194
+
195
+ /** @group LCA API Plugin - SSS Key Management */
196
+ export const AuthProviderTypeValidator = z.enum(['firebase', 'supertokens', 'keycloak', 'oidc']);
197
+ export type AuthProviderType = z.infer<typeof AuthProviderTypeValidator>;
198
+
199
+ export const ServerEncryptedShareValidator = z.object({
200
+ encryptedData: z.string(),
201
+ encryptedDek: z.string(),
202
+ iv: z.string(),
203
+ });
204
+ export type ServerEncryptedShare = z.infer<typeof ServerEncryptedShareValidator>;
205
+
206
+ export const EncryptedShareValidator = z.object({
207
+ encryptedData: z.string(),
208
+ iv: z.string(),
209
+ salt: z.string().optional(),
210
+ });
211
+ export type EncryptedShare = z.infer<typeof EncryptedShareValidator>;
212
+
213
+ export const RecoveryMethodTypeValidator = z.enum(['passkey', 'backup', 'phrase', 'email']);
214
+ export type RecoveryMethodType = z.infer<typeof RecoveryMethodTypeValidator>;
215
+
216
+ export const SecurityLevelValidator = z.enum(['basic', 'enhanced', 'advanced']);
217
+ export type SecurityLevel = z.infer<typeof SecurityLevelValidator>;
218
+
219
+ export const KeyProviderValidator = z.enum(['web3auth', 'sss']);
220
+ export type KeyProvider = z.infer<typeof KeyProviderValidator>;
221
+
222
+ export const RecoveryMethodInfoValidator = z.object({
223
+ type: RecoveryMethodTypeValidator,
224
+ createdAt: z.string(),
225
+ credentialId: z.string().optional(),
226
+ shareVersion: z.number().optional(),
227
+ });
228
+ export type RecoveryMethodInfo = z.infer<typeof RecoveryMethodInfoValidator>;
229
+
230
+ export const GetAuthShareResponseValidator = z
231
+ .object({
232
+ authShare: ServerEncryptedShareValidator.nullable(),
233
+ primaryDid: z.string().nullable(),
234
+ securityLevel: SecurityLevelValidator,
235
+ recoveryMethods: z.array(RecoveryMethodInfoValidator),
236
+ keyProvider: KeyProviderValidator,
237
+ shareVersion: z.number(),
238
+ maskedRecoveryEmail: z.string().nullable(),
239
+ })
240
+ .nullable();
241
+ export type GetAuthShareResponse = z.infer<typeof GetAuthShareResponseValidator>;
242
+
243
+ /** @group LCA API Plugin */
244
+ export type LCAPluginDependentMethods = {
245
+ getDidAuthVp: (options?: ProofOptions) => Promise<VP | string>;
246
+ getProfile: () => Promise<LCNVisibleProfile | undefined>;
247
+ generateEd25519KeyFromBytes: (bytes: Uint8Array) => JWKWithPrivateKey;
248
+ keyToDid: (type: 'key', keypair: JWKWithPrivateKey) => string;
249
+ resolveDid: (did: string) => Promise<DidDocument>;
250
+ addDidMetadata: (metadata: Partial<DidDocument>) => Promise<boolean>;
251
+ decryptDagJwe: <T>(jwe: JWE, jwks?: JWKWithPrivateKey[]) => Promise<T>;
252
+ crypto: () => Crypto;
253
+ };
254
+
255
+ export enum DASHBOARD_TYPE {
256
+ NSO,
257
+ GLOBAL,
258
+ TROOP,
259
+ }
260
+
261
+ export type AnalyticsPayload = {
262
+ resource: {
263
+ dashboardType: DASHBOARD_TYPE;
264
+ };
265
+ params: {
266
+ nso_id?: string[];
267
+ troop_id?: string[];
268
+ };
269
+ exp: number;
270
+ };
271
+
272
+ /** @group LCA API Plugin */
273
+ export type LCAPluginMethods = {
274
+ registerDeviceForPushNotifications: (token: string) => Promise<boolean>;
275
+ unregisterDeviceForPushNotifications: (token: string) => Promise<boolean>;
276
+ getNotifications: (
277
+ options: PaginatedNotificationsOptionsType,
278
+ filter?: NotificationQueryFiltersType
279
+ ) => Promise<PaginatedNotificationsType | false>;
280
+ queryNotifications: (
281
+ query: NotificationQueryInputType,
282
+ options?: Partial<PaginatedNotificationsOptionsType>
283
+ ) => Promise<PaginatedNotificationsType | false>;
284
+ updateNotificationMeta: (_id: string, meta: NotificationMetaType) => Promise<boolean>;
285
+ markAllNotificationsRead: () => Promise<boolean>;
286
+ createSigningAuthority: (
287
+ name: string,
288
+ ownerDid?: string
289
+ ) => Promise<SigningAuthorityType | false>;
290
+ getSigningAuthorities: () => Promise<SigningAuthorityType[] | false>;
291
+ authorizeSigningAuthority: (
292
+ name: string,
293
+ authorization: SigningAuthorityAuthorization
294
+ ) => Promise<boolean>;
295
+ resetLCAClient: () => Promise<void>;
296
+ generateBoostInfo: (description: string) => Promise<{
297
+ title: string;
298
+ description: string;
299
+ category: string;
300
+ type: string;
301
+ skills: BoostSkills[];
302
+ narrative: string;
303
+ }>;
304
+ generateImage: (prompt: string) => Promise<string>;
305
+ generateBoostSkills: (description: string) => Promise<BoostSkills[]>;
306
+ generateSkillIcons: (names: string[]) => Promise<Record<string, string>>;
307
+ createPin: (pin: string) => Promise<boolean>;
308
+ hasPin: (did?: string) => Promise<boolean>;
309
+ verifyPin: (pin: string, did?: string) => Promise<boolean>;
310
+ updatePin: (currentPin: string, newPin: string) => Promise<boolean>;
311
+ generatePinUpdateToken: () => Promise<{ token: string; tokenExpire: Date } | null>;
312
+ validatePinUpdateToken: (token: string) => Promise<boolean>;
313
+ updatePinWithToken: (token: string, newPin: string) => Promise<boolean>;
314
+ generateAnalyticsAccessToken: (payload: AnalyticsPayload) => Promise<string | null>;
315
+ decryptDagJwe: <T>(jwe: JWE, jwks?: JWKWithPrivateKey[]) => Promise<T>;
316
+ hash: (message: string, algorithm?: string) => Promise<string | undefined>;
317
+ getFirebaseUserByEmail: (email: string) => Promise<UserRecordType | null>;
318
+ authenticateWithKeycloak: (token: string) => Promise<FirebaseCustomAuthResponse>;
319
+ authenticateWithScoutsSSO: (
320
+ username: string,
321
+ password: string
322
+ ) => Promise<ScoutSSOResponseType | null>;
323
+ sendLoginVerificationCode: (email: string) => Promise<{ success: boolean; message?: string }>;
324
+ verifyLoginCode: (
325
+ email: string,
326
+ code: string
327
+ ) => Promise<{ success: boolean; message?: string; token?: string }>;
328
+ verifyNetworkHandoffToken: (
329
+ token: string
330
+ ) => Promise<{ success: boolean; message?: string; token?: string }>;
331
+ getProofOfLoginVp: (
332
+ token: string
333
+ ) => Promise<{ success: boolean; error?: string; vp?: string }>;
334
+ updatePreferences: (preferences: PreferencesType) => Promise<boolean>;
335
+ createPreferences: (preferences: CreatePreferencesType) => Promise<boolean>;
336
+ getPreferencesForDid: () => Promise<PreferencesType>;
337
+ sendEndorsementShareLink: (
338
+ email: string,
339
+ shareLink: string,
340
+ issuer: {
341
+ name: string;
342
+ },
343
+ credential: {
344
+ name: string;
345
+ },
346
+ message: string
347
+ ) => Promise<boolean>;
348
+
349
+ // SSS Key Management Methods
350
+ getAuthShare: (
351
+ authToken: string,
352
+ providerType: AuthProviderType
353
+ ) => Promise<GetAuthShareResponse>;
354
+
355
+ storeAuthShare: (
356
+ authToken: string,
357
+ providerType: AuthProviderType,
358
+ authShare: ServerEncryptedShare,
359
+ primaryDid: string,
360
+ securityLevel?: SecurityLevel
361
+ ) => Promise<{ success: boolean }>;
362
+
363
+ addRecoveryMethod: (
364
+ authToken: string,
365
+ providerType: AuthProviderType,
366
+ type: RecoveryMethodType,
367
+ encryptedShare?: EncryptedShare,
368
+ credentialId?: string
369
+ ) => Promise<{ success: boolean }>;
370
+
371
+ getRecoveryShare: (
372
+ authToken: string,
373
+ providerType: AuthProviderType,
374
+ type: RecoveryMethodType,
375
+ credentialId?: string
376
+ ) => Promise<{ encryptedShare?: EncryptedShare; shareVersion?: number } | null>;
377
+
378
+ markMigrated: (
379
+ authToken: string,
380
+ providerType: AuthProviderType
381
+ ) => Promise<{ success: boolean }>;
382
+
383
+ deleteUserKey: (
384
+ authToken: string,
385
+ providerType: AuthProviderType
386
+ ) => Promise<{ success: boolean }>;
387
+ };
388
+
389
+ /** @group LearnCardNetwork Plugin */
390
+ export type LCAPlugin = Plugin<
391
+ 'LearnCard App',
392
+ never,
393
+ LCAPluginMethods,
394
+ 'id',
395
+ LCAPluginDependentMethods
396
+ >;