@lessonkit/core 0.8.1 → 0.9.1
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.cjs +72 -0
- package/dist/index.d.cts +62 -1
- package/dist/index.d.ts +62 -1
- package/dist/index.js +70 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -26,8 +26,10 @@ __export(index_exports, {
|
|
|
26
26
|
assertValidId: () => assertValidId,
|
|
27
27
|
buildLessonkitUrn: () => buildLessonkitUrn,
|
|
28
28
|
buildTelemetryCatalog: () => buildTelemetryCatalog,
|
|
29
|
+
createPluginHost: () => createPluginHost,
|
|
29
30
|
createSessionId: () => createSessionId,
|
|
30
31
|
createTrackingClient: () => createTrackingClient,
|
|
32
|
+
defineLessonkitPlugin: () => defineLessonkitPlugin,
|
|
31
33
|
deriveId: () => deriveId,
|
|
32
34
|
nowIso: () => nowIso,
|
|
33
35
|
slugifyId: () => slugifyId,
|
|
@@ -273,6 +275,74 @@ function createSessionId() {
|
|
|
273
275
|
function nowIso() {
|
|
274
276
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
275
277
|
}
|
|
278
|
+
|
|
279
|
+
// src/plugins.ts
|
|
280
|
+
function defineLessonkitPlugin(plugin) {
|
|
281
|
+
return plugin;
|
|
282
|
+
}
|
|
283
|
+
function warnDuplicatePlugin(id) {
|
|
284
|
+
const g = globalThis;
|
|
285
|
+
if (typeof g.process !== "undefined" && g.process.env?.NODE_ENV === "production") return;
|
|
286
|
+
console.warn(`[lessonkit] plugin id "${id}" was registered more than once; using the latest definition`);
|
|
287
|
+
}
|
|
288
|
+
function createPluginHost(plugins = []) {
|
|
289
|
+
const registry = /* @__PURE__ */ new Map();
|
|
290
|
+
for (const plugin of plugins) {
|
|
291
|
+
if (registry.has(plugin.id)) warnDuplicatePlugin(plugin.id);
|
|
292
|
+
registry.set(plugin.id, plugin);
|
|
293
|
+
}
|
|
294
|
+
const list = [...registry.values()];
|
|
295
|
+
const setupAll = (ctx) => {
|
|
296
|
+
for (const plugin of list) {
|
|
297
|
+
plugin.setup?.(ctx);
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
const disposeAll = () => {
|
|
301
|
+
for (let i = list.length - 1; i >= 0; i -= 1) {
|
|
302
|
+
list[i]?.dispose?.();
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
const runTelemetry = (event, ctx) => {
|
|
306
|
+
let current = event;
|
|
307
|
+
for (const plugin of list) {
|
|
308
|
+
if (!plugin.onTelemetry || current === null) continue;
|
|
309
|
+
current = plugin.onTelemetry(current, ctx);
|
|
310
|
+
}
|
|
311
|
+
return current;
|
|
312
|
+
};
|
|
313
|
+
const runTelemetryBatch = (events, ctx) => {
|
|
314
|
+
const filtered = events.map((event) => runTelemetry(event, ctx)).filter((event) => event !== null);
|
|
315
|
+
for (const plugin of list) {
|
|
316
|
+
plugin.onTelemetryBatch?.(filtered, ctx);
|
|
317
|
+
}
|
|
318
|
+
return filtered;
|
|
319
|
+
};
|
|
320
|
+
const composeTrackingSink = (sink, ctx) => {
|
|
321
|
+
let composed = sink;
|
|
322
|
+
for (const plugin of list) {
|
|
323
|
+
if (!plugin.wrapTrackingSink || !composed) continue;
|
|
324
|
+
composed = plugin.wrapTrackingSink(composed, ctx);
|
|
325
|
+
}
|
|
326
|
+
return composed;
|
|
327
|
+
};
|
|
328
|
+
const scoreAssessment = (input, ctx) => {
|
|
329
|
+
for (const plugin of list) {
|
|
330
|
+
if (plugin.kind !== "assessment" || !plugin.scoreAssessment) continue;
|
|
331
|
+
const result = plugin.scoreAssessment(input, ctx);
|
|
332
|
+
if (result) return result;
|
|
333
|
+
}
|
|
334
|
+
return null;
|
|
335
|
+
};
|
|
336
|
+
return {
|
|
337
|
+
plugins: list,
|
|
338
|
+
setupAll,
|
|
339
|
+
disposeAll,
|
|
340
|
+
runTelemetry,
|
|
341
|
+
runTelemetryBatch,
|
|
342
|
+
composeTrackingSink,
|
|
343
|
+
scoreAssessment
|
|
344
|
+
};
|
|
345
|
+
}
|
|
276
346
|
// Annotate the CommonJS export names for ESM import in node:
|
|
277
347
|
0 && (module.exports = {
|
|
278
348
|
ID_MAX_LENGTH,
|
|
@@ -281,8 +351,10 @@ function nowIso() {
|
|
|
281
351
|
assertValidId,
|
|
282
352
|
buildLessonkitUrn,
|
|
283
353
|
buildTelemetryCatalog,
|
|
354
|
+
createPluginHost,
|
|
284
355
|
createSessionId,
|
|
285
356
|
createTrackingClient,
|
|
357
|
+
defineLessonkitPlugin,
|
|
286
358
|
deriveId,
|
|
287
359
|
nowIso,
|
|
288
360
|
slugifyId,
|
package/dist/index.d.cts
CHANGED
|
@@ -143,4 +143,65 @@ declare function createSessionId(): string;
|
|
|
143
143
|
|
|
144
144
|
declare function nowIso(): string;
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
/** Plugin category — aligns with roadmap extension areas. */
|
|
147
|
+
type LessonkitPluginKind = "analytics" | "lms" | "assessment" | "interaction" | "ai";
|
|
148
|
+
type LessonkitPluginContext = {
|
|
149
|
+
courseId: CourseId;
|
|
150
|
+
sessionId?: string;
|
|
151
|
+
attemptId?: string;
|
|
152
|
+
};
|
|
153
|
+
type AssessmentScoreInput = {
|
|
154
|
+
checkId: string;
|
|
155
|
+
lessonId?: string;
|
|
156
|
+
response: unknown;
|
|
157
|
+
};
|
|
158
|
+
type AssessmentScoreResult = {
|
|
159
|
+
score: number;
|
|
160
|
+
maxScore?: number;
|
|
161
|
+
passed?: boolean;
|
|
162
|
+
feedback?: string;
|
|
163
|
+
};
|
|
164
|
+
/** Metadata for custom interaction blocks (renderer wiring stays in app code until 1.0). */
|
|
165
|
+
type InteractionBlockRegistration = {
|
|
166
|
+
blockType: string;
|
|
167
|
+
catalogVersion?: string;
|
|
168
|
+
description?: string;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* Framework plugin contract (v1). Plugins are plain objects registered on `LessonkitProvider`.
|
|
172
|
+
* Marketplace / dynamic loading are out of scope until Studio post-1.0.
|
|
173
|
+
*/
|
|
174
|
+
type LessonkitPlugin = {
|
|
175
|
+
id: string;
|
|
176
|
+
version: string;
|
|
177
|
+
kind: LessonkitPluginKind;
|
|
178
|
+
name?: string;
|
|
179
|
+
setup?: (ctx: LessonkitPluginContext) => void;
|
|
180
|
+
dispose?: () => void;
|
|
181
|
+
/**
|
|
182
|
+
* Observe or filter telemetry before tracking/xAPI. Return `null` to drop the event.
|
|
183
|
+
* Hooks run in registration order.
|
|
184
|
+
*/
|
|
185
|
+
onTelemetry?: (event: TelemetryEvent, ctx: LessonkitPluginContext) => TelemetryEvent | null;
|
|
186
|
+
/** Optional batch observer (analytics); receives events after per-event hooks. */
|
|
187
|
+
onTelemetryBatch?: (events: TelemetryEvent[], ctx: LessonkitPluginContext) => void;
|
|
188
|
+
/** Wrap the configured tracking sink (analytics plugins). First registered = innermost. */
|
|
189
|
+
wrapTrackingSink?: (sink: TelemetrySink, ctx: LessonkitPluginContext) => TelemetrySink;
|
|
190
|
+
/** Optional assessment scoring override (assessment plugins). */
|
|
191
|
+
scoreAssessment?: (input: AssessmentScoreInput, ctx: LessonkitPluginContext) => AssessmentScoreResult | null;
|
|
192
|
+
/** Declare custom interaction block types for generators/tooling. */
|
|
193
|
+
interactionBlocks?: InteractionBlockRegistration[];
|
|
194
|
+
};
|
|
195
|
+
type PluginHost = {
|
|
196
|
+
readonly plugins: readonly LessonkitPlugin[];
|
|
197
|
+
setupAll: (ctx: LessonkitPluginContext) => void;
|
|
198
|
+
disposeAll: () => void;
|
|
199
|
+
runTelemetry: (event: TelemetryEvent, ctx: LessonkitPluginContext) => TelemetryEvent | null;
|
|
200
|
+
runTelemetryBatch: (events: TelemetryEvent[], ctx: LessonkitPluginContext) => TelemetryEvent[];
|
|
201
|
+
composeTrackingSink: (sink: TelemetrySink | undefined, ctx: LessonkitPluginContext) => TelemetrySink | undefined;
|
|
202
|
+
scoreAssessment: (input: AssessmentScoreInput, ctx: LessonkitPluginContext) => AssessmentScoreResult | null;
|
|
203
|
+
};
|
|
204
|
+
declare function defineLessonkitPlugin(plugin: LessonkitPlugin): LessonkitPlugin;
|
|
205
|
+
declare function createPluginHost(plugins?: readonly LessonkitPlugin[]): PluginHost;
|
|
206
|
+
|
|
207
|
+
export { type AssessmentScoreInput, type AssessmentScoreResult, type BlockId, type CheckId, type CourseId, ID_MAX_LENGTH, ID_PATTERN, type IdentityValidationIssue, type IdentityValidationResult, type InteractionBlockRegistration, type InteractionData, type LessonId, type LessonLifecycleData, type LessonkitPlugin, type LessonkitPluginContext, type LessonkitPluginKind, type LessonkitUrnParts, type PluginHost, type QuizAnsweredData, type QuizCompletedData, TELEMETRY_EVENT_CATALOG, type TelemetryBatchSink, type TelemetryCatalogEntry, type TelemetryEvent, type TelemetryEventBase, type TelemetryEventName, type TelemetrySink, type TelemetryUser, type TrackingClient, assertValidId, buildLessonkitUrn, buildTelemetryCatalog, createPluginHost, createSessionId, createTrackingClient, defineLessonkitPlugin, deriveId, nowIso, slugifyId, telemetryCatalogVersion, validateId };
|
package/dist/index.d.ts
CHANGED
|
@@ -143,4 +143,65 @@ declare function createSessionId(): string;
|
|
|
143
143
|
|
|
144
144
|
declare function nowIso(): string;
|
|
145
145
|
|
|
146
|
-
|
|
146
|
+
/** Plugin category — aligns with roadmap extension areas. */
|
|
147
|
+
type LessonkitPluginKind = "analytics" | "lms" | "assessment" | "interaction" | "ai";
|
|
148
|
+
type LessonkitPluginContext = {
|
|
149
|
+
courseId: CourseId;
|
|
150
|
+
sessionId?: string;
|
|
151
|
+
attemptId?: string;
|
|
152
|
+
};
|
|
153
|
+
type AssessmentScoreInput = {
|
|
154
|
+
checkId: string;
|
|
155
|
+
lessonId?: string;
|
|
156
|
+
response: unknown;
|
|
157
|
+
};
|
|
158
|
+
type AssessmentScoreResult = {
|
|
159
|
+
score: number;
|
|
160
|
+
maxScore?: number;
|
|
161
|
+
passed?: boolean;
|
|
162
|
+
feedback?: string;
|
|
163
|
+
};
|
|
164
|
+
/** Metadata for custom interaction blocks (renderer wiring stays in app code until 1.0). */
|
|
165
|
+
type InteractionBlockRegistration = {
|
|
166
|
+
blockType: string;
|
|
167
|
+
catalogVersion?: string;
|
|
168
|
+
description?: string;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* Framework plugin contract (v1). Plugins are plain objects registered on `LessonkitProvider`.
|
|
172
|
+
* Marketplace / dynamic loading are out of scope until Studio post-1.0.
|
|
173
|
+
*/
|
|
174
|
+
type LessonkitPlugin = {
|
|
175
|
+
id: string;
|
|
176
|
+
version: string;
|
|
177
|
+
kind: LessonkitPluginKind;
|
|
178
|
+
name?: string;
|
|
179
|
+
setup?: (ctx: LessonkitPluginContext) => void;
|
|
180
|
+
dispose?: () => void;
|
|
181
|
+
/**
|
|
182
|
+
* Observe or filter telemetry before tracking/xAPI. Return `null` to drop the event.
|
|
183
|
+
* Hooks run in registration order.
|
|
184
|
+
*/
|
|
185
|
+
onTelemetry?: (event: TelemetryEvent, ctx: LessonkitPluginContext) => TelemetryEvent | null;
|
|
186
|
+
/** Optional batch observer (analytics); receives events after per-event hooks. */
|
|
187
|
+
onTelemetryBatch?: (events: TelemetryEvent[], ctx: LessonkitPluginContext) => void;
|
|
188
|
+
/** Wrap the configured tracking sink (analytics plugins). First registered = innermost. */
|
|
189
|
+
wrapTrackingSink?: (sink: TelemetrySink, ctx: LessonkitPluginContext) => TelemetrySink;
|
|
190
|
+
/** Optional assessment scoring override (assessment plugins). */
|
|
191
|
+
scoreAssessment?: (input: AssessmentScoreInput, ctx: LessonkitPluginContext) => AssessmentScoreResult | null;
|
|
192
|
+
/** Declare custom interaction block types for generators/tooling. */
|
|
193
|
+
interactionBlocks?: InteractionBlockRegistration[];
|
|
194
|
+
};
|
|
195
|
+
type PluginHost = {
|
|
196
|
+
readonly plugins: readonly LessonkitPlugin[];
|
|
197
|
+
setupAll: (ctx: LessonkitPluginContext) => void;
|
|
198
|
+
disposeAll: () => void;
|
|
199
|
+
runTelemetry: (event: TelemetryEvent, ctx: LessonkitPluginContext) => TelemetryEvent | null;
|
|
200
|
+
runTelemetryBatch: (events: TelemetryEvent[], ctx: LessonkitPluginContext) => TelemetryEvent[];
|
|
201
|
+
composeTrackingSink: (sink: TelemetrySink | undefined, ctx: LessonkitPluginContext) => TelemetrySink | undefined;
|
|
202
|
+
scoreAssessment: (input: AssessmentScoreInput, ctx: LessonkitPluginContext) => AssessmentScoreResult | null;
|
|
203
|
+
};
|
|
204
|
+
declare function defineLessonkitPlugin(plugin: LessonkitPlugin): LessonkitPlugin;
|
|
205
|
+
declare function createPluginHost(plugins?: readonly LessonkitPlugin[]): PluginHost;
|
|
206
|
+
|
|
207
|
+
export { type AssessmentScoreInput, type AssessmentScoreResult, type BlockId, type CheckId, type CourseId, ID_MAX_LENGTH, ID_PATTERN, type IdentityValidationIssue, type IdentityValidationResult, type InteractionBlockRegistration, type InteractionData, type LessonId, type LessonLifecycleData, type LessonkitPlugin, type LessonkitPluginContext, type LessonkitPluginKind, type LessonkitUrnParts, type PluginHost, type QuizAnsweredData, type QuizCompletedData, TELEMETRY_EVENT_CATALOG, type TelemetryBatchSink, type TelemetryCatalogEntry, type TelemetryEvent, type TelemetryEventBase, type TelemetryEventName, type TelemetrySink, type TelemetryUser, type TrackingClient, assertValidId, buildLessonkitUrn, buildTelemetryCatalog, createPluginHost, createSessionId, createTrackingClient, defineLessonkitPlugin, deriveId, nowIso, slugifyId, telemetryCatalogVersion, validateId };
|
package/dist/index.js
CHANGED
|
@@ -235,6 +235,74 @@ function createSessionId() {
|
|
|
235
235
|
function nowIso() {
|
|
236
236
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
237
237
|
}
|
|
238
|
+
|
|
239
|
+
// src/plugins.ts
|
|
240
|
+
function defineLessonkitPlugin(plugin) {
|
|
241
|
+
return plugin;
|
|
242
|
+
}
|
|
243
|
+
function warnDuplicatePlugin(id) {
|
|
244
|
+
const g = globalThis;
|
|
245
|
+
if (typeof g.process !== "undefined" && g.process.env?.NODE_ENV === "production") return;
|
|
246
|
+
console.warn(`[lessonkit] plugin id "${id}" was registered more than once; using the latest definition`);
|
|
247
|
+
}
|
|
248
|
+
function createPluginHost(plugins = []) {
|
|
249
|
+
const registry = /* @__PURE__ */ new Map();
|
|
250
|
+
for (const plugin of plugins) {
|
|
251
|
+
if (registry.has(plugin.id)) warnDuplicatePlugin(plugin.id);
|
|
252
|
+
registry.set(plugin.id, plugin);
|
|
253
|
+
}
|
|
254
|
+
const list = [...registry.values()];
|
|
255
|
+
const setupAll = (ctx) => {
|
|
256
|
+
for (const plugin of list) {
|
|
257
|
+
plugin.setup?.(ctx);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
const disposeAll = () => {
|
|
261
|
+
for (let i = list.length - 1; i >= 0; i -= 1) {
|
|
262
|
+
list[i]?.dispose?.();
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
const runTelemetry = (event, ctx) => {
|
|
266
|
+
let current = event;
|
|
267
|
+
for (const plugin of list) {
|
|
268
|
+
if (!plugin.onTelemetry || current === null) continue;
|
|
269
|
+
current = plugin.onTelemetry(current, ctx);
|
|
270
|
+
}
|
|
271
|
+
return current;
|
|
272
|
+
};
|
|
273
|
+
const runTelemetryBatch = (events, ctx) => {
|
|
274
|
+
const filtered = events.map((event) => runTelemetry(event, ctx)).filter((event) => event !== null);
|
|
275
|
+
for (const plugin of list) {
|
|
276
|
+
plugin.onTelemetryBatch?.(filtered, ctx);
|
|
277
|
+
}
|
|
278
|
+
return filtered;
|
|
279
|
+
};
|
|
280
|
+
const composeTrackingSink = (sink, ctx) => {
|
|
281
|
+
let composed = sink;
|
|
282
|
+
for (const plugin of list) {
|
|
283
|
+
if (!plugin.wrapTrackingSink || !composed) continue;
|
|
284
|
+
composed = plugin.wrapTrackingSink(composed, ctx);
|
|
285
|
+
}
|
|
286
|
+
return composed;
|
|
287
|
+
};
|
|
288
|
+
const scoreAssessment = (input, ctx) => {
|
|
289
|
+
for (const plugin of list) {
|
|
290
|
+
if (plugin.kind !== "assessment" || !plugin.scoreAssessment) continue;
|
|
291
|
+
const result = plugin.scoreAssessment(input, ctx);
|
|
292
|
+
if (result) return result;
|
|
293
|
+
}
|
|
294
|
+
return null;
|
|
295
|
+
};
|
|
296
|
+
return {
|
|
297
|
+
plugins: list,
|
|
298
|
+
setupAll,
|
|
299
|
+
disposeAll,
|
|
300
|
+
runTelemetry,
|
|
301
|
+
runTelemetryBatch,
|
|
302
|
+
composeTrackingSink,
|
|
303
|
+
scoreAssessment
|
|
304
|
+
};
|
|
305
|
+
}
|
|
238
306
|
export {
|
|
239
307
|
ID_MAX_LENGTH,
|
|
240
308
|
ID_PATTERN,
|
|
@@ -242,8 +310,10 @@ export {
|
|
|
242
310
|
assertValidId,
|
|
243
311
|
buildLessonkitUrn,
|
|
244
312
|
buildTelemetryCatalog,
|
|
313
|
+
createPluginHost,
|
|
245
314
|
createSessionId,
|
|
246
315
|
createTrackingClient,
|
|
316
|
+
defineLessonkitPlugin,
|
|
247
317
|
deriveId,
|
|
248
318
|
nowIso,
|
|
249
319
|
slugifyId,
|