@lssm/example.personalization 0.0.0-canary-20251217063201 → 0.0.0-canary-20251217072406

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.
Files changed (63) hide show
  1. package/.turbo/turbo-build$colon$bundle.log +95 -86
  2. package/.turbo/turbo-build.log +96 -20
  3. package/CHANGELOG.md +7 -6
  4. package/dist/behavior-tracking.js +49 -1
  5. package/dist/docs/index.js +1 -1
  6. package/dist/docs/personalization.docblock.js +29 -8
  7. package/dist/example.js +38 -1
  8. package/dist/index.js +7 -1
  9. package/dist/libs/contracts/dist/docs/PUBLISHING.docblock.js +16 -76
  10. package/dist/libs/contracts/dist/docs/accessibility_wcag_compliance_specs.docblock.js +16 -350
  11. package/dist/libs/contracts/dist/docs/index.js +29 -1
  12. package/dist/libs/contracts/dist/docs/presentations.js +71 -1
  13. package/dist/libs/contracts/dist/docs/registry.js +44 -1
  14. package/dist/libs/contracts/dist/docs/tech/PHASE_1_QUICKSTART.docblock.js +16 -383
  15. package/dist/libs/contracts/dist/docs/tech/PHASE_2_AI_NATIVE_OPERATIONS.docblock.js +16 -68
  16. package/dist/libs/contracts/dist/docs/tech/PHASE_3_AUTO_EVOLUTION.docblock.js +16 -140
  17. package/dist/libs/contracts/dist/docs/tech/PHASE_4_PERSONALIZATION_ENGINE.docblock.js +16 -86
  18. package/dist/libs/contracts/dist/docs/tech/PHASE_5_ZERO_TOUCH_OPERATIONS.docblock.js +16 -1
  19. package/dist/libs/contracts/dist/docs/tech/auth/better-auth-nextjs.docblock.js +24 -2
  20. package/dist/libs/contracts/dist/docs/tech/contracts/openapi-export.docblock.js +21 -2
  21. package/dist/libs/contracts/dist/docs/tech/lifecycle-stage-system.docblock.js +16 -213
  22. package/dist/libs/contracts/dist/docs/tech/llm/llm-integration.docblock.js +73 -5
  23. package/dist/libs/contracts/dist/docs/tech/mcp-endpoints.docblock.js +37 -1
  24. package/dist/libs/contracts/dist/docs/tech/presentation-runtime.docblock.js +16 -1
  25. package/dist/libs/contracts/dist/docs/tech/schema/README.docblock.js +20 -262
  26. package/dist/libs/contracts/dist/docs/tech/studio/learning-events.docblock.js +48 -1
  27. package/dist/libs/contracts/dist/docs/tech/studio/learning-journeys.docblock.js +24 -2
  28. package/dist/libs/contracts/dist/docs/tech/studio/platform-admin-panel.docblock.js +23 -2
  29. package/dist/libs/contracts/dist/docs/tech/studio/project-access-teams.docblock.js +25 -16
  30. package/dist/libs/contracts/dist/docs/tech/studio/project-routing.docblock.js +67 -1
  31. package/dist/libs/contracts/dist/docs/tech/studio/sandbox-unlogged.docblock.js +22 -2
  32. package/dist/libs/contracts/dist/docs/tech/studio/team-invitations.docblock.js +40 -36
  33. package/dist/libs/contracts/dist/docs/tech/studio/workspace-ops.docblock.js +47 -1
  34. package/dist/libs/contracts/dist/docs/tech/studio/workspaces.docblock.js +23 -2
  35. package/dist/libs/contracts/dist/docs/tech/telemetry-ingest.docblock.js +36 -3
  36. package/dist/libs/contracts/dist/docs/tech/templates/runtime.docblock.js +20 -1
  37. package/dist/libs/contracts/dist/docs/tech/vscode-extension.docblock.js +36 -3
  38. package/dist/libs/contracts/dist/docs/tech/workflows/overview.docblock.js +20 -1
  39. package/dist/libs/logger/dist/context.node.js +78 -1
  40. package/dist/libs/logger/dist/elysia-plugin.js +3 -1
  41. package/dist/libs/logger/dist/formatters.js +163 -9
  42. package/dist/libs/logger/dist/index.js +7 -1
  43. package/dist/libs/logger/dist/logger.node.js +189 -1
  44. package/dist/libs/logger/dist/timer.js +126 -1
  45. package/dist/libs/logger/dist/tracer.node.js +115 -1
  46. package/dist/libs/logger/dist/types.js +13 -1
  47. package/dist/libs/overlay-engine/dist/index.js +6 -1
  48. package/dist/libs/overlay-engine/dist/merger.js +106 -1
  49. package/dist/libs/overlay-engine/dist/registry.js +106 -1
  50. package/dist/libs/overlay-engine/dist/runtime.js +53 -1
  51. package/dist/libs/overlay-engine/dist/signer.js +45 -1
  52. package/dist/libs/overlay-engine/dist/spec.js +7 -1
  53. package/dist/libs/overlay-engine/dist/validator.js +93 -1
  54. package/dist/libs/personalization/dist/analyzer.js +54 -1
  55. package/dist/libs/personalization/dist/store.js +58 -1
  56. package/dist/libs/personalization/dist/tracker.js +92 -1
  57. package/dist/libs/workflow-composer/dist/composer.js +28 -1
  58. package/dist/libs/workflow-composer/dist/injector.js +72 -1
  59. package/dist/libs/workflow-composer/dist/validator.js +36 -1
  60. package/dist/overlay-customization.js +53 -1
  61. package/dist/workflow-extension.js +67 -1
  62. package/package.json +9 -8
  63. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1,53 @@
