@learncard/partner-connect 0.2.0 → 0.2.2
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/index.d.ts +66 -7
- package/dist/partner-connect.esm.js +76 -27
- package/dist/partner-connect.esm.js.map +1 -1
- package/dist/partner-connect.js +76 -27
- package/dist/partner-connect.js.map +1 -1
- package/package.json +8 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { AppEvent, AppEventResponse } from '@learncard/types';
|
|
2
|
+
export { AppEvent, AppEventResponse, SendCredentialEvent } from '@learncard/types';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* LearnCard Partner Connect SDK - Type Definitions
|
|
3
6
|
*/
|
|
7
|
+
|
|
4
8
|
/**
|
|
5
9
|
* Configuration options for initializing the SDK
|
|
6
10
|
*/
|
|
@@ -70,12 +74,32 @@ interface IdentityResponse {
|
|
|
70
74
|
};
|
|
71
75
|
}
|
|
72
76
|
/**
|
|
73
|
-
* Response from SEND_CREDENTIAL action
|
|
77
|
+
* Response from SEND_CREDENTIAL action (raw credential)
|
|
74
78
|
*/
|
|
75
79
|
interface SendCredentialResponse {
|
|
76
80
|
credentialId: string;
|
|
77
81
|
[key: string]: unknown;
|
|
78
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Template-based credential input for sendCredential
|
|
85
|
+
* Uses a pre-configured boost template to issue a credential
|
|
86
|
+
*/
|
|
87
|
+
interface TemplateCredentialInput {
|
|
88
|
+
/** Alias of the boost template configured for this app */
|
|
89
|
+
templateAlias: string;
|
|
90
|
+
/** Optional template data for Mustache-style variable substitution */
|
|
91
|
+
templateData?: Record<string, unknown>;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Response from template-based credential issuance
|
|
95
|
+
*/
|
|
96
|
+
interface TemplateCredentialResponse {
|
|
97
|
+
/** URI of the issued credential */
|
|
98
|
+
credentialUri: string;
|
|
99
|
+
/** URI of the boost template used */
|
|
100
|
+
boostUri: string;
|
|
101
|
+
[key: string]: unknown;
|
|
102
|
+
}
|
|
79
103
|
/**
|
|
80
104
|
* Verifiable Presentation Request Query types
|
|
81
105
|
*/
|
|
@@ -162,7 +186,7 @@ interface PostMessageResponse {
|
|
|
162
186
|
interface PendingRequest {
|
|
163
187
|
resolve: (value: unknown) => void;
|
|
164
188
|
reject: (error: LearnCardError) => void;
|
|
165
|
-
timeoutId:
|
|
189
|
+
timeoutId: ReturnType<typeof setTimeout>;
|
|
166
190
|
}
|
|
167
191
|
|
|
168
192
|
/**
|
|
@@ -253,10 +277,14 @@ declare class PartnerConnect {
|
|
|
253
277
|
/**
|
|
254
278
|
* Send a credential to the user's LearnCard wallet
|
|
255
279
|
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
280
|
+
* Supports two modes:
|
|
281
|
+
* 1. **Raw credential**: Pass a full verifiable credential object
|
|
282
|
+
* 2. **Template-based**: Pass `{ templateAlias, templateData }` to issue from a pre-configured boost template
|
|
258
283
|
*
|
|
259
|
-
* @
|
|
284
|
+
* @param input - Either a verifiable credential or a template-based input
|
|
285
|
+
* @returns Promise resolving to credential response
|
|
286
|
+
*
|
|
287
|
+
* @example Raw credential
|
|
260
288
|
* ```typescript
|
|
261
289
|
* const response = await learnCard.sendCredential({
|
|
262
290
|
* '@context': ['https://www.w3.org/2018/credentials/v1'],
|
|
@@ -265,8 +293,17 @@ declare class PartnerConnect {
|
|
|
265
293
|
* });
|
|
266
294
|
* console.log('Credential ID:', response.credentialId);
|
|
267
295
|
* ```
|
|
296
|
+
*
|
|
297
|
+
* @example Template-based (for App Store apps)
|
|
298
|
+
* ```typescript
|
|
299
|
+
* const response = await learnCard.sendCredential({
|
|
300
|
+
* templateAlias: 'achievement-badge',
|
|
301
|
+
* templateData: { score: '95', courseName: 'Web Dev 101' }
|
|
302
|
+
* });
|
|
303
|
+
* console.log('Credential URI:', response.credentialUri);
|
|
304
|
+
* ```
|
|
268
305
|
*/
|
|
269
|
-
sendCredential(
|
|
306
|
+
sendCredential(input: unknown | TemplateCredentialInput): Promise<SendCredentialResponse | TemplateCredentialResponse>;
|
|
270
307
|
/**
|
|
271
308
|
* Launch a feature in the LearnCard host application
|
|
272
309
|
*
|
|
@@ -358,6 +395,28 @@ declare class PartnerConnect {
|
|
|
358
395
|
* ```
|
|
359
396
|
*/
|
|
360
397
|
initiateTemplateIssue(templateId: string, draftRecipients?: string[]): Promise<TemplateIssueResponse>;
|
|
398
|
+
/**
|
|
399
|
+
* Send a generic event to be processed by the brain service on behalf of this app.
|
|
400
|
+
* This is used for backend-like operations such as issuing credentials.
|
|
401
|
+
*
|
|
402
|
+
* @param event - The event payload to send
|
|
403
|
+
* @returns Promise resolving to the event response
|
|
404
|
+
*
|
|
405
|
+
* @example
|
|
406
|
+
* ```typescript
|
|
407
|
+
* // Issue a credential to the current user
|
|
408
|
+
* const response = await learnCard.sendAppEvent({
|
|
409
|
+
* type: 'send-credential',
|
|
410
|
+
* templateAlias: 'achievement-badge',
|
|
411
|
+
* templateData: { score: '95' }
|
|
412
|
+
* });
|
|
413
|
+
*
|
|
414
|
+
* if (response.credentialUri) {
|
|
415
|
+
* console.log('Credential issued:', response.credentialUri);
|
|
416
|
+
* }
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
419
|
+
sendAppEvent(event: AppEvent): Promise<AppEventResponse>;
|
|
361
420
|
/**
|
|
362
421
|
* Clean up the SDK and remove event listeners
|
|
363
422
|
*/
|
|
@@ -380,4 +439,4 @@ declare class PartnerConnect {
|
|
|
380
439
|
*/
|
|
381
440
|
declare function createPartnerConnect(options: PartnerConnectOptions): PartnerConnect;
|
|
382
441
|
|
|
383
|
-
export { ConsentResponse, CredentialSearchResponse, CredentialSpecificResponse, ErrorCode, IdentityResponse, LearnCardError, PartnerConnect, PartnerConnectOptions, PendingRequest, PostMessageRequest, PostMessageResponse, SendCredentialResponse, TemplateIssueResponse, VPRQuery, VerifiablePresentationRequest, createPartnerConnect, createPartnerConnect as default };
|
|
442
|
+
export { ConsentResponse, CredentialSearchResponse, CredentialSpecificResponse, ErrorCode, IdentityResponse, LearnCardError, PartnerConnect, PartnerConnectOptions, PendingRequest, PostMessageRequest, PostMessageResponse, SendCredentialResponse, TemplateCredentialInput, TemplateCredentialResponse, TemplateIssueResponse, VPRQuery, VerifiablePresentationRequest, createPartnerConnect, createPartnerConnect as default };
|
|
@@ -26,7 +26,7 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
26
26
|
* 1. Check for `lc_host_override` query parameter (for staging/testing)
|
|
27
27
|
* 2. Fall back to first configured origin
|
|
28
28
|
* 3. Fall back to DEFAULT_HOST_ORIGIN
|
|
29
|
-
*
|
|
29
|
+
*
|
|
30
30
|
* This origin will be used for all outgoing messages and incoming message validation.
|
|
31
31
|
*/
|
|
32
32
|
configureActiveOrigin() {
|
|
@@ -60,7 +60,7 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
isOriginNativeApp(origin) {
|
|
63
|
-
return origin.startsWith("capacitor://") || origin.startsWith("ionic://") || origin.startsWith("https://localhost") || origin.startsWith("http://localhost") || origin.startsWith("http://127.0.0.1")
|
|
63
|
+
return origin.startsWith("capacitor://") || origin.startsWith("ionic://") || origin.startsWith("https://localhost") || origin.startsWith("http://localhost") || origin.startsWith("http://127.0.0.1");
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
66
|
* Check if an origin is in the configured whitelist
|
|
@@ -70,10 +70,10 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
72
|
* Check if an event origin is valid against the active host origin
|
|
73
|
-
*
|
|
73
|
+
*
|
|
74
74
|
* Security Rule: Incoming messages must exactly match the active host origin.
|
|
75
75
|
* This prevents malicious actors from spoofing origins via query parameters.
|
|
76
|
-
*
|
|
76
|
+
*
|
|
77
77
|
* @param eventOrigin - The origin from the MessageEvent
|
|
78
78
|
* @returns true if the origin is valid
|
|
79
79
|
*/
|
|
@@ -104,7 +104,9 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
104
104
|
if (data.type === "SUCCESS") {
|
|
105
105
|
pending.resolve(data.data);
|
|
106
106
|
} else if (data.type === "ERROR") {
|
|
107
|
-
pending.reject(
|
|
107
|
+
pending.reject(
|
|
108
|
+
data.error || { code: "UNKNOWN_ERROR", message: "An unknown error occurred" }
|
|
109
|
+
);
|
|
108
110
|
}
|
|
109
111
|
};
|
|
110
112
|
window.addEventListener("message", this.messageListener);
|
|
@@ -153,10 +155,10 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
153
155
|
}
|
|
154
156
|
/**
|
|
155
157
|
* Request user identity (Single Sign-On)
|
|
156
|
-
*
|
|
158
|
+
*
|
|
157
159
|
* @returns Promise resolving to user identity including DID and JWT token
|
|
158
160
|
* @throws {LearnCardError} When user is not authenticated or request fails
|
|
159
|
-
*
|
|
161
|
+
*
|
|
160
162
|
* @example
|
|
161
163
|
* ```typescript
|
|
162
164
|
* const identity = await learnCard.requestIdentity();
|
|
@@ -165,15 +167,21 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
165
167
|
* ```
|
|
166
168
|
*/
|
|
167
169
|
requestIdentity() {
|
|
168
|
-
return this.sendMessage("REQUEST_IDENTITY", {
|
|
170
|
+
return this.sendMessage("REQUEST_IDENTITY", {
|
|
171
|
+
challenge: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
|
|
172
|
+
});
|
|
169
173
|
}
|
|
170
174
|
/**
|
|
171
175
|
* Send a credential to the user's LearnCard wallet
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
176
|
+
*
|
|
177
|
+
* Supports two modes:
|
|
178
|
+
* 1. **Raw credential**: Pass a full verifiable credential object
|
|
179
|
+
* 2. **Template-based**: Pass `{ templateAlias, templateData }` to issue from a pre-configured boost template
|
|
180
|
+
*
|
|
181
|
+
* @param input - Either a verifiable credential or a template-based input
|
|
182
|
+
* @returns Promise resolving to credential response
|
|
183
|
+
*
|
|
184
|
+
* @example Raw credential
|
|
177
185
|
* ```typescript
|
|
178
186
|
* const response = await learnCard.sendCredential({
|
|
179
187
|
* '@context': ['https://www.w3.org/2018/credentials/v1'],
|
|
@@ -182,16 +190,33 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
182
190
|
* });
|
|
183
191
|
* console.log('Credential ID:', response.credentialId);
|
|
184
192
|
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example Template-based (for App Store apps)
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const response = await learnCard.sendCredential({
|
|
197
|
+
* templateAlias: 'achievement-badge',
|
|
198
|
+
* templateData: { score: '95', courseName: 'Web Dev 101' }
|
|
199
|
+
* });
|
|
200
|
+
* console.log('Credential URI:', response.credentialUri);
|
|
201
|
+
* ```
|
|
185
202
|
*/
|
|
186
|
-
sendCredential(
|
|
187
|
-
|
|
203
|
+
sendCredential(input) {
|
|
204
|
+
if (input && typeof input === "object" && "templateAlias" in input && typeof input.templateAlias === "string") {
|
|
205
|
+
const templateInput = input;
|
|
206
|
+
return this.sendAppEvent({
|
|
207
|
+
type: "send-credential",
|
|
208
|
+
templateAlias: templateInput.templateAlias,
|
|
209
|
+
templateData: templateInput.templateData
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return this.sendMessage("SEND_CREDENTIAL", { credential: input });
|
|
188
213
|
}
|
|
189
214
|
/**
|
|
190
215
|
* Launch a feature in the LearnCard host application
|
|
191
|
-
*
|
|
216
|
+
*
|
|
192
217
|
* @param featurePath - Path to the feature (e.g., '/ai/topics')
|
|
193
218
|
* @param initialPrompt - Optional initial prompt or data
|
|
194
|
-
*
|
|
219
|
+
*
|
|
195
220
|
* @example
|
|
196
221
|
* ```typescript
|
|
197
222
|
* await learnCard.launchFeature(
|
|
@@ -205,10 +230,10 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
205
230
|
}
|
|
206
231
|
/**
|
|
207
232
|
* Request credentials from the user's wallet using a query
|
|
208
|
-
*
|
|
233
|
+
*
|
|
209
234
|
* @param verifiablePresentationRequest - VPR with query criteria
|
|
210
235
|
* @returns Promise resolving to verifiable presentation
|
|
211
|
-
*
|
|
236
|
+
*
|
|
212
237
|
* @example
|
|
213
238
|
* ```typescript
|
|
214
239
|
* const response = await learnCard.askCredentialSearch({
|
|
@@ -222,7 +247,7 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
222
247
|
* challenge: 'challenge-123',
|
|
223
248
|
* domain: window.location.hostname
|
|
224
249
|
* });
|
|
225
|
-
*
|
|
250
|
+
*
|
|
226
251
|
* if (response.verifiablePresentation) {
|
|
227
252
|
* console.log('Received credentials:', response.verifiablePresentation.verifiableCredential);
|
|
228
253
|
* }
|
|
@@ -235,10 +260,10 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
235
260
|
}
|
|
236
261
|
/**
|
|
237
262
|
* Request a specific credential by ID
|
|
238
|
-
*
|
|
263
|
+
*
|
|
239
264
|
* @param credentialId - The ID of the credential to request
|
|
240
265
|
* @returns Promise resolving to the credential
|
|
241
|
-
*
|
|
266
|
+
*
|
|
242
267
|
* @example
|
|
243
268
|
* ```typescript
|
|
244
269
|
* const response = await learnCard.askCredentialSpecific('credential-id-123');
|
|
@@ -254,10 +279,10 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
254
279
|
}
|
|
255
280
|
/**
|
|
256
281
|
* Request user consent for permissions
|
|
257
|
-
*
|
|
282
|
+
*
|
|
258
283
|
* @param contractUri - URI of the consent contract
|
|
259
284
|
* @returns Promise resolving to consent response
|
|
260
|
-
*
|
|
285
|
+
*
|
|
261
286
|
* @example
|
|
262
287
|
* ```typescript
|
|
263
288
|
* const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123');
|
|
@@ -271,18 +296,18 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
271
296
|
}
|
|
272
297
|
/**
|
|
273
298
|
* Initiate a template-based credential issuance flow
|
|
274
|
-
*
|
|
299
|
+
*
|
|
275
300
|
* @param templateId - ID of the template/boost to issue
|
|
276
301
|
* @param draftRecipients - Optional array of recipient DIDs
|
|
277
302
|
* @returns Promise resolving to template issue response
|
|
278
|
-
*
|
|
303
|
+
*
|
|
279
304
|
* @example
|
|
280
305
|
* ```typescript
|
|
281
306
|
* const response = await learnCard.initiateTemplateIssue(
|
|
282
307
|
* 'lc:network:network.learncard.com/trpc:boost:xyz789',
|
|
283
308
|
* ['did:key:abc', 'did:key:def']
|
|
284
309
|
* );
|
|
285
|
-
*
|
|
310
|
+
*
|
|
286
311
|
* if (response.issued) {
|
|
287
312
|
* console.log('Template issued successfully');
|
|
288
313
|
* }
|
|
@@ -294,6 +319,30 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
294
319
|
draftRecipients: draftRecipients || []
|
|
295
320
|
});
|
|
296
321
|
}
|
|
322
|
+
/**
|
|
323
|
+
* Send a generic event to be processed by the brain service on behalf of this app.
|
|
324
|
+
* This is used for backend-like operations such as issuing credentials.
|
|
325
|
+
*
|
|
326
|
+
* @param event - The event payload to send
|
|
327
|
+
* @returns Promise resolving to the event response
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```typescript
|
|
331
|
+
* // Issue a credential to the current user
|
|
332
|
+
* const response = await learnCard.sendAppEvent({
|
|
333
|
+
* type: 'send-credential',
|
|
334
|
+
* templateAlias: 'achievement-badge',
|
|
335
|
+
* templateData: { score: '95' }
|
|
336
|
+
* });
|
|
337
|
+
*
|
|
338
|
+
* if (response.credentialUri) {
|
|
339
|
+
* console.log('Credential issued:', response.credentialUri);
|
|
340
|
+
* }
|
|
341
|
+
* ```
|
|
342
|
+
*/
|
|
343
|
+
sendAppEvent(event) {
|
|
344
|
+
return this.sendMessage("APP_EVENT", event);
|
|
345
|
+
}
|
|
297
346
|
/**
|
|
298
347
|
* Clean up the SDK and remove event listeners
|
|
299
348
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"partner-connect.esm.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * LearnCard Partner Connect SDK\n * \n * A Promise-based JavaScript utility for managing cross-origin message communication\n * between partner apps and the LearnCard host application.\n * \n * @example\n * ```typescript\n * import { createPartnerConnect } from '@learncard/partner-connect';\n * \n * const learnCard = createPartnerConnect({\n * hostOrigin: 'https://learncard.app'\n * });\n * \n * // Request user identity (SSO)\n * const identity = await learnCard.requestIdentity();\n * console.log('User DID:', identity.user.did);\n * ```\n */\n\nimport type {\n PartnerConnectOptions,\n IdentityResponse,\n SendCredentialResponse,\n VerifiablePresentationRequest,\n CredentialSearchResponse,\n CredentialSpecificResponse,\n ConsentResponse,\n TemplateIssueResponse,\n LearnCardError,\n PostMessageRequest,\n PostMessageResponse,\n PendingRequest,\n} from './types';\n\nexport type * from './types';\n\n/**\n * LearnCard Partner Connect SDK class\n */\nexport class PartnerConnect {\n /** Default host origin (security anchor) */\n public static readonly DEFAULT_HOST_ORIGIN = 'https://learncard.app';\n \n private hostOrigins: string[] = ['https://learncard.app'];\n private activeHostOrigin: string = 'https://learncard.app';\n private allowNativeAppOrigins: boolean = true;\n private protocol: string = 'LEARNCARD_V1';\n private requestTimeout: number = 30000;\n private pendingRequests: Map<string, PendingRequest>;\n private messageListener: ((event: MessageEvent) => void) | null = null;\n private isInitialized = false;\n\n constructor(options?: PartnerConnectOptions) {\n // Normalize hostOrigin to an array for whitelist validation\n const hostOrigin = options?.hostOrigin || PartnerConnect.DEFAULT_HOST_ORIGIN;\n this.hostOrigins = Array.isArray(hostOrigin) ? hostOrigin : [hostOrigin];\n \n this.protocol = options?.protocol || 'LEARNCARD_V1';\n this.requestTimeout = options?.requestTimeout || 30000;\n this.allowNativeAppOrigins = options?.allowNativeAppOrigins ?? true;\n this.pendingRequests = new Map();\n this.configureActiveOrigin();\n this.setupMessageListener();\n }\n\n /**\n * Configure the active host origin using the following hierarchy:\n * 1. Check for `lc_host_override` query parameter (for staging/testing)\n * 2. Fall back to first configured origin\n * 3. Fall back to DEFAULT_HOST_ORIGIN\n * \n * This origin will be used for all outgoing messages and incoming message validation.\n */\n private configureActiveOrigin(): void {\n if (typeof window === 'undefined') {\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n return;\n }\n\n try {\n // Check for lc_host_override query parameter\n const urlParams = new URLSearchParams(window.location.search);\n const hostOverride = urlParams.get('lc_host_override');\n\n if (hostOverride) {\n // Validate override against whitelist (if provided)\n if (this.hostOrigins.length > 0 && !this.isOriginInWhitelist(hostOverride)) {\n console.warn(\n '[LearnCard SDK] lc_host_override value is not in the configured whitelist:',\n hostOverride,\n 'Allowed:',\n this.hostOrigins\n );\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n } else {\n this.activeHostOrigin = hostOverride;\n console.log('[LearnCard SDK] Using lc_host_override:', hostOverride);\n }\n } else {\n // Use first configured origin or default\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n console.log('[LearnCard SDK] Using configured origin:', this.activeHostOrigin);\n }\n } catch (error) {\n console.error('[LearnCard SDK] Error configuring active origin:', error);\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n }\n }\n\n private isOriginNativeApp(origin: string): boolean {\n return origin.startsWith('capacitor://') || origin.startsWith('ionic://') || origin.startsWith('https://localhost') || origin.startsWith('http://localhost') || origin.startsWith('http://127.0.0.1') || origin.startsWith('http://192.168.1.164')\n }\n\n /**\n * Check if an origin is in the configured whitelist\n */\n private isOriginInWhitelist(origin: string): boolean {\n return this.hostOrigins.includes(origin) || (this.allowNativeAppOrigins && this.isOriginNativeApp(origin));\n }\n\n /**\n * Check if an event origin is valid against the active host origin\n * \n * Security Rule: Incoming messages must exactly match the active host origin.\n * This prevents malicious actors from spoofing origins via query parameters.\n * \n * @param eventOrigin - The origin from the MessageEvent\n * @returns true if the origin is valid\n */\n private isValidOrigin(eventOrigin: string): boolean {\n // STRICT: Exact match with active host origin only\n return eventOrigin === this.activeHostOrigin;\n }\n\n /**\n * Set up the central message listener to handle responses from the LearnCard host\n */\n private setupMessageListener(): void {\n if (typeof window === 'undefined') {\n throw new Error('PartnerConnect SDK can only be used in a browser environment');\n }\n\n this.messageListener = (event: MessageEvent) => {\n // SECURITY CHECK 1: Strict origin validation - must exactly match active host origin\n if (!this.isValidOrigin(event.origin)) {\n // Silently ignore messages from unauthorized origins\n return;\n }\n\n const data = event.data as PostMessageResponse;\n\n // SECURITY CHECK 2: Validate protocol and requestId\n if (data.protocol !== this.protocol || !data.requestId) {\n return;\n }\n\n // Look up the pending request\n const pending = this.pendingRequests.get(data.requestId);\n if (!pending) {\n return; // Ignore stale or unrecognized responses\n }\n\n // Clean up\n clearTimeout(pending.timeoutId);\n this.pendingRequests.delete(data.requestId);\n\n // Resolve or reject the promise\n if (data.type === 'SUCCESS') {\n pending.resolve(data.data);\n } else if (data.type === 'ERROR') {\n pending.reject(data.error || { code: 'UNKNOWN_ERROR', message: 'An unknown error occurred' });\n }\n };\n\n window.addEventListener('message', this.messageListener);\n this.isInitialized = true;\n }\n\n /**\n * Generate a unique request ID\n */\n private generateRequestId(action: string): string {\n return `${action}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n\n /**\n * Send a message to the parent window and return a Promise\n */\n private sendMessage<T = unknown>(action: string, payload?: unknown): Promise<T> {\n if (!this.isInitialized) {\n return Promise.reject({\n code: 'SDK_NOT_INITIALIZED',\n message: 'SDK is not initialized',\n } as LearnCardError);\n }\n\n return new Promise<T>((resolve, reject) => {\n const requestId = this.generateRequestId(action);\n\n // Set up timeout\n const timeoutId = setTimeout(() => {\n if (this.pendingRequests.has(requestId)) {\n this.pendingRequests.delete(requestId);\n reject({\n code: 'LC_TIMEOUT',\n message: `Request ${action} timed out after ${this.requestTimeout}ms`,\n } as LearnCardError);\n }\n }, this.requestTimeout);\n\n // Store the pending request\n this.pendingRequests.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeoutId,\n });\n\n // Construct the message\n const message: PostMessageRequest = {\n protocol: this.protocol,\n action,\n requestId,\n payload,\n };\n\n // Send to parent window with the active host origin (configured or overridden)\n window.parent.postMessage(message, this.activeHostOrigin);\n });\n }\n\n /**\n * Request user identity (Single Sign-On)\n * \n * @returns Promise resolving to user identity including DID and JWT token\n * @throws {LearnCardError} When user is not authenticated or request fails\n * \n * @example\n * ```typescript\n * const identity = await learnCard.requestIdentity();\n * console.log('User DID:', identity.user.did);\n * console.log('JWT Token:', identity.token);\n * ```\n */\n public requestIdentity(): Promise<IdentityResponse> {\n return this.sendMessage<IdentityResponse>('REQUEST_IDENTITY', { challenge: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}` });\n }\n\n /**\n * Send a credential to the user's LearnCard wallet\n * \n * @param credential - The verifiable credential to send\n * @returns Promise resolving to credential ID\n * \n * @example\n * ```typescript\n * const response = await learnCard.sendCredential({\n * '@context': ['https://www.w3.org/2018/credentials/v1'],\n * type: ['VerifiableCredential'],\n * credentialSubject: { id: 'did:example:123' }\n * });\n * console.log('Credential ID:', response.credentialId);\n * ```\n */\n public sendCredential(credential: unknown): Promise<SendCredentialResponse> {\n return this.sendMessage<SendCredentialResponse>('SEND_CREDENTIAL', { credential });\n }\n\n /**\n * Launch a feature in the LearnCard host application\n * \n * @param featurePath - Path to the feature (e.g., '/ai/topics')\n * @param initialPrompt - Optional initial prompt or data\n * \n * @example\n * ```typescript\n * await learnCard.launchFeature(\n * '/ai/topics?shortCircuitStep=newTopic',\n * 'Help me understand cryptography'\n * );\n * ```\n */\n public launchFeature(featurePath: string, initialPrompt?: string): Promise<void> {\n return this.sendMessage<void>('LAUNCH_FEATURE', { featurePath, initialPrompt });\n }\n\n /**\n * Request credentials from the user's wallet using a query\n * \n * @param verifiablePresentationRequest - VPR with query criteria\n * @returns Promise resolving to verifiable presentation\n * \n * @example\n * ```typescript\n * const response = await learnCard.askCredentialSearch({\n * query: [{\n * type: 'QueryByTitle',\n * credentialQuery: {\n * reason: 'We need to verify your skills',\n * title: 'JavaScript Expert'\n * }\n * }],\n * challenge: 'challenge-123',\n * domain: window.location.hostname\n * });\n * \n * if (response.verifiablePresentation) {\n * console.log('Received credentials:', response.verifiablePresentation.verifiableCredential);\n * }\n * ```\n */\n public askCredentialSearch(\n verifiablePresentationRequest: VerifiablePresentationRequest\n ): Promise<CredentialSearchResponse> {\n return this.sendMessage<CredentialSearchResponse>('ASK_CREDENTIAL_SEARCH', {\n verifiablePresentationRequest,\n });\n }\n\n /**\n * Request a specific credential by ID\n * \n * @param credentialId - The ID of the credential to request\n * @returns Promise resolving to the credential\n * \n * @example\n * ```typescript\n * const response = await learnCard.askCredentialSpecific('credential-id-123');\n * if (response.credential) {\n * console.log('Received credential:', response.credential);\n * }\n * ```\n */\n public askCredentialSpecific(credentialId: string): Promise<CredentialSpecificResponse> {\n return this.sendMessage<CredentialSpecificResponse>('ASK_CREDENTIAL_SPECIFIC', {\n credentialId,\n });\n }\n\n /**\n * Request user consent for permissions\n * \n * @param contractUri - URI of the consent contract\n * @returns Promise resolving to consent response\n * \n * @example\n * ```typescript\n * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123');\n * if (response.granted) {\n * console.log('User granted consent');\n * }\n * ```\n */\n public requestConsent(contractUri: string): Promise<ConsentResponse> {\n return this.sendMessage<ConsentResponse>('REQUEST_CONSENT', { contractUri });\n }\n\n /**\n * Initiate a template-based credential issuance flow\n * \n * @param templateId - ID of the template/boost to issue\n * @param draftRecipients - Optional array of recipient DIDs\n * @returns Promise resolving to template issue response\n * \n * @example\n * ```typescript\n * const response = await learnCard.initiateTemplateIssue(\n * 'lc:network:network.learncard.com/trpc:boost:xyz789',\n * ['did:key:abc', 'did:key:def']\n * );\n * \n * if (response.issued) {\n * console.log('Template issued successfully');\n * }\n * ```\n */\n public initiateTemplateIssue(\n templateId: string,\n draftRecipients?: string[]\n ): Promise<TemplateIssueResponse> {\n return this.sendMessage<TemplateIssueResponse>('INITIATE_TEMPLATE_ISSUE', {\n templateId,\n draftRecipients: draftRecipients || [],\n });\n }\n\n /**\n * Clean up the SDK and remove event listeners\n */\n public destroy(): void {\n if (this.messageListener) {\n window.removeEventListener('message', this.messageListener);\n this.messageListener = null;\n }\n\n // Reject all pending requests\n for (const [requestId, pending] of this.pendingRequests.entries()) {\n clearTimeout(pending.timeoutId);\n pending.reject({\n code: 'SDK_DESTROYED',\n message: 'SDK was destroyed before request completed',\n });\n }\n\n this.pendingRequests.clear();\n this.isInitialized = false;\n }\n}\n\n/**\n * Factory function to create a PartnerConnect instance\n * \n * @param options - Configuration options\n * @returns PartnerConnect instance\n * \n * @example\n * ```typescript\n * const learnCard = createPartnerConnect({\n * hostOrigin: 'https://learncard.app',\n * protocol: 'LEARNCARD_V1',\n * requestTimeout: 30000\n * });\n * ```\n */\nexport function createPartnerConnect(options: PartnerConnectOptions): PartnerConnect {\n return new PartnerConnect(options);\n}\n\n// Default export for convenience\nexport default createPartnerConnect;\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"partner-connect.esm.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * LearnCard Partner Connect SDK\n *\n * A Promise-based JavaScript utility for managing cross-origin message communication\n * between partner apps and the LearnCard host application.\n *\n * @example\n * ```typescript\n * import { createPartnerConnect } from '@learncard/partner-connect';\n *\n * const learnCard = createPartnerConnect({\n * hostOrigin: 'https://learncard.app'\n * });\n *\n * // Request user identity (SSO)\n * const identity = await learnCard.requestIdentity();\n * console.log('User DID:', identity.user.did);\n * ```\n */\n\nimport type {\n PartnerConnectOptions,\n IdentityResponse,\n SendCredentialResponse,\n TemplateCredentialInput,\n TemplateCredentialResponse,\n VerifiablePresentationRequest,\n CredentialSearchResponse,\n CredentialSpecificResponse,\n ConsentResponse,\n TemplateIssueResponse,\n AppEvent,\n AppEventResponse,\n LearnCardError,\n PostMessageRequest,\n PostMessageResponse,\n PendingRequest,\n} from './types';\n\nexport type * from './types';\n\n/**\n * LearnCard Partner Connect SDK class\n */\nexport class PartnerConnect {\n /** Default host origin (security anchor) */\n public static readonly DEFAULT_HOST_ORIGIN = 'https://learncard.app';\n\n private hostOrigins: string[] = ['https://learncard.app'];\n private activeHostOrigin: string = 'https://learncard.app';\n private allowNativeAppOrigins: boolean = true;\n private protocol: string = 'LEARNCARD_V1';\n private requestTimeout: number = 30000;\n private pendingRequests: Map<string, PendingRequest>;\n private messageListener: ((event: MessageEvent) => void) | null = null;\n private isInitialized = false;\n\n constructor(options?: PartnerConnectOptions) {\n // Normalize hostOrigin to an array for whitelist validation\n const hostOrigin = options?.hostOrigin || PartnerConnect.DEFAULT_HOST_ORIGIN;\n this.hostOrigins = Array.isArray(hostOrigin) ? hostOrigin : [hostOrigin];\n\n this.protocol = options?.protocol || 'LEARNCARD_V1';\n this.requestTimeout = options?.requestTimeout || 30000;\n this.allowNativeAppOrigins = options?.allowNativeAppOrigins ?? true;\n this.pendingRequests = new Map();\n this.configureActiveOrigin();\n this.setupMessageListener();\n }\n\n /**\n * Configure the active host origin using the following hierarchy:\n * 1. Check for `lc_host_override` query parameter (for staging/testing)\n * 2. Fall back to first configured origin\n * 3. Fall back to DEFAULT_HOST_ORIGIN\n *\n * This origin will be used for all outgoing messages and incoming message validation.\n */\n private configureActiveOrigin(): void {\n if (typeof window === 'undefined') {\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n return;\n }\n\n try {\n // Check for lc_host_override query parameter\n const urlParams = new URLSearchParams(window.location.search);\n const hostOverride = urlParams.get('lc_host_override');\n\n if (hostOverride) {\n // Validate override against whitelist (if provided)\n if (this.hostOrigins.length > 0 && !this.isOriginInWhitelist(hostOverride)) {\n console.warn(\n '[LearnCard SDK] lc_host_override value is not in the configured whitelist:',\n hostOverride,\n 'Allowed:',\n this.hostOrigins\n );\n this.activeHostOrigin =\n this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n } else {\n this.activeHostOrigin = hostOverride;\n console.log('[LearnCard SDK] Using lc_host_override:', hostOverride);\n }\n } else {\n // Use first configured origin or default\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n console.log('[LearnCard SDK] Using configured origin:', this.activeHostOrigin);\n }\n } catch (error) {\n console.error('[LearnCard SDK] Error configuring active origin:', error);\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n }\n }\n\n private isOriginNativeApp(origin: string): boolean {\n return (\n origin.startsWith('capacitor://') ||\n origin.startsWith('ionic://') ||\n origin.startsWith('https://localhost') ||\n origin.startsWith('http://localhost') ||\n origin.startsWith('http://127.0.0.1')\n );\n }\n\n /**\n * Check if an origin is in the configured whitelist\n */\n private isOriginInWhitelist(origin: string): boolean {\n return (\n this.hostOrigins.includes(origin) ||\n (this.allowNativeAppOrigins && this.isOriginNativeApp(origin))\n );\n }\n\n /**\n * Check if an event origin is valid against the active host origin\n *\n * Security Rule: Incoming messages must exactly match the active host origin.\n * This prevents malicious actors from spoofing origins via query parameters.\n *\n * @param eventOrigin - The origin from the MessageEvent\n * @returns true if the origin is valid\n */\n private isValidOrigin(eventOrigin: string): boolean {\n // STRICT: Exact match with active host origin only\n return eventOrigin === this.activeHostOrigin;\n }\n\n /**\n * Set up the central message listener to handle responses from the LearnCard host\n */\n private setupMessageListener(): void {\n if (typeof window === 'undefined') {\n throw new Error('PartnerConnect SDK can only be used in a browser environment');\n }\n\n this.messageListener = (event: MessageEvent) => {\n // SECURITY CHECK 1: Strict origin validation - must exactly match active host origin\n if (!this.isValidOrigin(event.origin)) {\n // Silently ignore messages from unauthorized origins\n return;\n }\n\n const data = event.data as PostMessageResponse;\n\n // SECURITY CHECK 2: Validate protocol and requestId\n if (data.protocol !== this.protocol || !data.requestId) {\n return;\n }\n\n // Look up the pending request\n const pending = this.pendingRequests.get(data.requestId);\n if (!pending) {\n return; // Ignore stale or unrecognized responses\n }\n\n // Clean up\n clearTimeout(pending.timeoutId);\n this.pendingRequests.delete(data.requestId);\n\n // Resolve or reject the promise\n if (data.type === 'SUCCESS') {\n pending.resolve(data.data);\n } else if (data.type === 'ERROR') {\n pending.reject(\n data.error || { code: 'UNKNOWN_ERROR', message: 'An unknown error occurred' }\n );\n }\n };\n\n window.addEventListener('message', this.messageListener);\n this.isInitialized = true;\n }\n\n /**\n * Generate a unique request ID\n */\n private generateRequestId(action: string): string {\n return `${action}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n\n /**\n * Send a message to the parent window and return a Promise\n */\n private sendMessage<T = unknown>(action: string, payload?: unknown): Promise<T> {\n if (!this.isInitialized) {\n return Promise.reject({\n code: 'SDK_NOT_INITIALIZED',\n message: 'SDK is not initialized',\n } as LearnCardError);\n }\n\n return new Promise<T>((resolve, reject) => {\n const requestId = this.generateRequestId(action);\n\n // Set up timeout\n const timeoutId = setTimeout(() => {\n if (this.pendingRequests.has(requestId)) {\n this.pendingRequests.delete(requestId);\n reject({\n code: 'LC_TIMEOUT',\n message: `Request ${action} timed out after ${this.requestTimeout}ms`,\n } as LearnCardError);\n }\n }, this.requestTimeout);\n\n // Store the pending request\n this.pendingRequests.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeoutId,\n });\n\n // Construct the message\n const message: PostMessageRequest = {\n protocol: this.protocol,\n action,\n requestId,\n payload,\n };\n\n // Send to parent window with the active host origin (configured or overridden)\n window.parent.postMessage(message, this.activeHostOrigin);\n });\n }\n\n /**\n * Request user identity (Single Sign-On)\n *\n * @returns Promise resolving to user identity including DID and JWT token\n * @throws {LearnCardError} When user is not authenticated or request fails\n *\n * @example\n * ```typescript\n * const identity = await learnCard.requestIdentity();\n * console.log('User DID:', identity.user.did);\n * console.log('JWT Token:', identity.token);\n * ```\n */\n public requestIdentity(): Promise<IdentityResponse> {\n return this.sendMessage<IdentityResponse>('REQUEST_IDENTITY', {\n challenge: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,\n });\n }\n\n /**\n * Send a credential to the user's LearnCard wallet\n *\n * Supports two modes:\n * 1. **Raw credential**: Pass a full verifiable credential object\n * 2. **Template-based**: Pass `{ templateAlias, templateData }` to issue from a pre-configured boost template\n *\n * @param input - Either a verifiable credential or a template-based input\n * @returns Promise resolving to credential response\n *\n * @example Raw credential\n * ```typescript\n * const response = await learnCard.sendCredential({\n * '@context': ['https://www.w3.org/2018/credentials/v1'],\n * type: ['VerifiableCredential'],\n * credentialSubject: { id: 'did:example:123' }\n * });\n * console.log('Credential ID:', response.credentialId);\n * ```\n *\n * @example Template-based (for App Store apps)\n * ```typescript\n * const response = await learnCard.sendCredential({\n * templateAlias: 'achievement-badge',\n * templateData: { score: '95', courseName: 'Web Dev 101' }\n * });\n * console.log('Credential URI:', response.credentialUri);\n * ```\n */\n public sendCredential(\n input: unknown | TemplateCredentialInput\n ): Promise<SendCredentialResponse | TemplateCredentialResponse> {\n if (\n input &&\n typeof input === 'object' &&\n 'templateAlias' in input &&\n typeof (input as TemplateCredentialInput).templateAlias === 'string'\n ) {\n const templateInput = input as TemplateCredentialInput;\n\n return this.sendAppEvent({\n type: 'send-credential',\n templateAlias: templateInput.templateAlias,\n templateData: templateInput.templateData,\n }) as Promise<TemplateCredentialResponse>;\n }\n\n return this.sendMessage<SendCredentialResponse>('SEND_CREDENTIAL', { credential: input });\n }\n\n /**\n * Launch a feature in the LearnCard host application\n *\n * @param featurePath - Path to the feature (e.g., '/ai/topics')\n * @param initialPrompt - Optional initial prompt or data\n *\n * @example\n * ```typescript\n * await learnCard.launchFeature(\n * '/ai/topics?shortCircuitStep=newTopic',\n * 'Help me understand cryptography'\n * );\n * ```\n */\n public launchFeature(featurePath: string, initialPrompt?: string): Promise<void> {\n return this.sendMessage<void>('LAUNCH_FEATURE', { featurePath, initialPrompt });\n }\n\n /**\n * Request credentials from the user's wallet using a query\n *\n * @param verifiablePresentationRequest - VPR with query criteria\n * @returns Promise resolving to verifiable presentation\n *\n * @example\n * ```typescript\n * const response = await learnCard.askCredentialSearch({\n * query: [{\n * type: 'QueryByTitle',\n * credentialQuery: {\n * reason: 'We need to verify your skills',\n * title: 'JavaScript Expert'\n * }\n * }],\n * challenge: 'challenge-123',\n * domain: window.location.hostname\n * });\n *\n * if (response.verifiablePresentation) {\n * console.log('Received credentials:', response.verifiablePresentation.verifiableCredential);\n * }\n * ```\n */\n public askCredentialSearch(\n verifiablePresentationRequest: VerifiablePresentationRequest\n ): Promise<CredentialSearchResponse> {\n return this.sendMessage<CredentialSearchResponse>('ASK_CREDENTIAL_SEARCH', {\n verifiablePresentationRequest,\n });\n }\n\n /**\n * Request a specific credential by ID\n *\n * @param credentialId - The ID of the credential to request\n * @returns Promise resolving to the credential\n *\n * @example\n * ```typescript\n * const response = await learnCard.askCredentialSpecific('credential-id-123');\n * if (response.credential) {\n * console.log('Received credential:', response.credential);\n * }\n * ```\n */\n public askCredentialSpecific(credentialId: string): Promise<CredentialSpecificResponse> {\n return this.sendMessage<CredentialSpecificResponse>('ASK_CREDENTIAL_SPECIFIC', {\n credentialId,\n });\n }\n\n /**\n * Request user consent for permissions\n *\n * @param contractUri - URI of the consent contract\n * @returns Promise resolving to consent response\n *\n * @example\n * ```typescript\n * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123');\n * if (response.granted) {\n * console.log('User granted consent');\n * }\n * ```\n */\n public requestConsent(contractUri: string): Promise<ConsentResponse> {\n return this.sendMessage<ConsentResponse>('REQUEST_CONSENT', { contractUri });\n }\n\n /**\n * Initiate a template-based credential issuance flow\n *\n * @param templateId - ID of the template/boost to issue\n * @param draftRecipients - Optional array of recipient DIDs\n * @returns Promise resolving to template issue response\n *\n * @example\n * ```typescript\n * const response = await learnCard.initiateTemplateIssue(\n * 'lc:network:network.learncard.com/trpc:boost:xyz789',\n * ['did:key:abc', 'did:key:def']\n * );\n *\n * if (response.issued) {\n * console.log('Template issued successfully');\n * }\n * ```\n */\n public initiateTemplateIssue(\n templateId: string,\n draftRecipients?: string[]\n ): Promise<TemplateIssueResponse> {\n return this.sendMessage<TemplateIssueResponse>('INITIATE_TEMPLATE_ISSUE', {\n templateId,\n draftRecipients: draftRecipients || [],\n });\n }\n\n /**\n * Send a generic event to be processed by the brain service on behalf of this app.\n * This is used for backend-like operations such as issuing credentials.\n *\n * @param event - The event payload to send\n * @returns Promise resolving to the event response\n *\n * @example\n * ```typescript\n * // Issue a credential to the current user\n * const response = await learnCard.sendAppEvent({\n * type: 'send-credential',\n * templateAlias: 'achievement-badge',\n * templateData: { score: '95' }\n * });\n *\n * if (response.credentialUri) {\n * console.log('Credential issued:', response.credentialUri);\n * }\n * ```\n */\n public sendAppEvent(event: AppEvent): Promise<AppEventResponse> {\n return this.sendMessage<AppEventResponse>('APP_EVENT', event);\n }\n\n /**\n * Clean up the SDK and remove event listeners\n */\n public destroy(): void {\n if (this.messageListener) {\n window.removeEventListener('message', this.messageListener);\n this.messageListener = null;\n }\n\n // Reject all pending requests\n for (const [requestId, pending] of this.pendingRequests.entries()) {\n clearTimeout(pending.timeoutId);\n pending.reject({\n code: 'SDK_DESTROYED',\n message: 'SDK was destroyed before request completed',\n });\n }\n\n this.pendingRequests.clear();\n this.isInitialized = false;\n }\n}\n\n/**\n * Factory function to create a PartnerConnect instance\n *\n * @param options - Configuration options\n * @returns PartnerConnect instance\n *\n * @example\n * ```typescript\n * const learnCard = createPartnerConnect({\n * hostOrigin: 'https://learncard.app',\n * protocol: 'LEARNCARD_V1',\n * requestTimeout: 30000\n * });\n * ```\n */\nexport function createPartnerConnect(options: PartnerConnectOptions): PartnerConnect {\n return new PartnerConnect(options);\n}\n\n// Default export for convenience\nexport default createPartnerConnect;\n"],"names":[],"mappings":"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"}
|
package/dist/partner-connect.js
CHANGED
|
@@ -30,7 +30,7 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
30
30
|
* 1. Check for `lc_host_override` query parameter (for staging/testing)
|
|
31
31
|
* 2. Fall back to first configured origin
|
|
32
32
|
* 3. Fall back to DEFAULT_HOST_ORIGIN
|
|
33
|
-
*
|
|
33
|
+
*
|
|
34
34
|
* This origin will be used for all outgoing messages and incoming message validation.
|
|
35
35
|
*/
|
|
36
36
|
configureActiveOrigin() {
|
|
@@ -64,7 +64,7 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
isOriginNativeApp(origin) {
|
|
67
|
-
return origin.startsWith("capacitor://") || origin.startsWith("ionic://") || origin.startsWith("https://localhost") || origin.startsWith("http://localhost") || origin.startsWith("http://127.0.0.1")
|
|
67
|
+
return origin.startsWith("capacitor://") || origin.startsWith("ionic://") || origin.startsWith("https://localhost") || origin.startsWith("http://localhost") || origin.startsWith("http://127.0.0.1");
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
70
|
* Check if an origin is in the configured whitelist
|
|
@@ -74,10 +74,10 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
76
|
* Check if an event origin is valid against the active host origin
|
|
77
|
-
*
|
|
77
|
+
*
|
|
78
78
|
* Security Rule: Incoming messages must exactly match the active host origin.
|
|
79
79
|
* This prevents malicious actors from spoofing origins via query parameters.
|
|
80
|
-
*
|
|
80
|
+
*
|
|
81
81
|
* @param eventOrigin - The origin from the MessageEvent
|
|
82
82
|
* @returns true if the origin is valid
|
|
83
83
|
*/
|
|
@@ -108,7 +108,9 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
108
108
|
if (data.type === "SUCCESS") {
|
|
109
109
|
pending.resolve(data.data);
|
|
110
110
|
} else if (data.type === "ERROR") {
|
|
111
|
-
pending.reject(
|
|
111
|
+
pending.reject(
|
|
112
|
+
data.error || { code: "UNKNOWN_ERROR", message: "An unknown error occurred" }
|
|
113
|
+
);
|
|
112
114
|
}
|
|
113
115
|
};
|
|
114
116
|
window.addEventListener("message", this.messageListener);
|
|
@@ -157,10 +159,10 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
157
159
|
}
|
|
158
160
|
/**
|
|
159
161
|
* Request user identity (Single Sign-On)
|
|
160
|
-
*
|
|
162
|
+
*
|
|
161
163
|
* @returns Promise resolving to user identity including DID and JWT token
|
|
162
164
|
* @throws {LearnCardError} When user is not authenticated or request fails
|
|
163
|
-
*
|
|
165
|
+
*
|
|
164
166
|
* @example
|
|
165
167
|
* ```typescript
|
|
166
168
|
* const identity = await learnCard.requestIdentity();
|
|
@@ -169,15 +171,21 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
169
171
|
* ```
|
|
170
172
|
*/
|
|
171
173
|
requestIdentity() {
|
|
172
|
-
return this.sendMessage("REQUEST_IDENTITY", {
|
|
174
|
+
return this.sendMessage("REQUEST_IDENTITY", {
|
|
175
|
+
challenge: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`
|
|
176
|
+
});
|
|
173
177
|
}
|
|
174
178
|
/**
|
|
175
179
|
* Send a credential to the user's LearnCard wallet
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
180
|
+
*
|
|
181
|
+
* Supports two modes:
|
|
182
|
+
* 1. **Raw credential**: Pass a full verifiable credential object
|
|
183
|
+
* 2. **Template-based**: Pass `{ templateAlias, templateData }` to issue from a pre-configured boost template
|
|
184
|
+
*
|
|
185
|
+
* @param input - Either a verifiable credential or a template-based input
|
|
186
|
+
* @returns Promise resolving to credential response
|
|
187
|
+
*
|
|
188
|
+
* @example Raw credential
|
|
181
189
|
* ```typescript
|
|
182
190
|
* const response = await learnCard.sendCredential({
|
|
183
191
|
* '@context': ['https://www.w3.org/2018/credentials/v1'],
|
|
@@ -186,16 +194,33 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
186
194
|
* });
|
|
187
195
|
* console.log('Credential ID:', response.credentialId);
|
|
188
196
|
* ```
|
|
197
|
+
*
|
|
198
|
+
* @example Template-based (for App Store apps)
|
|
199
|
+
* ```typescript
|
|
200
|
+
* const response = await learnCard.sendCredential({
|
|
201
|
+
* templateAlias: 'achievement-badge',
|
|
202
|
+
* templateData: { score: '95', courseName: 'Web Dev 101' }
|
|
203
|
+
* });
|
|
204
|
+
* console.log('Credential URI:', response.credentialUri);
|
|
205
|
+
* ```
|
|
189
206
|
*/
|
|
190
|
-
sendCredential(
|
|
191
|
-
|
|
207
|
+
sendCredential(input) {
|
|
208
|
+
if (input && typeof input === "object" && "templateAlias" in input && typeof input.templateAlias === "string") {
|
|
209
|
+
const templateInput = input;
|
|
210
|
+
return this.sendAppEvent({
|
|
211
|
+
type: "send-credential",
|
|
212
|
+
templateAlias: templateInput.templateAlias,
|
|
213
|
+
templateData: templateInput.templateData
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return this.sendMessage("SEND_CREDENTIAL", { credential: input });
|
|
192
217
|
}
|
|
193
218
|
/**
|
|
194
219
|
* Launch a feature in the LearnCard host application
|
|
195
|
-
*
|
|
220
|
+
*
|
|
196
221
|
* @param featurePath - Path to the feature (e.g., '/ai/topics')
|
|
197
222
|
* @param initialPrompt - Optional initial prompt or data
|
|
198
|
-
*
|
|
223
|
+
*
|
|
199
224
|
* @example
|
|
200
225
|
* ```typescript
|
|
201
226
|
* await learnCard.launchFeature(
|
|
@@ -209,10 +234,10 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
209
234
|
}
|
|
210
235
|
/**
|
|
211
236
|
* Request credentials from the user's wallet using a query
|
|
212
|
-
*
|
|
237
|
+
*
|
|
213
238
|
* @param verifiablePresentationRequest - VPR with query criteria
|
|
214
239
|
* @returns Promise resolving to verifiable presentation
|
|
215
|
-
*
|
|
240
|
+
*
|
|
216
241
|
* @example
|
|
217
242
|
* ```typescript
|
|
218
243
|
* const response = await learnCard.askCredentialSearch({
|
|
@@ -226,7 +251,7 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
226
251
|
* challenge: 'challenge-123',
|
|
227
252
|
* domain: window.location.hostname
|
|
228
253
|
* });
|
|
229
|
-
*
|
|
254
|
+
*
|
|
230
255
|
* if (response.verifiablePresentation) {
|
|
231
256
|
* console.log('Received credentials:', response.verifiablePresentation.verifiableCredential);
|
|
232
257
|
* }
|
|
@@ -239,10 +264,10 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
239
264
|
}
|
|
240
265
|
/**
|
|
241
266
|
* Request a specific credential by ID
|
|
242
|
-
*
|
|
267
|
+
*
|
|
243
268
|
* @param credentialId - The ID of the credential to request
|
|
244
269
|
* @returns Promise resolving to the credential
|
|
245
|
-
*
|
|
270
|
+
*
|
|
246
271
|
* @example
|
|
247
272
|
* ```typescript
|
|
248
273
|
* const response = await learnCard.askCredentialSpecific('credential-id-123');
|
|
@@ -258,10 +283,10 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
258
283
|
}
|
|
259
284
|
/**
|
|
260
285
|
* Request user consent for permissions
|
|
261
|
-
*
|
|
286
|
+
*
|
|
262
287
|
* @param contractUri - URI of the consent contract
|
|
263
288
|
* @returns Promise resolving to consent response
|
|
264
|
-
*
|
|
289
|
+
*
|
|
265
290
|
* @example
|
|
266
291
|
* ```typescript
|
|
267
292
|
* const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123');
|
|
@@ -275,18 +300,18 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
275
300
|
}
|
|
276
301
|
/**
|
|
277
302
|
* Initiate a template-based credential issuance flow
|
|
278
|
-
*
|
|
303
|
+
*
|
|
279
304
|
* @param templateId - ID of the template/boost to issue
|
|
280
305
|
* @param draftRecipients - Optional array of recipient DIDs
|
|
281
306
|
* @returns Promise resolving to template issue response
|
|
282
|
-
*
|
|
307
|
+
*
|
|
283
308
|
* @example
|
|
284
309
|
* ```typescript
|
|
285
310
|
* const response = await learnCard.initiateTemplateIssue(
|
|
286
311
|
* 'lc:network:network.learncard.com/trpc:boost:xyz789',
|
|
287
312
|
* ['did:key:abc', 'did:key:def']
|
|
288
313
|
* );
|
|
289
|
-
*
|
|
314
|
+
*
|
|
290
315
|
* if (response.issued) {
|
|
291
316
|
* console.log('Template issued successfully');
|
|
292
317
|
* }
|
|
@@ -298,6 +323,30 @@ const _PartnerConnect = class _PartnerConnect {
|
|
|
298
323
|
draftRecipients: draftRecipients || []
|
|
299
324
|
});
|
|
300
325
|
}
|
|
326
|
+
/**
|
|
327
|
+
* Send a generic event to be processed by the brain service on behalf of this app.
|
|
328
|
+
* This is used for backend-like operations such as issuing credentials.
|
|
329
|
+
*
|
|
330
|
+
* @param event - The event payload to send
|
|
331
|
+
* @returns Promise resolving to the event response
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```typescript
|
|
335
|
+
* // Issue a credential to the current user
|
|
336
|
+
* const response = await learnCard.sendAppEvent({
|
|
337
|
+
* type: 'send-credential',
|
|
338
|
+
* templateAlias: 'achievement-badge',
|
|
339
|
+
* templateData: { score: '95' }
|
|
340
|
+
* });
|
|
341
|
+
*
|
|
342
|
+
* if (response.credentialUri) {
|
|
343
|
+
* console.log('Credential issued:', response.credentialUri);
|
|
344
|
+
* }
|
|
345
|
+
* ```
|
|
346
|
+
*/
|
|
347
|
+
sendAppEvent(event) {
|
|
348
|
+
return this.sendMessage("APP_EVENT", event);
|
|
349
|
+
}
|
|
301
350
|
/**
|
|
302
351
|
* Clean up the SDK and remove event listeners
|
|
303
352
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"partner-connect.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * LearnCard Partner Connect SDK\n * \n * A Promise-based JavaScript utility for managing cross-origin message communication\n * between partner apps and the LearnCard host application.\n * \n * @example\n * ```typescript\n * import { createPartnerConnect } from '@learncard/partner-connect';\n * \n * const learnCard = createPartnerConnect({\n * hostOrigin: 'https://learncard.app'\n * });\n * \n * // Request user identity (SSO)\n * const identity = await learnCard.requestIdentity();\n * console.log('User DID:', identity.user.did);\n * ```\n */\n\nimport type {\n PartnerConnectOptions,\n IdentityResponse,\n SendCredentialResponse,\n VerifiablePresentationRequest,\n CredentialSearchResponse,\n CredentialSpecificResponse,\n ConsentResponse,\n TemplateIssueResponse,\n LearnCardError,\n PostMessageRequest,\n PostMessageResponse,\n PendingRequest,\n} from './types';\n\nexport type * from './types';\n\n/**\n * LearnCard Partner Connect SDK class\n */\nexport class PartnerConnect {\n /** Default host origin (security anchor) */\n public static readonly DEFAULT_HOST_ORIGIN = 'https://learncard.app';\n \n private hostOrigins: string[] = ['https://learncard.app'];\n private activeHostOrigin: string = 'https://learncard.app';\n private allowNativeAppOrigins: boolean = true;\n private protocol: string = 'LEARNCARD_V1';\n private requestTimeout: number = 30000;\n private pendingRequests: Map<string, PendingRequest>;\n private messageListener: ((event: MessageEvent) => void) | null = null;\n private isInitialized = false;\n\n constructor(options?: PartnerConnectOptions) {\n // Normalize hostOrigin to an array for whitelist validation\n const hostOrigin = options?.hostOrigin || PartnerConnect.DEFAULT_HOST_ORIGIN;\n this.hostOrigins = Array.isArray(hostOrigin) ? hostOrigin : [hostOrigin];\n \n this.protocol = options?.protocol || 'LEARNCARD_V1';\n this.requestTimeout = options?.requestTimeout || 30000;\n this.allowNativeAppOrigins = options?.allowNativeAppOrigins ?? true;\n this.pendingRequests = new Map();\n this.configureActiveOrigin();\n this.setupMessageListener();\n }\n\n /**\n * Configure the active host origin using the following hierarchy:\n * 1. Check for `lc_host_override` query parameter (for staging/testing)\n * 2. Fall back to first configured origin\n * 3. Fall back to DEFAULT_HOST_ORIGIN\n * \n * This origin will be used for all outgoing messages and incoming message validation.\n */\n private configureActiveOrigin(): void {\n if (typeof window === 'undefined') {\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n return;\n }\n\n try {\n // Check for lc_host_override query parameter\n const urlParams = new URLSearchParams(window.location.search);\n const hostOverride = urlParams.get('lc_host_override');\n\n if (hostOverride) {\n // Validate override against whitelist (if provided)\n if (this.hostOrigins.length > 0 && !this.isOriginInWhitelist(hostOverride)) {\n console.warn(\n '[LearnCard SDK] lc_host_override value is not in the configured whitelist:',\n hostOverride,\n 'Allowed:',\n this.hostOrigins\n );\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n } else {\n this.activeHostOrigin = hostOverride;\n console.log('[LearnCard SDK] Using lc_host_override:', hostOverride);\n }\n } else {\n // Use first configured origin or default\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n console.log('[LearnCard SDK] Using configured origin:', this.activeHostOrigin);\n }\n } catch (error) {\n console.error('[LearnCard SDK] Error configuring active origin:', error);\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n }\n }\n\n private isOriginNativeApp(origin: string): boolean {\n return origin.startsWith('capacitor://') || origin.startsWith('ionic://') || origin.startsWith('https://localhost') || origin.startsWith('http://localhost') || origin.startsWith('http://127.0.0.1') || origin.startsWith('http://192.168.1.164')\n }\n\n /**\n * Check if an origin is in the configured whitelist\n */\n private isOriginInWhitelist(origin: string): boolean {\n return this.hostOrigins.includes(origin) || (this.allowNativeAppOrigins && this.isOriginNativeApp(origin));\n }\n\n /**\n * Check if an event origin is valid against the active host origin\n * \n * Security Rule: Incoming messages must exactly match the active host origin.\n * This prevents malicious actors from spoofing origins via query parameters.\n * \n * @param eventOrigin - The origin from the MessageEvent\n * @returns true if the origin is valid\n */\n private isValidOrigin(eventOrigin: string): boolean {\n // STRICT: Exact match with active host origin only\n return eventOrigin === this.activeHostOrigin;\n }\n\n /**\n * Set up the central message listener to handle responses from the LearnCard host\n */\n private setupMessageListener(): void {\n if (typeof window === 'undefined') {\n throw new Error('PartnerConnect SDK can only be used in a browser environment');\n }\n\n this.messageListener = (event: MessageEvent) => {\n // SECURITY CHECK 1: Strict origin validation - must exactly match active host origin\n if (!this.isValidOrigin(event.origin)) {\n // Silently ignore messages from unauthorized origins\n return;\n }\n\n const data = event.data as PostMessageResponse;\n\n // SECURITY CHECK 2: Validate protocol and requestId\n if (data.protocol !== this.protocol || !data.requestId) {\n return;\n }\n\n // Look up the pending request\n const pending = this.pendingRequests.get(data.requestId);\n if (!pending) {\n return; // Ignore stale or unrecognized responses\n }\n\n // Clean up\n clearTimeout(pending.timeoutId);\n this.pendingRequests.delete(data.requestId);\n\n // Resolve or reject the promise\n if (data.type === 'SUCCESS') {\n pending.resolve(data.data);\n } else if (data.type === 'ERROR') {\n pending.reject(data.error || { code: 'UNKNOWN_ERROR', message: 'An unknown error occurred' });\n }\n };\n\n window.addEventListener('message', this.messageListener);\n this.isInitialized = true;\n }\n\n /**\n * Generate a unique request ID\n */\n private generateRequestId(action: string): string {\n return `${action}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n\n /**\n * Send a message to the parent window and return a Promise\n */\n private sendMessage<T = unknown>(action: string, payload?: unknown): Promise<T> {\n if (!this.isInitialized) {\n return Promise.reject({\n code: 'SDK_NOT_INITIALIZED',\n message: 'SDK is not initialized',\n } as LearnCardError);\n }\n\n return new Promise<T>((resolve, reject) => {\n const requestId = this.generateRequestId(action);\n\n // Set up timeout\n const timeoutId = setTimeout(() => {\n if (this.pendingRequests.has(requestId)) {\n this.pendingRequests.delete(requestId);\n reject({\n code: 'LC_TIMEOUT',\n message: `Request ${action} timed out after ${this.requestTimeout}ms`,\n } as LearnCardError);\n }\n }, this.requestTimeout);\n\n // Store the pending request\n this.pendingRequests.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeoutId,\n });\n\n // Construct the message\n const message: PostMessageRequest = {\n protocol: this.protocol,\n action,\n requestId,\n payload,\n };\n\n // Send to parent window with the active host origin (configured or overridden)\n window.parent.postMessage(message, this.activeHostOrigin);\n });\n }\n\n /**\n * Request user identity (Single Sign-On)\n * \n * @returns Promise resolving to user identity including DID and JWT token\n * @throws {LearnCardError} When user is not authenticated or request fails\n * \n * @example\n * ```typescript\n * const identity = await learnCard.requestIdentity();\n * console.log('User DID:', identity.user.did);\n * console.log('JWT Token:', identity.token);\n * ```\n */\n public requestIdentity(): Promise<IdentityResponse> {\n return this.sendMessage<IdentityResponse>('REQUEST_IDENTITY', { challenge: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}` });\n }\n\n /**\n * Send a credential to the user's LearnCard wallet\n * \n * @param credential - The verifiable credential to send\n * @returns Promise resolving to credential ID\n * \n * @example\n * ```typescript\n * const response = await learnCard.sendCredential({\n * '@context': ['https://www.w3.org/2018/credentials/v1'],\n * type: ['VerifiableCredential'],\n * credentialSubject: { id: 'did:example:123' }\n * });\n * console.log('Credential ID:', response.credentialId);\n * ```\n */\n public sendCredential(credential: unknown): Promise<SendCredentialResponse> {\n return this.sendMessage<SendCredentialResponse>('SEND_CREDENTIAL', { credential });\n }\n\n /**\n * Launch a feature in the LearnCard host application\n * \n * @param featurePath - Path to the feature (e.g., '/ai/topics')\n * @param initialPrompt - Optional initial prompt or data\n * \n * @example\n * ```typescript\n * await learnCard.launchFeature(\n * '/ai/topics?shortCircuitStep=newTopic',\n * 'Help me understand cryptography'\n * );\n * ```\n */\n public launchFeature(featurePath: string, initialPrompt?: string): Promise<void> {\n return this.sendMessage<void>('LAUNCH_FEATURE', { featurePath, initialPrompt });\n }\n\n /**\n * Request credentials from the user's wallet using a query\n * \n * @param verifiablePresentationRequest - VPR with query criteria\n * @returns Promise resolving to verifiable presentation\n * \n * @example\n * ```typescript\n * const response = await learnCard.askCredentialSearch({\n * query: [{\n * type: 'QueryByTitle',\n * credentialQuery: {\n * reason: 'We need to verify your skills',\n * title: 'JavaScript Expert'\n * }\n * }],\n * challenge: 'challenge-123',\n * domain: window.location.hostname\n * });\n * \n * if (response.verifiablePresentation) {\n * console.log('Received credentials:', response.verifiablePresentation.verifiableCredential);\n * }\n * ```\n */\n public askCredentialSearch(\n verifiablePresentationRequest: VerifiablePresentationRequest\n ): Promise<CredentialSearchResponse> {\n return this.sendMessage<CredentialSearchResponse>('ASK_CREDENTIAL_SEARCH', {\n verifiablePresentationRequest,\n });\n }\n\n /**\n * Request a specific credential by ID\n * \n * @param credentialId - The ID of the credential to request\n * @returns Promise resolving to the credential\n * \n * @example\n * ```typescript\n * const response = await learnCard.askCredentialSpecific('credential-id-123');\n * if (response.credential) {\n * console.log('Received credential:', response.credential);\n * }\n * ```\n */\n public askCredentialSpecific(credentialId: string): Promise<CredentialSpecificResponse> {\n return this.sendMessage<CredentialSpecificResponse>('ASK_CREDENTIAL_SPECIFIC', {\n credentialId,\n });\n }\n\n /**\n * Request user consent for permissions\n * \n * @param contractUri - URI of the consent contract\n * @returns Promise resolving to consent response\n * \n * @example\n * ```typescript\n * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123');\n * if (response.granted) {\n * console.log('User granted consent');\n * }\n * ```\n */\n public requestConsent(contractUri: string): Promise<ConsentResponse> {\n return this.sendMessage<ConsentResponse>('REQUEST_CONSENT', { contractUri });\n }\n\n /**\n * Initiate a template-based credential issuance flow\n * \n * @param templateId - ID of the template/boost to issue\n * @param draftRecipients - Optional array of recipient DIDs\n * @returns Promise resolving to template issue response\n * \n * @example\n * ```typescript\n * const response = await learnCard.initiateTemplateIssue(\n * 'lc:network:network.learncard.com/trpc:boost:xyz789',\n * ['did:key:abc', 'did:key:def']\n * );\n * \n * if (response.issued) {\n * console.log('Template issued successfully');\n * }\n * ```\n */\n public initiateTemplateIssue(\n templateId: string,\n draftRecipients?: string[]\n ): Promise<TemplateIssueResponse> {\n return this.sendMessage<TemplateIssueResponse>('INITIATE_TEMPLATE_ISSUE', {\n templateId,\n draftRecipients: draftRecipients || [],\n });\n }\n\n /**\n * Clean up the SDK and remove event listeners\n */\n public destroy(): void {\n if (this.messageListener) {\n window.removeEventListener('message', this.messageListener);\n this.messageListener = null;\n }\n\n // Reject all pending requests\n for (const [requestId, pending] of this.pendingRequests.entries()) {\n clearTimeout(pending.timeoutId);\n pending.reject({\n code: 'SDK_DESTROYED',\n message: 'SDK was destroyed before request completed',\n });\n }\n\n this.pendingRequests.clear();\n this.isInitialized = false;\n }\n}\n\n/**\n * Factory function to create a PartnerConnect instance\n * \n * @param options - Configuration options\n * @returns PartnerConnect instance\n * \n * @example\n * ```typescript\n * const learnCard = createPartnerConnect({\n * hostOrigin: 'https://learncard.app',\n * protocol: 'LEARNCARD_V1',\n * requestTimeout: 30000\n * });\n * ```\n */\nexport function createPartnerConnect(options: PartnerConnectOptions): PartnerConnect {\n return new PartnerConnect(options);\n}\n\n// Default export for convenience\nexport default createPartnerConnect;\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"partner-connect.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * LearnCard Partner Connect SDK\n *\n * A Promise-based JavaScript utility for managing cross-origin message communication\n * between partner apps and the LearnCard host application.\n *\n * @example\n * ```typescript\n * import { createPartnerConnect } from '@learncard/partner-connect';\n *\n * const learnCard = createPartnerConnect({\n * hostOrigin: 'https://learncard.app'\n * });\n *\n * // Request user identity (SSO)\n * const identity = await learnCard.requestIdentity();\n * console.log('User DID:', identity.user.did);\n * ```\n */\n\nimport type {\n PartnerConnectOptions,\n IdentityResponse,\n SendCredentialResponse,\n TemplateCredentialInput,\n TemplateCredentialResponse,\n VerifiablePresentationRequest,\n CredentialSearchResponse,\n CredentialSpecificResponse,\n ConsentResponse,\n TemplateIssueResponse,\n AppEvent,\n AppEventResponse,\n LearnCardError,\n PostMessageRequest,\n PostMessageResponse,\n PendingRequest,\n} from './types';\n\nexport type * from './types';\n\n/**\n * LearnCard Partner Connect SDK class\n */\nexport class PartnerConnect {\n /** Default host origin (security anchor) */\n public static readonly DEFAULT_HOST_ORIGIN = 'https://learncard.app';\n\n private hostOrigins: string[] = ['https://learncard.app'];\n private activeHostOrigin: string = 'https://learncard.app';\n private allowNativeAppOrigins: boolean = true;\n private protocol: string = 'LEARNCARD_V1';\n private requestTimeout: number = 30000;\n private pendingRequests: Map<string, PendingRequest>;\n private messageListener: ((event: MessageEvent) => void) | null = null;\n private isInitialized = false;\n\n constructor(options?: PartnerConnectOptions) {\n // Normalize hostOrigin to an array for whitelist validation\n const hostOrigin = options?.hostOrigin || PartnerConnect.DEFAULT_HOST_ORIGIN;\n this.hostOrigins = Array.isArray(hostOrigin) ? hostOrigin : [hostOrigin];\n\n this.protocol = options?.protocol || 'LEARNCARD_V1';\n this.requestTimeout = options?.requestTimeout || 30000;\n this.allowNativeAppOrigins = options?.allowNativeAppOrigins ?? true;\n this.pendingRequests = new Map();\n this.configureActiveOrigin();\n this.setupMessageListener();\n }\n\n /**\n * Configure the active host origin using the following hierarchy:\n * 1. Check for `lc_host_override` query parameter (for staging/testing)\n * 2. Fall back to first configured origin\n * 3. Fall back to DEFAULT_HOST_ORIGIN\n *\n * This origin will be used for all outgoing messages and incoming message validation.\n */\n private configureActiveOrigin(): void {\n if (typeof window === 'undefined') {\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n return;\n }\n\n try {\n // Check for lc_host_override query parameter\n const urlParams = new URLSearchParams(window.location.search);\n const hostOverride = urlParams.get('lc_host_override');\n\n if (hostOverride) {\n // Validate override against whitelist (if provided)\n if (this.hostOrigins.length > 0 && !this.isOriginInWhitelist(hostOverride)) {\n console.warn(\n '[LearnCard SDK] lc_host_override value is not in the configured whitelist:',\n hostOverride,\n 'Allowed:',\n this.hostOrigins\n );\n this.activeHostOrigin =\n this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n } else {\n this.activeHostOrigin = hostOverride;\n console.log('[LearnCard SDK] Using lc_host_override:', hostOverride);\n }\n } else {\n // Use first configured origin or default\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n console.log('[LearnCard SDK] Using configured origin:', this.activeHostOrigin);\n }\n } catch (error) {\n console.error('[LearnCard SDK] Error configuring active origin:', error);\n this.activeHostOrigin = this.hostOrigins[0] || PartnerConnect.DEFAULT_HOST_ORIGIN;\n }\n }\n\n private isOriginNativeApp(origin: string): boolean {\n return (\n origin.startsWith('capacitor://') ||\n origin.startsWith('ionic://') ||\n origin.startsWith('https://localhost') ||\n origin.startsWith('http://localhost') ||\n origin.startsWith('http://127.0.0.1')\n );\n }\n\n /**\n * Check if an origin is in the configured whitelist\n */\n private isOriginInWhitelist(origin: string): boolean {\n return (\n this.hostOrigins.includes(origin) ||\n (this.allowNativeAppOrigins && this.isOriginNativeApp(origin))\n );\n }\n\n /**\n * Check if an event origin is valid against the active host origin\n *\n * Security Rule: Incoming messages must exactly match the active host origin.\n * This prevents malicious actors from spoofing origins via query parameters.\n *\n * @param eventOrigin - The origin from the MessageEvent\n * @returns true if the origin is valid\n */\n private isValidOrigin(eventOrigin: string): boolean {\n // STRICT: Exact match with active host origin only\n return eventOrigin === this.activeHostOrigin;\n }\n\n /**\n * Set up the central message listener to handle responses from the LearnCard host\n */\n private setupMessageListener(): void {\n if (typeof window === 'undefined') {\n throw new Error('PartnerConnect SDK can only be used in a browser environment');\n }\n\n this.messageListener = (event: MessageEvent) => {\n // SECURITY CHECK 1: Strict origin validation - must exactly match active host origin\n if (!this.isValidOrigin(event.origin)) {\n // Silently ignore messages from unauthorized origins\n return;\n }\n\n const data = event.data as PostMessageResponse;\n\n // SECURITY CHECK 2: Validate protocol and requestId\n if (data.protocol !== this.protocol || !data.requestId) {\n return;\n }\n\n // Look up the pending request\n const pending = this.pendingRequests.get(data.requestId);\n if (!pending) {\n return; // Ignore stale or unrecognized responses\n }\n\n // Clean up\n clearTimeout(pending.timeoutId);\n this.pendingRequests.delete(data.requestId);\n\n // Resolve or reject the promise\n if (data.type === 'SUCCESS') {\n pending.resolve(data.data);\n } else if (data.type === 'ERROR') {\n pending.reject(\n data.error || { code: 'UNKNOWN_ERROR', message: 'An unknown error occurred' }\n );\n }\n };\n\n window.addEventListener('message', this.messageListener);\n this.isInitialized = true;\n }\n\n /**\n * Generate a unique request ID\n */\n private generateRequestId(action: string): string {\n return `${action}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n\n /**\n * Send a message to the parent window and return a Promise\n */\n private sendMessage<T = unknown>(action: string, payload?: unknown): Promise<T> {\n if (!this.isInitialized) {\n return Promise.reject({\n code: 'SDK_NOT_INITIALIZED',\n message: 'SDK is not initialized',\n } as LearnCardError);\n }\n\n return new Promise<T>((resolve, reject) => {\n const requestId = this.generateRequestId(action);\n\n // Set up timeout\n const timeoutId = setTimeout(() => {\n if (this.pendingRequests.has(requestId)) {\n this.pendingRequests.delete(requestId);\n reject({\n code: 'LC_TIMEOUT',\n message: `Request ${action} timed out after ${this.requestTimeout}ms`,\n } as LearnCardError);\n }\n }, this.requestTimeout);\n\n // Store the pending request\n this.pendingRequests.set(requestId, {\n resolve: resolve as (value: unknown) => void,\n reject,\n timeoutId,\n });\n\n // Construct the message\n const message: PostMessageRequest = {\n protocol: this.protocol,\n action,\n requestId,\n payload,\n };\n\n // Send to parent window with the active host origin (configured or overridden)\n window.parent.postMessage(message, this.activeHostOrigin);\n });\n }\n\n /**\n * Request user identity (Single Sign-On)\n *\n * @returns Promise resolving to user identity including DID and JWT token\n * @throws {LearnCardError} When user is not authenticated or request fails\n *\n * @example\n * ```typescript\n * const identity = await learnCard.requestIdentity();\n * console.log('User DID:', identity.user.did);\n * console.log('JWT Token:', identity.token);\n * ```\n */\n public requestIdentity(): Promise<IdentityResponse> {\n return this.sendMessage<IdentityResponse>('REQUEST_IDENTITY', {\n challenge: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,\n });\n }\n\n /**\n * Send a credential to the user's LearnCard wallet\n *\n * Supports two modes:\n * 1. **Raw credential**: Pass a full verifiable credential object\n * 2. **Template-based**: Pass `{ templateAlias, templateData }` to issue from a pre-configured boost template\n *\n * @param input - Either a verifiable credential or a template-based input\n * @returns Promise resolving to credential response\n *\n * @example Raw credential\n * ```typescript\n * const response = await learnCard.sendCredential({\n * '@context': ['https://www.w3.org/2018/credentials/v1'],\n * type: ['VerifiableCredential'],\n * credentialSubject: { id: 'did:example:123' }\n * });\n * console.log('Credential ID:', response.credentialId);\n * ```\n *\n * @example Template-based (for App Store apps)\n * ```typescript\n * const response = await learnCard.sendCredential({\n * templateAlias: 'achievement-badge',\n * templateData: { score: '95', courseName: 'Web Dev 101' }\n * });\n * console.log('Credential URI:', response.credentialUri);\n * ```\n */\n public sendCredential(\n input: unknown | TemplateCredentialInput\n ): Promise<SendCredentialResponse | TemplateCredentialResponse> {\n if (\n input &&\n typeof input === 'object' &&\n 'templateAlias' in input &&\n typeof (input as TemplateCredentialInput).templateAlias === 'string'\n ) {\n const templateInput = input as TemplateCredentialInput;\n\n return this.sendAppEvent({\n type: 'send-credential',\n templateAlias: templateInput.templateAlias,\n templateData: templateInput.templateData,\n }) as Promise<TemplateCredentialResponse>;\n }\n\n return this.sendMessage<SendCredentialResponse>('SEND_CREDENTIAL', { credential: input });\n }\n\n /**\n * Launch a feature in the LearnCard host application\n *\n * @param featurePath - Path to the feature (e.g., '/ai/topics')\n * @param initialPrompt - Optional initial prompt or data\n *\n * @example\n * ```typescript\n * await learnCard.launchFeature(\n * '/ai/topics?shortCircuitStep=newTopic',\n * 'Help me understand cryptography'\n * );\n * ```\n */\n public launchFeature(featurePath: string, initialPrompt?: string): Promise<void> {\n return this.sendMessage<void>('LAUNCH_FEATURE', { featurePath, initialPrompt });\n }\n\n /**\n * Request credentials from the user's wallet using a query\n *\n * @param verifiablePresentationRequest - VPR with query criteria\n * @returns Promise resolving to verifiable presentation\n *\n * @example\n * ```typescript\n * const response = await learnCard.askCredentialSearch({\n * query: [{\n * type: 'QueryByTitle',\n * credentialQuery: {\n * reason: 'We need to verify your skills',\n * title: 'JavaScript Expert'\n * }\n * }],\n * challenge: 'challenge-123',\n * domain: window.location.hostname\n * });\n *\n * if (response.verifiablePresentation) {\n * console.log('Received credentials:', response.verifiablePresentation.verifiableCredential);\n * }\n * ```\n */\n public askCredentialSearch(\n verifiablePresentationRequest: VerifiablePresentationRequest\n ): Promise<CredentialSearchResponse> {\n return this.sendMessage<CredentialSearchResponse>('ASK_CREDENTIAL_SEARCH', {\n verifiablePresentationRequest,\n });\n }\n\n /**\n * Request a specific credential by ID\n *\n * @param credentialId - The ID of the credential to request\n * @returns Promise resolving to the credential\n *\n * @example\n * ```typescript\n * const response = await learnCard.askCredentialSpecific('credential-id-123');\n * if (response.credential) {\n * console.log('Received credential:', response.credential);\n * }\n * ```\n */\n public askCredentialSpecific(credentialId: string): Promise<CredentialSpecificResponse> {\n return this.sendMessage<CredentialSpecificResponse>('ASK_CREDENTIAL_SPECIFIC', {\n credentialId,\n });\n }\n\n /**\n * Request user consent for permissions\n *\n * @param contractUri - URI of the consent contract\n * @returns Promise resolving to consent response\n *\n * @example\n * ```typescript\n * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123');\n * if (response.granted) {\n * console.log('User granted consent');\n * }\n * ```\n */\n public requestConsent(contractUri: string): Promise<ConsentResponse> {\n return this.sendMessage<ConsentResponse>('REQUEST_CONSENT', { contractUri });\n }\n\n /**\n * Initiate a template-based credential issuance flow\n *\n * @param templateId - ID of the template/boost to issue\n * @param draftRecipients - Optional array of recipient DIDs\n * @returns Promise resolving to template issue response\n *\n * @example\n * ```typescript\n * const response = await learnCard.initiateTemplateIssue(\n * 'lc:network:network.learncard.com/trpc:boost:xyz789',\n * ['did:key:abc', 'did:key:def']\n * );\n *\n * if (response.issued) {\n * console.log('Template issued successfully');\n * }\n * ```\n */\n public initiateTemplateIssue(\n templateId: string,\n draftRecipients?: string[]\n ): Promise<TemplateIssueResponse> {\n return this.sendMessage<TemplateIssueResponse>('INITIATE_TEMPLATE_ISSUE', {\n templateId,\n draftRecipients: draftRecipients || [],\n });\n }\n\n /**\n * Send a generic event to be processed by the brain service on behalf of this app.\n * This is used for backend-like operations such as issuing credentials.\n *\n * @param event - The event payload to send\n * @returns Promise resolving to the event response\n *\n * @example\n * ```typescript\n * // Issue a credential to the current user\n * const response = await learnCard.sendAppEvent({\n * type: 'send-credential',\n * templateAlias: 'achievement-badge',\n * templateData: { score: '95' }\n * });\n *\n * if (response.credentialUri) {\n * console.log('Credential issued:', response.credentialUri);\n * }\n * ```\n */\n public sendAppEvent(event: AppEvent): Promise<AppEventResponse> {\n return this.sendMessage<AppEventResponse>('APP_EVENT', event);\n }\n\n /**\n * Clean up the SDK and remove event listeners\n */\n public destroy(): void {\n if (this.messageListener) {\n window.removeEventListener('message', this.messageListener);\n this.messageListener = null;\n }\n\n // Reject all pending requests\n for (const [requestId, pending] of this.pendingRequests.entries()) {\n clearTimeout(pending.timeoutId);\n pending.reject({\n code: 'SDK_DESTROYED',\n message: 'SDK was destroyed before request completed',\n });\n }\n\n this.pendingRequests.clear();\n this.isInitialized = false;\n }\n}\n\n/**\n * Factory function to create a PartnerConnect instance\n *\n * @param options - Configuration options\n * @returns PartnerConnect instance\n *\n * @example\n * ```typescript\n * const learnCard = createPartnerConnect({\n * hostOrigin: 'https://learncard.app',\n * protocol: 'LEARNCARD_V1',\n * requestTimeout: 30000\n * });\n * ```\n */\nexport function createPartnerConnect(options: PartnerConnectOptions): PartnerConnect {\n return new PartnerConnect(options);\n}\n\n// Default export for convenience\nexport default createPartnerConnect;\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@learncard/partner-connect",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/learningeconomy/LearnCard"
|
|
7
|
+
},
|
|
4
8
|
"description": "LearnCard Partner Connect SDK - Promise-based cross-origin messaging for partner apps",
|
|
5
9
|
"main": "dist/partner-connect.js",
|
|
6
10
|
"module": "dist/partner-connect.esm.js",
|
|
@@ -25,6 +29,9 @@
|
|
|
25
29
|
],
|
|
26
30
|
"license": "MIT",
|
|
27
31
|
"author": "Learning Economy Foundation (www.learningeconomy.io)",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@learncard/types": "5.11.3"
|
|
34
|
+
},
|
|
28
35
|
"devDependencies": {
|
|
29
36
|
"@rollup/plugin-commonjs": "^22.0.2",
|
|
30
37
|
"@rollup/plugin-node-resolve": "^13.3.0",
|