@learncard/partner-connect 0.2.0 → 0.2.3

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 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
  */
@@ -112,6 +136,16 @@ interface CredentialSearchResponse {
112
136
  interface CredentialSpecificResponse {
113
137
  credential?: unknown;
114
138
  }
139
+ /**
140
+ * Options for REQUEST_CONSENT action
141
+ */
142
+ interface RequestConsentOptions {
143
+ /**
144
+ * If true, redirect to contract's redirectUrl with VP after consent.
145
+ * Default: false
146
+ */
147
+ redirect?: boolean;
148
+ }
115
149
  /**
116
150
  * Response from REQUEST_CONSENT action
117
151
  */
@@ -162,7 +196,7 @@ interface PostMessageResponse {
162
196
  interface PendingRequest {
163
197
  resolve: (value: unknown) => void;
164
198
  reject: (error: LearnCardError) => void;
165
- timeoutId: NodeJS.Timeout;
199
+ timeoutId: ReturnType<typeof setTimeout>;
166
200
  }
167
201
 
168
202
  /**
@@ -253,10 +287,14 @@ declare class PartnerConnect {
253
287
  /**
254
288
  * Send a credential to the user's LearnCard wallet
255
289
  *
256
- * @param credential - The verifiable credential to send
257
- * @returns Promise resolving to credential ID
290
+ * Supports two modes:
291
+ * 1. **Raw credential**: Pass a full verifiable credential object
292
+ * 2. **Template-based**: Pass `{ templateAlias, templateData }` to issue from a pre-configured boost template
258
293
  *
259
- * @example
294
+ * @param input - Either a verifiable credential or a template-based input
295
+ * @returns Promise resolving to credential response
296
+ *
297
+ * @example Raw credential
260
298
  * ```typescript
261
299
  * const response = await learnCard.sendCredential({
262
300
  * '@context': ['https://www.w3.org/2018/credentials/v1'],
@@ -265,8 +303,17 @@ declare class PartnerConnect {
265
303
  * });
266
304
  * console.log('Credential ID:', response.credentialId);
267
305
  * ```
306
+ *
307
+ * @example Template-based (for App Store apps)
308
+ * ```typescript
309
+ * const response = await learnCard.sendCredential({
310
+ * templateAlias: 'achievement-badge',
311
+ * templateData: { score: '95', courseName: 'Web Dev 101' }
312
+ * });
313
+ * console.log('Credential URI:', response.credentialUri);
314
+ * ```
268
315
  */
269
- sendCredential(credential: unknown): Promise<SendCredentialResponse>;
316
+ sendCredential(input: unknown | TemplateCredentialInput): Promise<SendCredentialResponse | TemplateCredentialResponse>;
270
317
  /**
271
318
  * Launch a feature in the LearnCard host application
272
319
  *
@@ -331,13 +378,20 @@ declare class PartnerConnect {
331
378
  *
332
379
  * @example
333
380
  * ```typescript
381
+ * // Without redirect (default) - returns VP in response if app owns the contract
334
382
  * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123');
335
383
  * if (response.granted) {
336
384
  * console.log('User granted consent');
385
+ * if (response.vp) {
386
+ * console.log('VP:', response.vp);
387
+ * }
337
388
  * }
389
+ *
390
+ * // With redirect - redirects to contract's redirectUrl with VP in URL params
391
+ * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123', { redirect: true });
338
392
  * ```
339
393
  */
340
- requestConsent(contractUri: string): Promise<ConsentResponse>;
394
+ requestConsent(contractUri: string, options?: RequestConsentOptions): Promise<ConsentResponse>;
341
395
  /**
342
396
  * Initiate a template-based credential issuance flow
343
397
  *
@@ -358,6 +412,28 @@ declare class PartnerConnect {
358
412
  * ```
359
413
  */
360
414
  initiateTemplateIssue(templateId: string, draftRecipients?: string[]): Promise<TemplateIssueResponse>;
415
+ /**
416
+ * Send a generic event to be processed by the brain service on behalf of this app.
417
+ * This is used for backend-like operations such as issuing credentials.
418
+ *
419
+ * @param event - The event payload to send
420
+ * @returns Promise resolving to the event response
421
+ *
422
+ * @example
423
+ * ```typescript
424
+ * // Issue a credential to the current user
425
+ * const response = await learnCard.sendAppEvent({
426
+ * type: 'send-credential',
427
+ * templateAlias: 'achievement-badge',
428
+ * templateData: { score: '95' }
429
+ * });
430
+ *
431
+ * if (response.credentialUri) {
432
+ * console.log('Credential issued:', response.credentialUri);
433
+ * }
434
+ * ```
435
+ */
436
+ sendAppEvent(event: AppEvent): Promise<AppEventResponse>;
361
437
  /**
362
438
  * Clean up the SDK and remove event listeners
363
439
  */
@@ -380,4 +456,4 @@ declare class PartnerConnect {
380
456
  */
381
457
  declare function createPartnerConnect(options: PartnerConnectOptions): PartnerConnect;
382
458
 
383
- export { ConsentResponse, CredentialSearchResponse, CredentialSpecificResponse, ErrorCode, IdentityResponse, LearnCardError, PartnerConnect, PartnerConnectOptions, PendingRequest, PostMessageRequest, PostMessageResponse, SendCredentialResponse, TemplateIssueResponse, VPRQuery, VerifiablePresentationRequest, createPartnerConnect, createPartnerConnect as default };
459
+ export { ConsentResponse, CredentialSearchResponse, CredentialSpecificResponse, ErrorCode, IdentityResponse, LearnCardError, PartnerConnect, PartnerConnectOptions, PendingRequest, PostMessageRequest, PostMessageResponse, RequestConsentOptions, 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") || origin.startsWith("http://192.168.1.164");
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(data.error || { code: "UNKNOWN_ERROR", message: "An unknown error occurred" });
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", { challenge: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}` });
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
- * @param credential - The verifiable credential to send
174
- * @returns Promise resolving to credential ID
175
- *
176
- * @example
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(credential) {
187
- return this.sendMessage("SEND_CREDENTIAL", { credential });
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,35 +279,46 @@ 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
288
+ * // Without redirect (default) - returns VP in response if app owns the contract
263
289
  * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123');
264
290
  * if (response.granted) {
265
291
  * console.log('User granted consent');
292
+ * if (response.vp) {
293
+ * console.log('VP:', response.vp);
294
+ * }
266
295
  * }
296
+ *
297
+ * // With redirect - redirects to contract's redirectUrl with VP in URL params
298
+ * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123', { redirect: true });
267
299
  * ```
268
300
  */
269
- requestConsent(contractUri) {
270
- return this.sendMessage("REQUEST_CONSENT", { contractUri });
301
+ requestConsent(contractUri, options = {}) {
302
+ const { redirect = false } = options;
303
+ return this.sendMessage("REQUEST_CONSENT", {
304
+ contractUri,
305
+ redirect
306
+ });
271
307
  }
272
308
  /**
273
309
  * Initiate a template-based credential issuance flow
274
- *
310
+ *
275
311
  * @param templateId - ID of the template/boost to issue
276
312
  * @param draftRecipients - Optional array of recipient DIDs
277
313
  * @returns Promise resolving to template issue response
278
- *
314
+ *
279
315
  * @example
280
316
  * ```typescript
281
317
  * const response = await learnCard.initiateTemplateIssue(
282
318
  * 'lc:network:network.learncard.com/trpc:boost:xyz789',
283
319
  * ['did:key:abc', 'did:key:def']
284
320
  * );
285
- *
321
+ *
286
322
  * if (response.issued) {
287
323
  * console.log('Template issued successfully');
288
324
  * }
@@ -294,6 +330,30 @@ const _PartnerConnect = class _PartnerConnect {
294
330
  draftRecipients: draftRecipients || []
295
331
  });
296
332
  }
333
+ /**
334
+ * Send a generic event to be processed by the brain service on behalf of this app.
335
+ * This is used for backend-like operations such as issuing credentials.
336
+ *
337
+ * @param event - The event payload to send
338
+ * @returns Promise resolving to the event response
339
+ *
340
+ * @example
341
+ * ```typescript
342
+ * // Issue a credential to the current user
343
+ * const response = await learnCard.sendAppEvent({
344
+ * type: 'send-credential',
345
+ * templateAlias: 'achievement-badge',
346
+ * templateData: { score: '95' }
347
+ * });
348
+ *
349
+ * if (response.credentialUri) {
350
+ * console.log('Credential issued:', response.credentialUri);
351
+ * }
352
+ * ```
353
+ */
354
+ sendAppEvent(event) {
355
+ return this.sendMessage("APP_EVENT", event);
356
+ }
297
357
  /**
298
358
  * Clean up the SDK and remove event listeners
299
359
  */
@@ -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":";;;AAwCO,MAAM,eAAA,GAAN,MAAM,eAAe,CAAA;AAAA,EAa1B,YAAY,OAAiC,EAAA;AAT7C,IAAQ,aAAA,CAAA,IAAA,EAAA,aAAA,EAAwB,CAAC,uBAAuB,CAAA,CAAA,CAAA;AACxD,IAAA,aAAA,CAAA,IAAA,EAAQ,kBAA2B,EAAA,uBAAA,CAAA,CAAA;AACnC,IAAA,aAAA,CAAA,IAAA,EAAQ,uBAAiC,EAAA,IAAA,CAAA,CAAA;AACzC,IAAA,aAAA,CAAA,IAAA,EAAQ,UAAmB,EAAA,cAAA,CAAA,CAAA;AAC3B,IAAA,aAAA,CAAA,IAAA,EAAQ,gBAAyB,EAAA,GAAA,CAAA,CAAA;AACjC,IAAQ,aAAA,CAAA,IAAA,EAAA,iBAAA,CAAA,CAAA;AACR,IAAA,aAAA,CAAA,IAAA,EAAQ,iBAA0D,EAAA,IAAA,CAAA,CAAA;AAClE,IAAA,aAAA,CAAA,IAAA,EAAQ,eAAgB,EAAA,KAAA,CAAA,CAAA;AAnD1B,IAAA,IAAA,EAAA,CAAA;AAuDI,IAAM,MAAA,UAAA,GAAA,CAAa,OAAS,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAA,UAAA,KAAc,eAAe,CAAA,mBAAA,CAAA;AACzD,IAAA,IAAA,CAAK,cAAc,KAAM,CAAA,OAAA,CAAQ,UAAU,CAAI,GAAA,UAAA,GAAa,CAAC,UAAU,CAAA,CAAA;AAEvE,IAAK,IAAA,CAAA,QAAA,GAAA,CAAW,mCAAS,QAAY,KAAA,cAAA,CAAA;AACrC,IAAK,IAAA,CAAA,cAAA,GAAA,CAAiB,mCAAS,cAAkB,KAAA,GAAA,CAAA;AACjD,IAAK,IAAA,CAAA,qBAAA,GAAA,CAAwB,EAAS,GAAA,OAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAA,qBAAA,KAAT,IAAkC,GAAA,EAAA,GAAA,IAAA,CAAA;AAC/D,IAAK,IAAA,CAAA,eAAA,uBAAsB,GAAI,EAAA,CAAA;AAC/B,IAAA,IAAA,CAAK,qBAAsB,EAAA,CAAA;AAC3B,IAAA,IAAA,CAAK,oBAAqB,EAAA,CAAA;AAAA,GAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,qBAA8B,GAAA;AACpC,IAAI,IAAA,OAAO,WAAW,WAAa,EAAA;AACjC,MAAA,IAAA,CAAK,gBAAmB,GAAA,IAAA,CAAK,WAAY,CAAA,CAAC,KAAK,eAAe,CAAA,mBAAA,CAAA;AAC9D,MAAA,OAAA;AAAA,KACF;AAEA,IAAI,IAAA;AAEF,MAAA,MAAM,SAAY,GAAA,IAAI,eAAgB,CAAA,MAAA,CAAO,SAAS,MAAM,CAAA,CAAA;AAC5D,MAAM,MAAA,YAAA,GAAe,SAAU,CAAA,GAAA,CAAI,kBAAkB,CAAA,CAAA;AAErD,MAAA,IAAI,YAAc,EAAA;AAEhB,QAAI,IAAA,IAAA,CAAK,YAAY,MAAS,GAAA,CAAA,IAAK,CAAC,IAAK,CAAA,mBAAA,CAAoB,YAAY,CAAG,EAAA;AAC1E,UAAQ,OAAA,CAAA,IAAA;AAAA,YACN,4EAAA;AAAA,YACA,YAAA;AAAA,YACA,UAAA;AAAA,YACA,IAAK,CAAA,WAAA;AAAA,WACP,CAAA;AACA,UAAA,IAAA,CAAK,gBAAmB,GAAA,IAAA,CAAK,WAAY,CAAA,CAAC,KAAK,eAAe,CAAA,mBAAA,CAAA;AAAA,SACzD,MAAA;AACL,UAAA,IAAA,CAAK,gBAAmB,GAAA,YAAA,CAAA;AACxB,UAAQ,OAAA,CAAA,GAAA,CAAI,2CAA2C,YAAY,CAAA,CAAA;AAAA,SACrE;AAAA,OACK,MAAA;AAEL,QAAA,IAAA,CAAK,gBAAmB,GAAA,IAAA,CAAK,WAAY,CAAA,CAAC,KAAK,eAAe,CAAA,mBAAA,CAAA;AAC9D,QAAQ,OAAA,CAAA,GAAA,CAAI,0CAA4C,EAAA,IAAA,CAAK,gBAAgB,CAAA,CAAA;AAAA,OAC/E;AAAA,aACO,KAAO,EAAA;AACd,MAAQ,OAAA,CAAA,KAAA,CAAM,oDAAoD,KAAK,CAAA,CAAA;AACvE,MAAA,IAAA,CAAK,gBAAmB,GAAA,IAAA,CAAK,WAAY,CAAA,CAAC,KAAK,eAAe,CAAA,mBAAA,CAAA;AAAA,KAChE;AAAA,GACF;AAAA,EAEQ,kBAAkB,MAAyB,EAAA;AACjD,IAAO,OAAA,MAAA,CAAO,WAAW,cAAc,CAAA,IAAK,OAAO,UAAW,CAAA,UAAU,CAAK,IAAA,MAAA,CAAO,UAAW,CAAA,mBAAmB,KAAK,MAAO,CAAA,UAAA,CAAW,kBAAkB,CAAK,IAAA,MAAA,CAAO,WAAW,kBAAkB,CAAA,IAAK,MAAO,CAAA,UAAA,CAAW,sBAAsB,CAAA,CAAA;AAAA,GACnP;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,MAAyB,EAAA;AACnD,IAAO,OAAA,IAAA,CAAK,YAAY,QAAS,CAAA,MAAM,KAAM,IAAK,CAAA,qBAAA,IAAyB,IAAK,CAAA,iBAAA,CAAkB,MAAM,CAAA,CAAA;AAAA,GAC1G;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,cAAc,WAA8B,EAAA;AAElD,IAAA,OAAO,gBAAgB,IAAK,CAAA,gBAAA,CAAA;AAAA,GAC9B;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAA6B,GAAA;AACnC,IAAI,IAAA,OAAO,WAAW,WAAa,EAAA;AACjC,MAAM,MAAA,IAAI,MAAM,8DAA8D,CAAA,CAAA;AAAA,KAChF;AAEA,IAAK,IAAA,CAAA,eAAA,GAAkB,CAAC,KAAwB,KAAA;AAE9C,MAAA,IAAI,CAAC,IAAA,CAAK,aAAc,CAAA,KAAA,CAAM,MAAM,CAAG,EAAA;AAErC,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,MAAM,OAAO,KAAM,CAAA,IAAA,CAAA;AAGnB,MAAA,IAAI,KAAK,QAAa,KAAA,IAAA,CAAK,QAAY,IAAA,CAAC,KAAK,SAAW,EAAA;AACtD,QAAA,OAAA;AAAA,OACF;AAGA,MAAA,MAAM,OAAU,GAAA,IAAA,CAAK,eAAgB,CAAA,GAAA,CAAI,KAAK,SAAS,CAAA,CAAA;AACvD,MAAA,IAAI,CAAC,OAAS,EAAA;AACZ,QAAA,OAAA;AAAA,OACF;AAGA,MAAA,YAAA,CAAa,QAAQ,SAAS,CAAA,CAAA;AAC9B,MAAK,IAAA,CAAA,eAAA,CAAgB,MAAO,CAAA,IAAA,CAAK,SAAS,CAAA,CAAA;AAG1C,MAAI,IAAA,IAAA,CAAK,SAAS,SAAW,EAAA;AAC3B,QAAQ,OAAA,CAAA,OAAA,CAAQ,KAAK,IAAI,CAAA,CAAA;AAAA,OAC3B,MAAA,IAAW,IAAK,CAAA,IAAA,KAAS,OAAS,EAAA;AAChC,QAAQ,OAAA,CAAA,MAAA,CAAO,KAAK,KAAS,IAAA,EAAE,MAAM,eAAiB,EAAA,OAAA,EAAS,6BAA6B,CAAA,CAAA;AAAA,OAC9F;AAAA,KACF,CAAA;AAEA,IAAO,MAAA,CAAA,gBAAA,CAAiB,SAAW,EAAA,IAAA,CAAK,eAAe,CAAA,CAAA;AACvD,IAAA,IAAA,CAAK,aAAgB,GAAA,IAAA,CAAA;AAAA,GACvB;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,MAAwB,EAAA;AAChD,IAAA,OAAO,GAAG,MAAM,CAAA,CAAA,EAAI,IAAK,CAAA,GAAA,EAAK,CAAI,CAAA,EAAA,IAAA,CAAK,MAAO,EAAA,CAAE,SAAS,EAAE,CAAA,CAAE,SAAU,CAAA,CAAA,EAAG,CAAC,CAAC,CAAA,CAAA,CAAA;AAAA,GAC9E;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAA,CAAyB,QAAgB,OAA+B,EAAA;AAC9E,IAAI,IAAA,CAAC,KAAK,aAAe,EAAA;AACvB,MAAA,OAAO,QAAQ,MAAO,CAAA;AAAA,QACpB,IAAM,EAAA,qBAAA;AAAA,QACN,OAAS,EAAA,wBAAA;AAAA,OACQ,CAAA,CAAA;AAAA,KACrB;AAEA,IAAA,OAAO,IAAI,OAAA,CAAW,CAAC,OAAA,EAAS,MAAW,KAAA;AACzC,MAAM,MAAA,SAAA,GAAY,IAAK,CAAA,iBAAA,CAAkB,MAAM,CAAA,CAAA;AAG/C,MAAM,MAAA,SAAA,GAAY,WAAW,MAAM;AACjC,QAAA,IAAI,IAAK,CAAA,eAAA,CAAgB,GAAI,CAAA,SAAS,CAAG,EAAA;AACvC,UAAK,IAAA,CAAA,eAAA,CAAgB,OAAO,SAAS,CAAA,CAAA;AACrC,UAAO,MAAA,CAAA;AAAA,YACL,IAAM,EAAA,YAAA;AAAA,YACN,OAAS,EAAA,CAAA,QAAA,EAAW,MAAM,CAAA,iBAAA,EAAoB,KAAK,cAAc,CAAA,EAAA,CAAA;AAAA,WAChD,CAAA,CAAA;AAAA,SACrB;AAAA,OACF,EAAG,KAAK,cAAc,CAAA,CAAA;AAGtB,MAAK,IAAA,CAAA,eAAA,CAAgB,IAAI,SAAW,EAAA;AAAA,QAClC,OAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,OACD,CAAA,CAAA;AAGD,MAAA,MAAM,OAA8B,GAAA;AAAA,QAClC,UAAU,IAAK,CAAA,QAAA;AAAA,QACf,MAAA;AAAA,QACA,SAAA;AAAA,QACA,OAAA;AAAA,OACF,CAAA;AAGA,MAAA,MAAA,CAAO,MAAO,CAAA,WAAA,CAAY,OAAS,EAAA,IAAA,CAAK,gBAAgB,CAAA,CAAA;AAAA,KACzD,CAAA,CAAA;AAAA,GACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeO,eAA6C,GAAA;AAClD,IAAO,OAAA,IAAA,CAAK,YAA8B,kBAAoB,EAAA,EAAE,WAAW,CAAG,EAAA,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,KAAK,MAAO,EAAA,CAAE,SAAS,EAAE,CAAA,CAAE,UAAU,CAAG,EAAA,CAAC,CAAC,CAAA,CAAA,EAAI,CAAA,CAAA;AAAA,GAC5I;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBO,eAAe,UAAsD,EAAA;AAC1E,IAAA,OAAO,IAAK,CAAA,WAAA,CAAoC,iBAAmB,EAAA,EAAE,YAAY,CAAA,CAAA;AAAA,GACnF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBO,aAAA,CAAc,aAAqB,aAAuC,EAAA;AAC/E,IAAA,OAAO,KAAK,WAAkB,CAAA,gBAAA,EAAkB,EAAE,WAAA,EAAa,eAAe,CAAA,CAAA;AAAA,GAChF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2BO,oBACL,6BACmC,EAAA;AACnC,IAAO,OAAA,IAAA,CAAK,YAAsC,uBAAyB,EAAA;AAAA,MACzE,6BAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBO,sBAAsB,YAA2D,EAAA;AACtF,IAAO,OAAA,IAAA,CAAK,YAAwC,yBAA2B,EAAA;AAAA,MAC7E,YAAA;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBO,eAAe,WAA+C,EAAA;AACnE,IAAA,OAAO,IAAK,CAAA,WAAA,CAA6B,iBAAmB,EAAA,EAAE,aAAa,CAAA,CAAA;AAAA,GAC7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBO,qBAAA,CACL,YACA,eACgC,EAAA;AAChC,IAAO,OAAA,IAAA,CAAK,YAAmC,yBAA2B,EAAA;AAAA,MACxE,UAAA;AAAA,MACA,eAAA,EAAiB,mBAAmB,EAAC;AAAA,KACtC,CAAA,CAAA;AAAA,GACH;AAAA;AAAA;AAAA;AAAA,EAKO,OAAgB,GAAA;AACrB,IAAA,IAAI,KAAK,eAAiB,EAAA;AACxB,MAAO,MAAA,CAAA,mBAAA,CAAoB,SAAW,EAAA,IAAA,CAAK,eAAe,CAAA,CAAA;AAC1D,MAAA,IAAA,CAAK,eAAkB,GAAA,IAAA,CAAA;AAAA,KACzB;AAGA,IAAA,KAAA,MAAW,CAAC,SAAW,EAAA,OAAO,KAAK,IAAK,CAAA,eAAA,CAAgB,SAAW,EAAA;AACjE,MAAA,YAAA,CAAa,QAAQ,SAAS,CAAA,CAAA;AAC9B,MAAA,OAAA,CAAQ,MAAO,CAAA;AAAA,QACb,IAAM,EAAA,eAAA;AAAA,QACN,OAAS,EAAA,4CAAA;AAAA,OACV,CAAA,CAAA;AAAA,KACH;AAEA,IAAA,IAAA,CAAK,gBAAgB,KAAM,EAAA,CAAA;AAC3B,IAAA,IAAA,CAAK,aAAgB,GAAA,KAAA,CAAA;AAAA,GACvB;AACF,CAAA,CAAA;AAAA;AA7WE,aAAA,CAFW,iBAEY,qBAAsB,EAAA,uBAAA,CAAA,CAAA;AAFxC,IAAM,cAAN,GAAA,gBAAA;AAgYA,SAAS,qBAAqB,OAAgD,EAAA;AACnF,EAAO,OAAA,IAAI,eAAe,OAAO,CAAA,CAAA;AACnC;;;;"}
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 RequestConsentOptions,\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 * // Without redirect (default) - returns VP in response if app owns the contract\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 * if (response.vp) {\n * console.log('VP:', response.vp);\n * }\n * }\n *\n * // With redirect - redirects to contract's redirectUrl with VP in URL params\n * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123', { redirect: true });\n * ```\n */\n public requestConsent(\n contractUri: string,\n options: RequestConsentOptions = {}\n ): Promise<ConsentResponse> {\n const { redirect = false } = options;\n\n return this.sendMessage<ConsentResponse>('REQUEST_CONSENT', {\n contractUri,\n redirect,\n });\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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"}
@@ -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") || origin.startsWith("http://192.168.1.164");
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(data.error || { code: "UNKNOWN_ERROR", message: "An unknown error occurred" });
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", { challenge: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}` });
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
- * @param credential - The verifiable credential to send
178
- * @returns Promise resolving to credential ID
179
- *
180
- * @example
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(credential) {
191
- return this.sendMessage("SEND_CREDENTIAL", { credential });
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,35 +283,46 @@ 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
292
+ * // Without redirect (default) - returns VP in response if app owns the contract
267
293
  * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123');
268
294
  * if (response.granted) {
269
295
  * console.log('User granted consent');
296
+ * if (response.vp) {
297
+ * console.log('VP:', response.vp);
298
+ * }
270
299
  * }
300
+ *
301
+ * // With redirect - redirects to contract's redirectUrl with VP in URL params
302
+ * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123', { redirect: true });
271
303
  * ```
272
304
  */
273
- requestConsent(contractUri) {
274
- return this.sendMessage("REQUEST_CONSENT", { contractUri });
305
+ requestConsent(contractUri, options = {}) {
306
+ const { redirect = false } = options;
307
+ return this.sendMessage("REQUEST_CONSENT", {
308
+ contractUri,
309
+ redirect
310
+ });
275
311
  }
276
312
  /**
277
313
  * Initiate a template-based credential issuance flow
278
- *
314
+ *
279
315
  * @param templateId - ID of the template/boost to issue
280
316
  * @param draftRecipients - Optional array of recipient DIDs
281
317
  * @returns Promise resolving to template issue response
282
- *
318
+ *
283
319
  * @example
284
320
  * ```typescript
285
321
  * const response = await learnCard.initiateTemplateIssue(
286
322
  * 'lc:network:network.learncard.com/trpc:boost:xyz789',
287
323
  * ['did:key:abc', 'did:key:def']
288
324
  * );
289
- *
325
+ *
290
326
  * if (response.issued) {
291
327
  * console.log('Template issued successfully');
292
328
  * }
@@ -298,6 +334,30 @@ const _PartnerConnect = class _PartnerConnect {
298
334
  draftRecipients: draftRecipients || []
299
335
  });
300
336
  }
337
+ /**
338
+ * Send a generic event to be processed by the brain service on behalf of this app.
339
+ * This is used for backend-like operations such as issuing credentials.
340
+ *
341
+ * @param event - The event payload to send
342
+ * @returns Promise resolving to the event response
343
+ *
344
+ * @example
345
+ * ```typescript
346
+ * // Issue a credential to the current user
347
+ * const response = await learnCard.sendAppEvent({
348
+ * type: 'send-credential',
349
+ * templateAlias: 'achievement-badge',
350
+ * templateData: { score: '95' }
351
+ * });
352
+ *
353
+ * if (response.credentialUri) {
354
+ * console.log('Credential issued:', response.credentialUri);
355
+ * }
356
+ * ```
357
+ */
358
+ sendAppEvent(event) {
359
+ return this.sendMessage("APP_EVENT", event);
360
+ }
301
361
  /**
302
362
  * Clean up the SDK and remove event listeners
303
363
  */
@@ -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 RequestConsentOptions,\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 * // Without redirect (default) - returns VP in response if app owns the contract\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 * if (response.vp) {\n * console.log('VP:', response.vp);\n * }\n * }\n *\n * // With redirect - redirects to contract's redirectUrl with VP in URL params\n * const response = await learnCard.requestConsent('lc:network:network.learncard.com/trpc:contract:abc123', { redirect: true });\n * ```\n */\n public requestConsent(\n contractUri: string,\n options: RequestConsentOptions = {}\n ): Promise<ConsentResponse> {\n const { redirect = false } = options;\n\n return this.sendMessage<ConsentResponse>('REQUEST_CONSENT', {\n contractUri,\n redirect,\n });\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.0",
3
+ "version": "0.2.3",
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",