1
- import{e}from"./merger.js";var t=class{registry;audit;constructor(e){this.registry=e.registry,this.audit=e.audit}apply(t){let r=t.overlays??this.registry.forContext({capability:t.capability,workflow:t.workflow,dataView:t.dataView,presentation:t.presentation,operation:t.operation,tenantId:t.tenantId,role:t.role,userId:t.userId,device:t.device,tags:t.tags}),i=e(t.target,r,{strict:t.strict}),a=n(t);return r.forEach(e=>{this.audit?.({overlay:{overlayId:e.overlayId,version:e.version},context:a,timestamp:new Date().toISOString()})}),{target:i,overlaysApplied:r}}};function n(e){return{tenantId:e.tenantId,role:e.role,userId:e.userId,device:e.device,tags:e.tags}}export{t};
1
+ import { applyOverlayModifications } from "./merger.js";
2
+
3
+ //#region ../../libs/overlay-engine/dist/runtime.js
4
+ var OverlayEngine = class {
5
+ registry;
6
+ audit;
7
+ constructor(options) {
8
+ this.registry = options.registry;
9
+ this.audit = options.audit;
10
+ }
11
+ apply(params) {
12
+ const overlays = params.overlays ?? this.registry.forContext({
13
+ capability: params.capability,
14
+ workflow: params.workflow,
15
+ dataView: params.dataView,
16
+ presentation: params.presentation,
17
+ operation: params.operation,
18
+ tenantId: params.tenantId,
19
+ role: params.role,
20
+ userId: params.userId,
21
+ device: params.device,
22
+ tags: params.tags
23
+ });
24
+ const merged = applyOverlayModifications(params.target, overlays, { strict: params.strict });
25
+ const context = extractContext(params);
26
+ overlays.forEach((overlay) => {
27
+ this.audit?.({
28
+ overlay: {
29
+ overlayId: overlay.overlayId,
30
+ version: overlay.version
31
+ },
32
+ context,
33
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
34
+ });
35
+ });
36
+ return {
37
+ target: merged,
38
+ overlaysApplied: overlays
39
+ };
40
+ }
41
+ };
42
+ function extractContext(params) {
43
+ return {
44
+ tenantId: params.tenantId,
45
+ role: params.role,
46
+ userId: params.userId,
47
+ device: params.device,
48
+ tags: params.tags
49
+ };
50
+ }
51
+
52
+ //#endregion
53
+ export { OverlayEngine };
@@ -1 +1,45 @@
1
- import e from"fast-json-stable-stringify";import{constants as t,createPrivateKey as n,createPublicKey as r,sign as i}from"crypto";function a(e,a,c={}){let l=c.algorithm??`ed25519`,u=typeof a==`string`||Buffer.isBuffer(a)?n(a):a,d=Buffer.from(o(e),`utf8`),f;if(l===`ed25519`)f=i(null,d,u);else if(l===`rsa-pss-sha256`)f=i(`sha256`,d,{key:u,padding:t.RSA_PKCS1_PSS_PADDING,saltLength:32});else throw Error(`Unsupported overlay signature algorithm: ${l}`);let p=c.publicKey??r(u).export({format:`pem`,type:`spki`}).toString();return{...e,signature:{algorithm:l,signature:f.toString(`base64`),publicKey:p,keyId:c.keyId,issuedAt:s(c.issuedAt)??new Date().toISOString(),expiresAt:s(c.expiresAt),metadata:c.metadata}}}function o(t){let{signature:n,...r}=t;return e(r)}function s(e){if(e)return typeof e==`string`?new Date(e).toISOString():e.toISOString()}export{o as c,a as o};
1
+ import stringify from "fast-json-stable-stringify";
2
+ import { constants, createPrivateKey, createPublicKey, sign } from "crypto";
3
+
4
+ //#region ../../libs/overlay-engine/dist/signer.js
5
+ function signOverlay(spec, privateKey, options = {}) {
6
+ const algorithm = options.algorithm ?? "ed25519";
7
+ const keyObject = typeof privateKey === "string" || Buffer.isBuffer(privateKey) ? createPrivateKey(privateKey) : privateKey;
8
+ const payload = Buffer.from(canonicalizeOverlay(spec), "utf8");
9
+ let rawSignature;
10
+ if (algorithm === "ed25519") rawSignature = sign(null, payload, keyObject);
11
+ else if (algorithm === "rsa-pss-sha256") rawSignature = sign("sha256", payload, {
12
+ key: keyObject,
13
+ padding: constants.RSA_PKCS1_PSS_PADDING,
14
+ saltLength: 32
15
+ });
16
+ else throw new Error(`Unsupported overlay signature algorithm: ${algorithm}`);
17
+ const publicKey = options.publicKey ?? createPublicKey(keyObject).export({
18
+ format: "pem",
19
+ type: "spki"
20
+ }).toString();
21
+ return {
22
+ ...spec,
23
+ signature: {
24
+ algorithm,
25
+ signature: rawSignature.toString("base64"),
26
+ publicKey,
27
+ keyId: options.keyId,
28
+ issuedAt: toIso(options.issuedAt) ?? (/* @__PURE__ */ new Date()).toISOString(),
29
+ expiresAt: toIso(options.expiresAt),
30
+ metadata: options.metadata
31
+ }
32
+ };
33
+ }
34
+ function canonicalizeOverlay(spec) {
35
+ const { signature, ...rest } = spec;
36
+ return stringify(rest);
37
+ }
38
+ function toIso(value) {
39
+ if (!value) return;
40
+ if (typeof value === "string") return new Date(value).toISOString();
41
+ return value.toISOString();
42
+ }
43
+
44
+ //#endregion
45
+ export { canonicalizeOverlay, signOverlay };
@@ -1 +1,7 @@
1
- function e(e){return e}export{e as t};
1
+ //#region ../../libs/overlay-engine/dist/spec.js
2
+ function defineOverlay(spec) {
3
+ return spec;
4
+ }
5
+
6
+ //#endregion
7
+ export { defineOverlay };
@@ -1 +1,93 @@
1
- const e=[`capability`,`workflow`,`dataView`,`presentation`,`operation`],t=e=>n(e);function n(t){let n=[];return t.overlayId?.trim()||n.push({code:`overlay.id`,message:`overlayId is required`,path:[`overlayId`]}),t.version?.trim()||n.push({code:`overlay.version`,message:`version is required`,path:[`version`]}),e.some(e=>{let n=t.appliesTo?.[e];return typeof n==`string`&&n.trim().length>0})||n.push({code:`overlay.target`,message:`Overlay must specify at least one target (capability, workflow, dataView, presentation, or operation).`,path:[`appliesTo`]}),t.modifications?.length?t.modifications.forEach((e,t)=>{r(e,[`modifications`,String(t)],n)}):n.push({code:`overlay.modifications.empty`,message:`Overlay must include at least one modification.`,path:[`modifications`]}),{valid:n.length===0,issues:n}}function r(e,t,n){let r=(e,r,i)=>{n.push({code:e,message:r,path:i?[...t,...i]:t})};switch(i(e)&&(e.field?.trim()||r(`overlay.mod.field`,`field is required for this modification`,[`field`])),e.type){case`renameLabel`:e.newLabel?.trim()||r(`overlay.mod.renameLabel.newLabel`,`newLabel is required`,[`newLabel`]);break;case`reorderFields`:{e.fields?.length||r(`overlay.mod.reorderFields.fields`,`fields list cannot be empty`,[`fields`]);let t=new Set;for(let n of e.fields??[]){if(!n?.trim()){r(`overlay.mod.reorderFields.fields.blank`,`fields entries must be non-empty`);break}if(t.has(n)){r(`overlay.mod.reorderFields.fields.duplicate`,`field "${n}" was listed multiple times`);break}t.add(n)}break}case`setDefault`:e.value===void 0&&r(`overlay.mod.setDefault.value`,`value is required`,[`value`]);break;case`addHelpText`:e.text?.trim()||r(`overlay.mod.addHelpText.text`,`text is required`,[`text`]);break;case`makeRequired`:case`hideField`:break;default:{let t=e;throw Error(`Unsupported overlay modification ${t?.type??`unknown`}`)}}}function i(e){return`field`in e}export{n,t};
1
+ //#region ../../libs/overlay-engine/dist/validator.js
2
+ const TARGET_KEYS = [
3
+ "capability",
4
+ "workflow",
5
+ "dataView",
6
+ "presentation",
7
+ "operation"
8
+ ];
9
+ const defaultOverlayValidator = (spec) => validateOverlaySpec(spec);
10
+ function validateOverlaySpec(spec) {
11
+ const issues = [];
12
+ if (!spec.overlayId?.trim()) issues.push({
13
+ code: "overlay.id",
14
+ message: "overlayId is required",
15
+ path: ["overlayId"]
16
+ });
17
+ if (!spec.version?.trim()) issues.push({
18
+ code: "overlay.version",
19
+ message: "version is required",
20
+ path: ["version"]
21
+ });
22
+ if (!TARGET_KEYS.some((key) => {
23
+ const value = spec.appliesTo?.[key];
24
+ return typeof value === "string" && value.trim().length > 0;
25
+ })) issues.push({
26
+ code: "overlay.target",
27
+ message: "Overlay must specify at least one target (capability, workflow, dataView, presentation, or operation).",
28
+ path: ["appliesTo"]
29
+ });
30
+ if (!spec.modifications?.length) issues.push({
31
+ code: "overlay.modifications.empty",
32
+ message: "Overlay must include at least one modification.",
33
+ path: ["modifications"]
34
+ });
35
+ else spec.modifications.forEach((mod, idx) => {
36
+ validateModification(mod, ["modifications", String(idx)], issues);
37
+ });
38
+ return {
39
+ valid: issues.length === 0,
40
+ issues
41
+ };
42
+ }
43
+ function validateModification(modification, path, issues) {
44
+ const push = (code, message, extraPath) => {
45
+ issues.push({
46
+ code,
47
+ message,
48
+ path: extraPath ? [...path, ...extraPath] : path
49
+ });
50
+ };
51
+ if (isFieldModification(modification)) {
52
+ if (!modification.field?.trim()) push("overlay.mod.field", "field is required for this modification", ["field"]);
53
+ }
54
+ switch (modification.type) {
55
+ case "renameLabel":
56
+ if (!modification.newLabel?.trim()) push("overlay.mod.renameLabel.newLabel", "newLabel is required", ["newLabel"]);
57
+ break;
58
+ case "reorderFields": {
59
+ if (!modification.fields?.length) push("overlay.mod.reorderFields.fields", "fields list cannot be empty", ["fields"]);
60
+ const seen = /* @__PURE__ */ new Set();
61
+ for (const field of modification.fields ?? []) {
62
+ if (!field?.trim()) {
63
+ push("overlay.mod.reorderFields.fields.blank", "fields entries must be non-empty");
64
+ break;
65
+ }
66
+ if (seen.has(field)) {
67
+ push("overlay.mod.reorderFields.fields.duplicate", `field "${field}" was listed multiple times`);
68
+ break;
69
+ }
70
+ seen.add(field);
71
+ }
72
+ break;
73
+ }
74
+ case "setDefault":
75
+ if (modification.value === void 0) push("overlay.mod.setDefault.value", "value is required", ["value"]);
76
+ break;
77
+ case "addHelpText":
78
+ if (!modification.text?.trim()) push("overlay.mod.addHelpText.text", "text is required", ["text"]);
79
+ break;
80
+ case "makeRequired":
81
+ case "hideField": break;
82
+ default: {
83
+ const exhaustive = modification;
84
+ throw new Error(`Unsupported overlay modification ${exhaustive?.type ?? "unknown"}`);
85
+ }
86
+ }
87
+ }
88
+ function isFieldModification(mod) {
89
+ return "field" in mod;
90
+ }
91
+
92
+ //#endregion
93
+ export { defaultOverlayValidator, validateOverlaySpec };
@@ -1 +1,54 @@
1
- var e=class{constructor(e,t={}){this.store=e,this.options=t}async analyze(e){let n={tenantId:e.tenantId,userId:e.userId,role:e.role};return e.windowMs&&(n.since=Date.now()-e.windowMs),t(await this.store.summarize(n),this.options)}};function t(e,t){let r=t.fieldInactivityThreshold??3,i=t.minSamples??10,a=[],o=[];for(let[t,n]of Object.entries(e.fieldCounts))n<=r&&a.push(t),n>=r*4&&o.push(t);let s=Object.entries(e.workflowStepCounts).flatMap(([e,t])=>{let n=Object.values(t).reduce((e,t)=>e+t,0);return!n||n<i?[]:Object.entries(t).filter(([,e])=>e/n<.4).map(([t,r])=>({workflow:e,step:t,dropRate:1-r/n}))}),c=n(e);return{unusedFields:a,suggestedHiddenFields:a.slice(0,5),frequentlyUsedFields:o.slice(0,10),workflowBottlenecks:s,layoutPreference:c}}function n(e){let t=Object.keys(e.fieldCounts).length;if(t)return t>=15?`table`:t>=8?`grid`:`form`}export{e};
1
+ //#region ../../libs/personalization/dist/analyzer.js
2
+ const DEFAULT_THRESHOLD = 3;
3
+ var BehaviorAnalyzer = class {
4
+ constructor(store, options = {}) {
5
+ this.store = store;
6
+ this.options = options;
7
+ }
8
+ async analyze(params) {
9
+ const query = {
10
+ tenantId: params.tenantId,
11
+ userId: params.userId,
12
+ role: params.role
13
+ };
14
+ if (params.windowMs) query.since = Date.now() - params.windowMs;
15
+ return buildInsights(await this.store.summarize(query), this.options);
16
+ }
17
+ };
18
+ function buildInsights(summary, options) {
19
+ const threshold = options.fieldInactivityThreshold ?? DEFAULT_THRESHOLD;
20
+ const minSamples = options.minSamples ?? 10;
21
+ const ignoredFields = [];
22
+ const frequentlyUsedFields = [];
23
+ for (const [field, count] of Object.entries(summary.fieldCounts)) {
24
+ if (count <= threshold) ignoredFields.push(field);
25
+ if (count >= threshold * 4) frequentlyUsedFields.push(field);
26
+ }
27
+ const workflowBottlenecks = Object.entries(summary.workflowStepCounts).flatMap(([workflow, steps]) => {
28
+ const total = Object.values(steps).reduce((acc, value) => acc + value, 0);
29
+ if (!total || total < minSamples) return [];
30
+ return Object.entries(steps).filter(([, count]) => count / total < .4).map(([step, count]) => ({
31
+ workflow,
32
+ step,
33
+ dropRate: 1 - count / total
34
+ }));
35
+ });
36
+ const layoutPreference = detectLayout(summary);
37
+ return {
38
+ unusedFields: ignoredFields,
39
+ suggestedHiddenFields: ignoredFields.slice(0, 5),
40
+ frequentlyUsedFields: frequentlyUsedFields.slice(0, 10),
41
+ workflowBottlenecks,
42
+ layoutPreference
43
+ };
44
+ }
45
+ function detectLayout(summary) {
46
+ const fieldCount = Object.keys(summary.fieldCounts).length;
47
+ if (!fieldCount) return;
48
+ if (fieldCount >= 15) return "table";
49
+ if (fieldCount >= 8) return "grid";
50
+ return "form";
51
+ }
52
+
53
+ //#endregion
54
+ export { BehaviorAnalyzer };
@@ -1 +1,58 @@
1
- var e=class{events=[];async record(e){this.events.push(e)}async bulkRecord(e){this.events.push(...e)}async query(e){return t(this.events,e)}async summarize(e){let t=await this.query(e),n={fieldCounts:{},featureCounts:{},workflowStepCounts:{},totalEvents:t.length};return t.forEach(e=>{switch(e.type){case`field_access`:n.fieldCounts[e.field]=(n.fieldCounts[e.field]??0)+1;break;case`feature_usage`:n.featureCounts[e.feature]=(n.featureCounts[e.feature]??0)+1;break;case`workflow_step`:{let t=n.workflowStepCounts[e.workflow]??={};t[e.step]=(t[e.step]??0)+1;break}default:break}}),n}async clear(){this.events=[]}};function t(e,t){return e.filter(e=>!(t.tenantId&&e.tenantId!==t.tenantId||t.userId&&e.userId!==t.userId||t.role&&e.role!==t.role||t.since&&e.timestamp<t.since||t.until&&e.timestamp>t.until||t.operation&&e.type===`field_access`&&e.operation!==t.operation||t.feature&&e.type===`feature_usage`&&e.feature!==t.feature||t.workflow&&e.type===`workflow_step`&&e.workflow!==t.workflow))}export{e};
1
+ //#region ../../libs/personalization/dist/store.js
2
+ var InMemoryBehaviorStore = class {
3
+ events = [];
4
+ async record(event) {
5
+ this.events.push(event);
6
+ }
7
+ async bulkRecord(events) {
8
+ this.events.push(...events);
9
+ }
10
+ async query(query) {
11
+ return filterEvents(this.events, query);
12
+ }
13
+ async summarize(query) {
14
+ const events = await this.query(query);
15
+ const summary = {
16
+ fieldCounts: {},
17
+ featureCounts: {},
18
+ workflowStepCounts: {},
19
+ totalEvents: events.length
20
+ };
21
+ events.forEach((event) => {
22
+ switch (event.type) {
23
+ case "field_access":
24
+ summary.fieldCounts[event.field] = (summary.fieldCounts[event.field] ?? 0) + 1;
25
+ break;
26
+ case "feature_usage":
27
+ summary.featureCounts[event.feature] = (summary.featureCounts[event.feature] ?? 0) + 1;
28
+ break;
29
+ case "workflow_step": {
30
+ const workflow = summary.workflowStepCounts[event.workflow] ??= {};
31
+ workflow[event.step] = (workflow[event.step] ?? 0) + 1;
32
+ break;
33
+ }
34
+ default: break;
35
+ }
36
+ });
37
+ return summary;
38
+ }
39
+ async clear() {
40
+ this.events = [];
41
+ }
42
+ };
43
+ function filterEvents(events, query) {
44
+ return events.filter((event) => {
45
+ if (query.tenantId && event.tenantId !== query.tenantId) return false;
46
+ if (query.userId && event.userId !== query.userId) return false;
47
+ if (query.role && event.role !== query.role) return false;
48
+ if (query.since && event.timestamp < query.since) return false;
49
+ if (query.until && event.timestamp > query.until) return false;
50
+ if (query.operation && event.type === "field_access" && event.operation !== query.operation) return false;
51
+ if (query.feature && event.type === "feature_usage" && event.feature !== query.feature) return false;
52
+ if (query.workflow && event.type === "workflow_step" && event.workflow !== query.workflow) return false;
53
+ return true;
54
+ });
55
+ }
56
+
57
+ //#endregion
58
+ export { InMemoryBehaviorStore };
@@ -1 +1,92 @@
1
- import{metrics as e,trace as t}from"@opentelemetry/api";var n=class{store;context;tracer=t.getTracer(`lssm.personalization`,`1.0.0`);counter=e.getMeter(`lssm.personalization`,`1.0.0`).createCounter(`lssm.personalization.events`,{description:`Behavior events tracked for personalization`});buffer=[];bufferSize;flushTimer;constructor(e){this.store=e.store,this.context=e.context,this.bufferSize=e.bufferSize??25,e.autoFlushIntervalMs&&(this.flushTimer=setInterval(()=>{this.flush()},e.autoFlushIntervalMs))}trackFieldAccess(e){let t={type:`field_access`,operation:e.operation,field:e.field,timestamp:Date.now(),...this.context,metadata:{...this.context.metadata,...e.metadata}};this.enqueue(t)}trackFeatureUsage(e){let t={type:`feature_usage`,feature:e.feature,action:e.action,timestamp:Date.now(),...this.context,metadata:{...this.context.metadata,...e.metadata}};this.enqueue(t)}trackWorkflowStep(e){let t={type:`workflow_step`,workflow:e.workflow,step:e.step,status:e.status,timestamp:Date.now(),...this.context,metadata:{...this.context.metadata,...e.metadata}};this.enqueue(t)}async flush(){if(!this.buffer.length)return;let e=this.buffer;this.buffer=[],await this.store.bulkRecord(e)}async dispose(){this.flushTimer&&clearInterval(this.flushTimer),await this.flush()}enqueue(e){this.buffer.push(e),this.counter.add(1,{tenantId:this.context.tenantId,type:e.type}),this.tracer.startActiveSpan(`personalization.${e.type}`,t=>{t.setAttribute(`tenant.id`,this.context.tenantId),this.context.userId&&t.setAttribute(`user.id`,this.context.userId),t.setAttribute(`personalization.event_type`,e.type),t.end()}),this.buffer.length>=this.bufferSize&&this.flush()}};const r=e=>new n(e);export{r};
1
+ import { metrics, trace } from "@opentelemetry/api";
2
+
3
+ //#region ../../libs/personalization/dist/tracker.js
4
+ const DEFAULT_BUFFER_SIZE = 25;
5
+ var BehaviorTracker = class {
6
+ store;
7
+ context;
8
+ tracer = trace.getTracer("lssm.personalization", "1.0.0");
9
+ counter = metrics.getMeter("lssm.personalization", "1.0.0").createCounter("lssm.personalization.events", { description: "Behavior events tracked for personalization" });
10
+ buffer = [];
11
+ bufferSize;
12
+ flushTimer;
13
+ constructor(options) {
14
+ this.store = options.store;
15
+ this.context = options.context;
16
+ this.bufferSize = options.bufferSize ?? DEFAULT_BUFFER_SIZE;
17
+ if (options.autoFlushIntervalMs) this.flushTimer = setInterval(() => {
18
+ this.flush();
19
+ }, options.autoFlushIntervalMs);
20
+ }
21
+ trackFieldAccess(input) {
22
+ const event = {
23
+ type: "field_access",
24
+ operation: input.operation,
25
+ field: input.field,
26
+ timestamp: Date.now(),
27
+ ...this.context,
28
+ metadata: {
29
+ ...this.context.metadata,
30
+ ...input.metadata
31
+ }
32
+ };
33
+ this.enqueue(event);
34
+ }
35
+ trackFeatureUsage(input) {
36
+ const event = {
37
+ type: "feature_usage",
38
+ feature: input.feature,
39
+ action: input.action,
40
+ timestamp: Date.now(),
41
+ ...this.context,
42
+ metadata: {
43
+ ...this.context.metadata,
44
+ ...input.metadata
45
+ }
46
+ };
47
+ this.enqueue(event);
48
+ }
49
+ trackWorkflowStep(input) {
50
+ const event = {
51
+ type: "workflow_step",
52
+ workflow: input.workflow,
53
+ step: input.step,
54
+ status: input.status,
55
+ timestamp: Date.now(),
56
+ ...this.context,
57
+ metadata: {
58
+ ...this.context.metadata,
59
+ ...input.metadata
60
+ }
61
+ };
62
+ this.enqueue(event);
63
+ }
64
+ async flush() {
65
+ if (!this.buffer.length) return;
66
+ const events = this.buffer;
67
+ this.buffer = [];
68
+ await this.store.bulkRecord(events);
69
+ }
70
+ async dispose() {
71
+ if (this.flushTimer) clearInterval(this.flushTimer);
72
+ await this.flush();
73
+ }
74
+ enqueue(event) {
75
+ this.buffer.push(event);
76
+ this.counter.add(1, {
77
+ tenantId: this.context.tenantId,
78
+ type: event.type
79
+ });
80
+ this.tracer.startActiveSpan(`personalization.${event.type}`, (span) => {
81
+ span.setAttribute("tenant.id", this.context.tenantId);
82
+ if (this.context.userId) span.setAttribute("user.id", this.context.userId);
83
+ span.setAttribute("personalization.event_type", event.type);
84
+ span.end();
85
+ });
86
+ if (this.buffer.length >= this.bufferSize) this.flush();
87
+ }
88
+ };
89
+ const createBehaviorTracker = (options) => new BehaviorTracker(options);
90
+
91
+ //#endregion
92
+ export { createBehaviorTracker };
@@ -1 +1,28 @@
1
- import{t as e}from"./injector.js";var t=class{extensions=[];register(e){return this.extensions.push(e),this}registerMany(e){return e.forEach(e=>this.register(e)),this}compose(t){return this.extensions.filter(e=>n(t,e)).sort((e,t)=>(e.priority??0)-(t.priority??0)).reduce((t,n)=>e(t,n),t.base)}};function n(e,t){return!(t.workflow!==e.base.meta.name||t.baseVersion&&t.baseVersion!==e.base.meta.version||t.tenantId&&t.tenantId!==e.tenantId||t.role&&t.role!==e.role||t.device&&t.device!==e.device)}export{t};
1
+ import { applyWorkflowExtension } from "./injector.js";
2
+
3
+ //#region ../../libs/workflow-composer/dist/composer.js
4
+ var WorkflowComposer = class {
5
+ extensions = [];
6
+ register(extension) {
7
+ this.extensions.push(extension);
8
+ return this;
9
+ }
10
+ registerMany(extensions) {
11
+ extensions.forEach((extension) => this.register(extension));
12
+ return this;
13
+ }
14
+ compose(params) {
15
+ return this.extensions.filter((extension) => matches(params, extension)).sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0)).reduce((acc, extension) => applyWorkflowExtension(acc, extension), params.base);
16
+ }
17
+ };
18
+ function matches(params, extension) {
19
+ if (extension.workflow !== params.base.meta.name) return false;
20
+ if (extension.baseVersion && extension.baseVersion !== params.base.meta.version) return false;
21
+ if (extension.tenantId && extension.tenantId !== params.tenantId) return false;
22
+ if (extension.role && extension.role !== params.role) return false;
23
+ if (extension.device && extension.device !== params.device) return false;
24
+ return true;
25
+ }
26
+
27
+ //#endregion
28
+ export { WorkflowComposer };
@@ -1 +1,72 @@
1
- import{e}from"./validator.js";function t(t,r){e(r,t);let s=o(t),c=[...s.definition.steps],l=[...s.definition.transitions],u=new Set(r.hiddenSteps??[]);return u.forEach(e=>{let t=c.findIndex(t=>t.id===e);t!==-1&&c.splice(t,1)}),u.size&&(l=l.filter(e=>!u.has(e.from)&&!u.has(e.to))),r.customSteps?.forEach(e=>{n(c,e),i(l,e)}),s.definition.steps=c,s.definition.transitions=a(l),s.meta={...s.meta,version:s.meta.version},s}function n(e,t){let n=r(e,t);if(n===-1)throw Error(`Unable to place injected step "${t.inject.id}"`);e.splice(n,0,{...t.inject})}function r(e,t){if(t.after){let n=e.findIndex(e=>e.id===t.after);return n===-1?-1:n+1}if(t.before){let n=e.findIndex(e=>e.id===t.before);return n===-1?-1:n}return e.length}function i(e,t){t.inject.id&&(t.transitionFrom&&e.push({from:t.transitionFrom,to:t.inject.id,condition:t.when}),t.transitionTo&&e.push({from:t.inject.id,to:t.transitionTo,condition:t.when}))}function a(e){let t=new Set,n=[];return e.forEach(e=>{let r=`${e.from}->${e.to}:${e.condition??``}`;t.has(r)||(t.add(r),n.push(e))}),n}function o(e){return JSON.parse(JSON.stringify(e))}export{t};
1
+ import { validateExtension } from "./validator.js";
2
+
3
+ //#region ../../libs/workflow-composer/dist/injector.js
4
+ function applyWorkflowExtension(base, extension) {
5
+ validateExtension(extension, base);
6
+ const spec = cloneWorkflowSpec(base);
7
+ const steps = [...spec.definition.steps];
8
+ let transitions = [...spec.definition.transitions];
9
+ const hiddenSet = new Set(extension.hiddenSteps ?? []);
10
+ hiddenSet.forEach((stepId) => {
11
+ const idx = steps.findIndex((step) => step.id === stepId);
12
+ if (idx !== -1) steps.splice(idx, 1);
13
+ });
14
+ if (hiddenSet.size) transitions = transitions.filter((transition) => !hiddenSet.has(transition.from) && !hiddenSet.has(transition.to));
15
+ extension.customSteps?.forEach((injection) => {
16
+ insertStep(steps, injection);
17
+ wireTransitions(transitions, injection);
18
+ });
19
+ spec.definition.steps = steps;
20
+ spec.definition.transitions = dedupeTransitions(transitions);
21
+ spec.meta = {
22
+ ...spec.meta,
23
+ version: spec.meta.version
24
+ };
25
+ return spec;
26
+ }
27
+ function insertStep(steps, injection) {
28
+ const anchorIndex = resolveAnchorIndex(steps, injection);
29
+ if (anchorIndex === -1) throw new Error(`Unable to place injected step "${injection.inject.id}"`);
30
+ steps.splice(anchorIndex, 0, { ...injection.inject });
31
+ }
32
+ function resolveAnchorIndex(steps, injection) {
33
+ if (injection.after) {
34
+ const idx = steps.findIndex((step) => step.id === injection.after);
35
+ return idx === -1 ? -1 : idx + 1;
36
+ }
37
+ if (injection.before) {
38
+ const idx = steps.findIndex((step) => step.id === injection.before);
39
+ return idx === -1 ? -1 : idx;
40
+ }
41
+ return steps.length;
42
+ }
43
+ function wireTransitions(transitions, injection) {
44
+ if (!injection.inject.id) return;
45
+ if (injection.transitionFrom) transitions.push({
46
+ from: injection.transitionFrom,
47
+ to: injection.inject.id,
48
+ condition: injection.when
49
+ });
50
+ if (injection.transitionTo) transitions.push({
51
+ from: injection.inject.id,
52
+ to: injection.transitionTo,
53
+ condition: injection.when
54
+ });
55
+ }
56
+ function dedupeTransitions(transitions) {
57
+ const seen = /* @__PURE__ */ new Set();
58
+ const result = [];
59
+ transitions.forEach((transition) => {
60
+ const key = `${transition.from}->${transition.to}:${transition.condition ?? ""}`;
61
+ if (seen.has(key)) return;
62
+ seen.add(key);
63
+ result.push(transition);
64
+ });
65
+ return result;
66
+ }
67
+ function cloneWorkflowSpec(spec) {
68
+ return JSON.parse(JSON.stringify(spec));
69
+ }
70
+
71
+ //#endregion
72
+ export { applyWorkflowExtension };
@@ -1 +1,36 @@
1
- function e(e,t){let n=[],r=new Set(t.definition.steps.map(e=>e.id));if(e.customSteps?.forEach((e,t)=>{e.inject.id||n.push({code:`workflow.extension.step.id`,message:`customSteps[${t}] is missing an id`}),!e.after&&!e.before&&n.push({code:`workflow.extension.step.anchor`,message:`customSteps[${t}] must set after or before`}),e.after&&!r.has(e.after)&&n.push({code:`workflow.extension.step.after`,message:`customSteps[${t}] references unknown step "${e.after}"`}),e.before&&!r.has(e.before)&&n.push({code:`workflow.extension.step.before`,message:`customSteps[${t}] references unknown step "${e.before}"`})}),e.hiddenSteps?.forEach(e=>{r.has(e)||n.push({code:`workflow.extension.hidden-step`,message:`hidden step "${e}" does not exist`})}),n.length){let t=n.map(e=>`${e.code}: ${e.message}`).join(`; `);throw Error(`Invalid workflow extension for ${e.workflow}: ${t}`)}}export{e};
1
+ //#region ../../libs/workflow-composer/dist/validator.js
2
+ function validateExtension(extension, base) {
3
+ const issues = [];
4
+ const stepIds = new Set(base.definition.steps.map((step) => step.id));
5
+ extension.customSteps?.forEach((injection, idx) => {
6
+ if (!injection.inject.id) issues.push({
7
+ code: "workflow.extension.step.id",
8
+ message: `customSteps[${idx}] is missing an id`
9
+ });
10
+ if (!injection.after && !injection.before) issues.push({
11
+ code: "workflow.extension.step.anchor",
12
+ message: `customSteps[${idx}] must set after or before`
13
+ });
14
+ if (injection.after && !stepIds.has(injection.after)) issues.push({
15
+ code: "workflow.extension.step.after",
16
+ message: `customSteps[${idx}] references unknown step "${injection.after}"`
17
+ });
18
+ if (injection.before && !stepIds.has(injection.before)) issues.push({
19
+ code: "workflow.extension.step.before",
20
+ message: `customSteps[${idx}] references unknown step "${injection.before}"`
21
+ });
22
+ });
23
+ extension.hiddenSteps?.forEach((stepId) => {
24
+ if (!stepIds.has(stepId)) issues.push({
25
+ code: "workflow.extension.hidden-step",
26
+ message: `hidden step "${stepId}" does not exist`
27
+ });
28
+ });
29
+ if (issues.length) {
30
+ const reason = issues.map((issue) => `${issue.code}: ${issue.message}`).join("; ");
31
+ throw new Error(`Invalid workflow extension for ${extension.workflow}: ${reason}`);
32
+ }
33
+ }
34
+
35
+ //#endregion
36
+ export { validateExtension };
@@ -1 +1,53 @@
1
- import{e}from"./libs/logger/dist/types.js";import{o as t}from"./libs/logger/dist/logger.node.js";import"./libs/logger/dist/index.js";import{t as n}from"./libs/overlay-engine/dist/spec.js";import{o as r}from"./libs/overlay-engine/dist/signer.js";import{r as i}from"./libs/overlay-engine/dist/registry.js";import{t as a}from"./libs/overlay-engine/dist/runtime.js";import"./libs/overlay-engine/dist/index.js";const o=new t({level:process.env.NODE_ENV===`production`?e.INFO:e.DEBUG,environment:process.env.NODE_ENV||`development`,enableColors:process.env.NODE_ENV!==`production`});async function s(){let e=new i({allowUnsigned:!0}),t=new a({registry:e}),s=await r(n({overlayId:`demo-overlay`,version:`1.0.0`,appliesTo:{capability:`billing.createOrder`,tenantId:`demo`},modifications:[{type:`hideField`,field:`internalNotes`},{type:`renameLabel`,field:`customerReference`,newLabel:`PO Number`}]}),process.env.PRIVATE_KEY_PEM??``);e.register(s);let c=t.apply({target:{fields:[{key:`customerReference`,label:`Customer Reference`,visible:!0},{key:`internalNotes`,label:`Internal Notes`,visible:!0}]},capability:`billing.createOrder`,tenantId:`demo`});o.info(`Overlay applied`,{fields:c.target.fields})}export{s as runOverlayCustomizationExample};
1
+ import { LogLevel } from "./libs/logger/dist/types.js";
2
+ import { Logger } from "./libs/logger/dist/logger.node.js";
3
+ import "./libs/logger/dist/index.js";
4
+ import { defineOverlay } from "./libs/overlay-engine/dist/spec.js";
5
+ import { signOverlay } from "./libs/overlay-engine/dist/signer.js";
6
+ import { OverlayRegistry } from "./libs/overlay-engine/dist/registry.js";
7
+ import { OverlayEngine } from "./libs/overlay-engine/dist/runtime.js";
8
+ import "./libs/overlay-engine/dist/index.js";
9
+
10
+ //#region src/overlay-customization.ts
11
+ const logger = new Logger({
12
+ level: process.env.NODE_ENV === "production" ? LogLevel.INFO : LogLevel.DEBUG,
13
+ environment: process.env.NODE_ENV || "development",
14
+ enableColors: process.env.NODE_ENV !== "production"
15
+ });
16
+ async function runOverlayCustomizationExample() {
17
+ const registry = new OverlayRegistry({ allowUnsigned: true });
18
+ const engine = new OverlayEngine({ registry });
19
+ const signed = await signOverlay(defineOverlay({
20
+ overlayId: "demo-overlay",
21
+ version: "1.0.0",
22
+ appliesTo: {
23
+ capability: "billing.createOrder",
24
+ tenantId: "demo"
25
+ },
26
+ modifications: [{
27
+ type: "hideField",
28
+ field: "internalNotes"
29
+ }, {
30
+ type: "renameLabel",
31
+ field: "customerReference",
32
+ newLabel: "PO Number"
33
+ }]
34
+ }), process.env.PRIVATE_KEY_PEM ?? "");
35
+ registry.register(signed);
36
+ const result = engine.apply({
37
+ target: { fields: [{
38
+ key: "customerReference",
39
+ label: "Customer Reference",
40
+ visible: true
41
+ }, {
42
+ key: "internalNotes",
43
+ label: "Internal Notes",
44
+ visible: true
45
+ }] },
46
+ capability: "billing.createOrder",
47
+ tenantId: "demo"
48
+ });
49
+ logger.info("Overlay applied", { fields: result.target.fields });
50
+ }
51
+
52
+ //#endregion
53
+ export { runOverlayCustomizationExample };