@devcabs/folio-engine 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -118,15 +118,15 @@ export declare const NodeCanvasDocumentSchema: z.ZodObject<{
118
118
  sections: z.ZodArray<z.ZodAny, "many">;
119
119
  updatedAt: z.ZodString;
120
120
  }, "strip", z.ZodTypeAny, {
121
- updatedAt: string;
122
121
  nodeId: string;
123
122
  version: number;
124
123
  sections: any[];
125
- }, {
126
124
  updatedAt: string;
125
+ }, {
127
126
  nodeId: string;
128
127
  version: number;
129
128
  sections: any[];
129
+ updatedAt: string;
130
130
  }>;
131
131
  export declare const CachedIndicatorDatasetSchema: z.ZodObject<{
132
132
  chartId: z.ZodString;
@@ -186,42 +186,42 @@ export declare const PublicNodePayloadSchema: z.ZodObject<{
186
186
  sections: z.ZodArray<z.ZodAny, "many">;
187
187
  updatedAt: z.ZodString;
188
188
  }, "strip", z.ZodTypeAny, {
189
- updatedAt: string;
190
189
  nodeId: string;
191
190
  version: number;
192
191
  sections: any[];
193
- }, {
194
192
  updatedAt: string;
193
+ }, {
195
194
  nodeId: string;
196
195
  version: number;
197
196
  sections: any[];
197
+ updatedAt: string;
198
198
  }>;
199
199
  chartDatasets: z.ZodRecord<z.ZodString, z.ZodAny>;
200
200
  sourceMetadata: z.ZodRecord<z.ZodString, z.ZodAny>;
201
201
  }, "strip", z.ZodTypeAny, {
202
+ nodeId: string;
203
+ version: number;
204
+ updatedAt: string;
205
+ snapshotId: string;
202
206
  canvas: {
203
- updatedAt: string;
204
207
  nodeId: string;
205
208
  version: number;
206
209
  sections: any[];
210
+ updatedAt: string;
207
211
  };
208
- updatedAt: string;
209
- nodeId: string;
210
- version: number;
211
- snapshotId: string;
212
212
  chartDatasets: Record<string, any>;
213
213
  sourceMetadata: Record<string, any>;
214
214
  }, {
215
+ nodeId: string;
216
+ version: number;
217
+ updatedAt: string;
218
+ snapshotId: string;
215
219
  canvas: {
216
- updatedAt: string;
217
220
  nodeId: string;
218
221
  version: number;
219
222
  sections: any[];
223
+ updatedAt: string;
220
224
  };
221
- updatedAt: string;
222
- nodeId: string;
223
- version: number;
224
- snapshotId: string;
225
225
  chartDatasets: Record<string, any>;
226
226
  sourceMetadata: Record<string, any>;
227
227
  }>;
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ export interface AccentValidationResult {
3
+ valid: boolean;
4
+ warnings: string[];
5
+ }
6
+ /**
7
+ * Validates accent text syntax (e.g. *word* or **word**).
8
+ * Detects unclosed delimiters, empty tags, or malformed syntax.
9
+ */
10
+ export declare function validateAccentedText(text: string): AccentValidationResult;
11
+ export interface ParseAccentedTextOptions {
12
+ accentClassName?: string;
13
+ onWarn?: (warning: string) => void;
14
+ }
15
+ /**
16
+ * Parses a string containing *accent* or **accent** tags into React elements.
17
+ * Unaccented segments remain plain text.
18
+ * Accented segments are wrapped in a span with `accentClassName`.
19
+ *
20
+ * If delimiters are unclosed or malformed:
21
+ * - Emits a warning via `options.onWarn` or console.warn in dev mode
22
+ * - Gracefully falls back to rendering as plain text so the UI never crashes
23
+ */
24
+ export declare function parseAccentedText(input: string | React.ReactNode, options?: ParseAccentedTextOptions): React.ReactNode;
@@ -0,0 +1,172 @@
1
+ import { o as h, s as o, n as y, b as p, c as w, d as T, P as $ } from "./edge-DziUDALF.js";
2
+ import { jsx as E, Fragment as A } from "react/jsx-runtime";
3
+ const C = h({
4
+ appName: o().min(1, "appName is required"),
5
+ tagline: o().optional(),
6
+ logoText: o().optional(),
7
+ markSides: y().int().min(3).max(32).optional(),
8
+ markWaviness: y().min(0).max(1).optional(),
9
+ heroKicker: o().optional(),
10
+ heroTitle: o().optional(),
11
+ heroSubtitle: o().optional(),
12
+ orgName: o().optional()
13
+ }), N = h({
14
+ appId: o().min(1, "appId is required"),
15
+ appNamespace: o().min(1, "appNamespace is required"),
16
+ basePath: o().optional(),
17
+ nodes: w(T()).default([]),
18
+ branding: C,
19
+ securitySalt: o().optional(),
20
+ expectedPinHash: o().optional(),
21
+ features: h({
22
+ enableChartDrawer: p().optional(),
23
+ enableEditorMode: p().optional(),
24
+ enableHistoryLedger: p().optional()
25
+ }).optional()
26
+ });
27
+ function m(e) {
28
+ return {
29
+ appId: "default-app",
30
+ appNamespace: "folio",
31
+ branding: {
32
+ appName: "Folio Engine",
33
+ tagline: "Parametric Stepped Sequence & Document AST Platform",
34
+ logoText: "FOLIO",
35
+ markSides: 8,
36
+ markWaviness: 0.15
37
+ },
38
+ nodes: [],
39
+ securitySalt: void 0,
40
+ expectedPinHash: void 0,
41
+ features: {
42
+ enableChartDrawer: !0,
43
+ enableEditorMode: !0,
44
+ enableHistoryLedger: !0
45
+ },
46
+ ...e
47
+ };
48
+ }
49
+ let u = m();
50
+ function S() {
51
+ return u;
52
+ }
53
+ function I(e) {
54
+ return u = m({ ...u, ...e }), u;
55
+ }
56
+ function F() {
57
+ u = m();
58
+ }
59
+ function P() {
60
+ return u.appNamespace || "folio";
61
+ }
62
+ function W(e, t) {
63
+ return (t || P()) + "_" + e;
64
+ }
65
+ function b(e) {
66
+ const t = [];
67
+ return !e || typeof e != "string" ? { valid: !0, warnings: t } : ((e.match(/\*/g) || []).length % 2 !== 0 && t.push(
68
+ `Unclosed asterisk delimiter detected in "${e}". Expected matching opening and closing '*'.`
69
+ ), (/\*{4}/.test(e) || /\*{2}\s+\*{2}/.test(e) || /\*\s+\*/.test(e)) && t.push(
70
+ `Empty accent delimiter detected in "${e}". Accent delimiters must wrap non-empty text.`
71
+ ), {
72
+ valid: t.length === 0,
73
+ warnings: t
74
+ });
75
+ }
76
+ function j(e, t) {
77
+ if (typeof e != "string" || !e.includes("*"))
78
+ return e;
79
+ const { valid: a, warnings: r } = b(e);
80
+ !a && r.length > 0 && r.forEach((n) => {
81
+ var d;
82
+ t != null && t.onWarn ? t.onWarn(n) : typeof console < "u" && typeof console.warn == "function" && ((typeof import.meta < "u" && !1) ?? (typeof process < "u" && ((d = process.env) == null ? void 0 : d.NODE_ENV) !== "production")) && console.warn(`⚠️ [Folio Engine] ${n}`);
83
+ });
84
+ const l = /(\*{1,2})([^\s*](?:[^*]*?[^\s*])?)\1/g, s = [];
85
+ let i = 0, c;
86
+ for (; (c = l.exec(e)) !== null; ) {
87
+ const [n, , d] = c, f = c.index;
88
+ f > i && s.push(e.substring(i, f)), s.push(
89
+ /* @__PURE__ */ E(
90
+ "span",
91
+ {
92
+ className: t == null ? void 0 : t.accentClassName,
93
+ children: d
94
+ },
95
+ `accent-${f}`
96
+ )
97
+ ), i = f + n.length;
98
+ }
99
+ return i < e.length && s.push(e.substring(i)), s.length === 0 ? e : s.length === 1 ? s[0] : /* @__PURE__ */ E(A, { children: s });
100
+ }
101
+ function q(e) {
102
+ const t = [], a = [], r = $.safeParse(e);
103
+ if (!r.success)
104
+ return r.error.issues.forEach((n) => {
105
+ t.push(`[Schema] ${n.path.join(".")}: ${n.message}`);
106
+ }), { ok: !1, errors: t, warnings: a };
107
+ const l = r.data, s = l.chartDatasets || {}, i = /* @__PURE__ */ new Set();
108
+ function c(n, d) {
109
+ n.id ? i.has(n.id) ? t.push(`[AST] Duplicate element id detected: "${n.id}".`) : i.add(n.id) : t.push(`[AST] Element in "${d}" is missing an 'id'.`), n.type === "chart" && (n.chartId ? s[n.chartId] || a.push(
110
+ `[Chart] Chart "${n.chartId}" is referenced in canvas section "${d}" but not found in chartDatasets.`
111
+ ) : t.push(`[Chart] Chart element "${n.id}" is missing 'chartId'.`));
112
+ }
113
+ return l.canvas && Array.isArray(l.canvas.sections) && l.canvas.sections.forEach((n, d) => {
114
+ n.id ? i.has(n.id) ? t.push(`[AST] Duplicate section id detected: "${n.id}".`) : i.add(n.id) : t.push(`[AST] Section at index ${d} is missing an 'id'.`), (!n.title || n.title.trim().length === 0) && a.push(`[AST] Section "${n.id || d}" has an empty title.`), Array.isArray(n.elements) && n.elements.forEach((f) => {
115
+ if (f.type === "subsection") {
116
+ const g = f;
117
+ g.id ? i.has(g.id) ? t.push(`[AST] Duplicate subsection id detected: "${g.id}".`) : i.add(g.id) : t.push(`[AST] Subsection in "${n.title || n.id}" is missing an 'id'.`), Array.isArray(g.elements) && g.elements.forEach((v) => c(v, `${n.title} > ${g.title}`));
118
+ } else
119
+ c(f, n.title);
120
+ });
121
+ }), {
122
+ ok: t.length === 0,
123
+ errors: t,
124
+ warnings: a
125
+ };
126
+ }
127
+ function k(e) {
128
+ var s;
129
+ const t = [], a = [], r = e ? { ...S(), ...e } : S(), l = N.safeParse(r);
130
+ if (l.success || l.error.issues.forEach((i) => {
131
+ t.push(`[Config] ${i.path.join(".")}: ${i.message}`);
132
+ }), (s = r.branding) != null && s.heroTitle) {
133
+ const i = b(r.branding.heroTitle);
134
+ !i.valid && i.warnings.length > 0 && i.warnings.forEach((c) => {
135
+ a.push(`[Branding] heroTitle accent syntax warning: ${c}`);
136
+ });
137
+ }
138
+ if (typeof window < "u" && typeof document < "u") {
139
+ const i = window.getComputedStyle(document.documentElement), c = i.getPropertyValue("--canvas-bg").trim(), n = i.getPropertyValue("--font-mono").trim();
140
+ !c && !n && a.push(
141
+ "[Styles] Folio Engine stylesheet not detected! Ensure you import '@devcabs/folio-engine/style.css' in your main entry point."
142
+ );
143
+ }
144
+ return {
145
+ ok: t.length === 0,
146
+ errors: t,
147
+ warnings: a
148
+ };
149
+ }
150
+ function H() {
151
+ const e = k();
152
+ return typeof console < "u" && (e.ok || console.error(`❌ [Folio Engine] Wiring verification failed:
153
+ ` + e.errors.join(`
154
+ `)), e.warnings.length > 0 && console.warn(`⚠️ [Folio Engine] Wiring warnings:
155
+ ` + e.warnings.join(`
156
+ `)), e.ok && e.warnings.length === 0 && console.log("✅ [Folio Engine] Configuration and stylesheet wiring verified successfully.")), e.ok;
157
+ }
158
+ export {
159
+ C as E,
160
+ N as a,
161
+ k as b,
162
+ S as c,
163
+ W as d,
164
+ m as e,
165
+ F as f,
166
+ P as g,
167
+ b as h,
168
+ j as p,
169
+ H as r,
170
+ I as s,
171
+ q as v
172
+ };
@@ -0,0 +1,5 @@
1
+ "use strict";const i=require("./edge-1WCVZ0J7.cjs"),h=require("react/jsx-runtime");var m=typeof document<"u"?document.currentScript:null;const E=i.objectType({appName:i.stringType().min(1,"appName is required"),tagline:i.stringType().optional(),logoText:i.stringType().optional(),markSides:i.numberType().int().min(3).max(32).optional(),markWaviness:i.numberType().min(0).max(1).optional(),heroKicker:i.stringType().optional(),heroTitle:i.stringType().optional(),heroSubtitle:i.stringType().optional(),orgName:i.stringType().optional()}),S=i.objectType({appId:i.stringType().min(1,"appId is required"),appNamespace:i.stringType().min(1,"appNamespace is required"),basePath:i.stringType().optional(),nodes:i.arrayType(i.anyType()).default([]),branding:E,securitySalt:i.stringType().optional(),expectedPinHash:i.stringType().optional(),features:i.objectType({enableChartDrawer:i.booleanType().optional(),enableEditorMode:i.booleanType().optional(),enableHistoryLedger:i.booleanType().optional()}).optional()});function p(e){return{appId:"default-app",appNamespace:"folio",branding:{appName:"Folio Engine",tagline:"Parametric Stepped Sequence & Document AST Platform",logoText:"FOLIO",markSides:8,markWaviness:.15},nodes:[],securitySalt:void 0,expectedPinHash:void 0,features:{enableChartDrawer:!0,enableEditorMode:!0,enableHistoryLedger:!0},...e}}let u=p();function y(){return u}function w(e){return u=p({...u,...e}),u}function A(){u=p()}function b(){return u.appNamespace||"folio"}function $(e,t){return(t||b())+"_"+e}function T(e){const t=[];return!e||typeof e!="string"?{valid:!0,warnings:t}:((e.match(/\*/g)||[]).length%2!==0&&t.push(`Unclosed asterisk delimiter detected in "${e}". Expected matching opening and closing '*'.`),(/\*{4}/.test(e)||/\*{2}\s+\*{2}/.test(e)||/\*\s+\*/.test(e))&&t.push(`Empty accent delimiter detected in "${e}". Accent delimiters must wrap non-empty text.`),{valid:t.length===0,warnings:t})}function N(e,t){if(typeof e!="string"||!e.includes("*"))return e;const{valid:r,warnings:s}=T(e);!r&&s.length>0&&s.forEach(n=>{var d;t!=null&&t.onWarn?t.onWarn(n):typeof console<"u"&&typeof console.warn=="function"&&((typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:m&&m.tagName.toUpperCase()==="SCRIPT"&&m.src||new URL("verifyEngineSetup-DeUzt_yx.cjs",document.baseURI).href}<"u"&&!1)??(typeof process<"u"&&((d=process.env)==null?void 0:d.NODE_ENV)!=="production"))&&console.warn(`⚠️ [Folio Engine] ${n}`)});const l=/(\*{1,2})([^\s*](?:[^*]*?[^\s*])?)\1/g,o=[];let a=0,c;for(;(c=l.exec(e))!==null;){const[n,,d]=c,g=c.index;g>a&&o.push(e.substring(a,g)),o.push(h.jsx("span",{className:t==null?void 0:t.accentClassName,children:d},`accent-${g}`)),a=g+n.length}return a<e.length&&o.push(e.substring(a)),o.length===0?e:o.length===1?o[0]:h.jsx(h.Fragment,{children:o})}function P(e){const t=[],r=[],s=i.PublicNodePayloadSchema.safeParse(e);if(!s.success)return s.error.issues.forEach(n=>{t.push(`[Schema] ${n.path.join(".")}: ${n.message}`)}),{ok:!1,errors:t,warnings:r};const l=s.data,o=l.chartDatasets||{},a=new Set;function c(n,d){n.id?a.has(n.id)?t.push(`[AST] Duplicate element id detected: "${n.id}".`):a.add(n.id):t.push(`[AST] Element in "${d}" is missing an 'id'.`),n.type==="chart"&&(n.chartId?o[n.chartId]||r.push(`[Chart] Chart "${n.chartId}" is referenced in canvas section "${d}" but not found in chartDatasets.`):t.push(`[Chart] Chart element "${n.id}" is missing 'chartId'.`))}return l.canvas&&Array.isArray(l.canvas.sections)&&l.canvas.sections.forEach((n,d)=>{n.id?a.has(n.id)?t.push(`[AST] Duplicate section id detected: "${n.id}".`):a.add(n.id):t.push(`[AST] Section at index ${d} is missing an 'id'.`),(!n.title||n.title.trim().length===0)&&r.push(`[AST] Section "${n.id||d}" has an empty title.`),Array.isArray(n.elements)&&n.elements.forEach(g=>{if(g.type==="subsection"){const f=g;f.id?a.has(f.id)?t.push(`[AST] Duplicate subsection id detected: "${f.id}".`):a.add(f.id):t.push(`[AST] Subsection in "${n.title||n.id}" is missing an 'id'.`),Array.isArray(f.elements)&&f.elements.forEach(C=>c(C,`${n.title} > ${f.title}`))}else c(g,n.title)})}),{ok:t.length===0,errors:t,warnings:r}}function v(e){var o;const t=[],r=[],s=e?{...y(),...e}:y(),l=S.safeParse(s);if(l.success||l.error.issues.forEach(a=>{t.push(`[Config] ${a.path.join(".")}: ${a.message}`)}),(o=s.branding)!=null&&o.heroTitle){const a=T(s.branding.heroTitle);!a.valid&&a.warnings.length>0&&a.warnings.forEach(c=>{r.push(`[Branding] heroTitle accent syntax warning: ${c}`)})}if(typeof window<"u"&&typeof document<"u"){const a=window.getComputedStyle(document.documentElement),c=a.getPropertyValue("--canvas-bg").trim(),n=a.getPropertyValue("--font-mono").trim();!c&&!n&&r.push("[Styles] Folio Engine stylesheet not detected! Ensure you import '@devcabs/folio-engine/style.css' in your main entry point.")}return{ok:t.length===0,errors:t,warnings:r}}function k(){const e=v();return typeof console<"u"&&(e.ok||console.error(`❌ [Folio Engine] Wiring verification failed:
2
+ `+e.errors.join(`
3
+ `)),e.warnings.length>0&&console.warn(`⚠️ [Folio Engine] Wiring warnings:
4
+ `+e.warnings.join(`
5
+ `)),e.ok&&e.warnings.length===0&&console.log("✅ [Folio Engine] Configuration and stylesheet wiring verified successfully.")),e.ok}exports.EngineBrandingConfigSchema=E;exports.EngineConfigSchema=S;exports.createDefaultEngineConfig=p;exports.getEngineConfig=y;exports.getStorageKey=$;exports.getStorageNamespace=b;exports.parseAccentedText=N;exports.resetEngineConfig=A;exports.runEngineSelfAudit=k;exports.setEngineConfig=w;exports.validateAccentedText=T;exports.validateNodePayload=P;exports.verifyEngineWiring=v;
package/package.json CHANGED
@@ -1,15 +1,25 @@
1
1
  {
2
2
  "name": "@devcabs/folio-engine",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
- "main": "./dist/folio.umd.cjs",
5
+ "main": "./dist/folio.cjs",
6
6
  "module": "./dist/folio.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/folio.js",
12
- "require": "./dist/folio.umd.cjs"
12
+ "require": "./dist/folio.cjs"
13
+ },
14
+ "./edge": {
15
+ "types": "./dist/edge.d.ts",
16
+ "import": "./dist/edge.js",
17
+ "require": "./dist/edge.cjs"
18
+ },
19
+ "./diagnostics": {
20
+ "types": "./dist/diagnostics.d.ts",
21
+ "import": "./dist/diagnostics.js",
22
+ "require": "./dist/diagnostics.cjs"
13
23
  },
14
24
  "./style.css": "./dist/style.css"
15
25
  },
@@ -47,10 +57,12 @@
47
57
  "build": "npm run test:tokens && tsc --noEmit && vite build",
48
58
  "build:lib": "npm run test:tokens && vite build -c vite.config.lib.ts && tsc -p tsconfig.lib.json",
49
59
  "preview": "vite preview --port 5174",
60
+ "test": "vitest run",
50
61
  "test:purity": "vitest run tests/purity",
51
62
  "test:tokens": "tsx scripts/verify-token-aliases.ts",
52
63
  "lint": "eslint .",
53
- "prepack": "npm run build:lib"
64
+ "prepack": "npm run build:lib",
65
+ "deploy": "tsx scripts/deploy.ts"
54
66
  },
55
67
  "files": [
56
68
  "dist"