your-ai-workflow-firebase-os 1.2.39 → 1.2.41
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/ContactPopup-D7dmsL5K.cjs +9 -0
- package/dist/{ContactPopup-Bm3DZkEB.js → ContactPopup-kZk-JP-d.js} +10296 -10296
- package/dist/{PhoneInputField-ChHip6t8.js → PhoneInputField-CaSYHqEc.js} +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/renderer.cjs.js +1 -1
- package/dist/renderer.es.js +1 -1
- package/dist/vite/index.d.ts +2 -2
- package/dist/vite.cjs.js +26 -10
- package/dist/vite.es.js +127 -79
- package/dist/your-ai-workflow-firebase-os.cjs.js +13 -12
- package/dist/your-ai-workflow-firebase-os.css +1 -1
- package/dist/your-ai-workflow-firebase-os.es.js +3406 -3333
- package/package.json +1 -1
- package/scripts/postinstall.js +104 -65
- package/src/configs/theme.config.ts +4 -2
- package/src/index.css +22 -12
- package/dist/ContactPopup-DY0VLjCP.cjs +0 -9
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Bt as e } from "./ContactPopup-kZk-JP-d.js";
|
|
2
2
|
import t, { forwardRef as n, useCallback as r, useEffect as i, useImperativeHandle as a, useMemo as o, useRef as s, useState as c } from "react";
|
|
3
3
|
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
4
4
|
//#region node_modules/react-international-phone/dist/index.mjs
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { useConfig } from './lib/ConfigContext';
|
|
|
6
6
|
export type { FirebaseOSConfig } from './lib/ConfigContext';
|
|
7
7
|
export { db, auth, storage } from './lib/firebase';
|
|
8
8
|
export { ContactPopup } from './components/ContactPopup';
|
|
9
|
+
export { registerMicrocomponent } from './microcomponents/registry';
|
|
9
10
|
export { Button } from './components/Button';
|
|
10
11
|
export { Input } from './components/Input';
|
|
11
12
|
export { CustomSelect } from './components/CustomSelect';
|
package/dist/renderer.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./chunk-DYteiM-1.cjs`);const e=require(`./ContactPopup-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require(`./chunk-DYteiM-1.cjs`);const e=require(`./ContactPopup-D7dmsL5K.cjs`);exports.ContactPopup=e.t;
|
package/dist/renderer.es.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as e } from "./ContactPopup-
|
|
1
|
+
import { t as e } from "./ContactPopup-kZk-JP-d.js";
|
|
2
2
|
export { e as ContactPopup };
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* your-ai-workflow-firebase-os/vite — the plugin a consumer's vite.config.ts loads.
|
|
3
3
|
*/
|
|
4
|
-
export { yourAiFirebase, restoreOwnedFiles, ownedMessage, VIRTUAL_ID, RESOLVED_VIRTUAL_ID } from './plugin';
|
|
5
|
-
export { CANONICAL_APP_TSX, CANONICAL_MAIN_TSX, OWNED_BANNER, VIRTUAL_REGISTRIES_ID } from './canonical';
|
|
4
|
+
export { yourAiFirebase, restoreOwnedFiles, ensureConsumerRegistry, ownedMessage, VIRTUAL_ID, RESOLVED_VIRTUAL_ID } from './plugin';
|
|
5
|
+
export { CANONICAL_APP_TSX, CANONICAL_MAIN_TSX, CONSUMER_REGISTRY_TS, OWNED_BANNER, VIRTUAL_REGISTRIES_ID } from './canonical';
|
|
6
6
|
export { discover, registrable, virtualModuleSource, virtualModuleSourceFor, classifyConfigFile, tabIdFromFile, pageIdFromFile, formIdFromFile, fileIdFromConfigFile, microcomponentKeysFromFile, isConsumerRoot, isDiscoveredPath, CONSUMER_DIR, CONFIGS_DIR, MICROCOMPONENTS_DIR, SHIPPED_CONFIG_FILES, } from './discover';
|
|
7
7
|
export type { DiscoveredFile, DiscoveredKind, ConfigKind } from './discover';
|
|
8
8
|
export { validate, validateDiscovered, stripComments } from './validate';
|
package/dist/vite.cjs.js
CHANGED
|
@@ -6,6 +6,11 @@ import { FirebaseOS } from 'your-ai-workflow-firebase-os';
|
|
|
6
6
|
import { Home } from './your-ai-workflow-firebase-os/Home';
|
|
7
7
|
import { themeConfig } from './your-ai-workflow-firebase-os/configs/theme.config';
|
|
8
8
|
|
|
9
|
+
// The page-content list. In a build with the Your AI Firebase plugin this is
|
|
10
|
+
// a safety net (content files are found automatically); in a runtime without
|
|
11
|
+
// the plugin (Google AI Studio) its registrations are what loads them.
|
|
12
|
+
import './your-ai-workflow-firebase-os/microcomponents/registry';
|
|
13
|
+
|
|
9
14
|
// Local Configuration Defaults (The Final Boss)
|
|
10
15
|
import { contactFormConfig } from './your-ai-workflow-firebase-os/configs/contactForm.config';
|
|
11
16
|
import { supportFormConfig } from './your-ai-workflow-firebase-os/configs/supportForm.config';
|
|
@@ -41,7 +46,18 @@ export default function App() {
|
|
|
41
46
|
/>
|
|
42
47
|
);
|
|
43
48
|
}
|
|
44
|
-
`,o
|
|
49
|
+
`,o=`// Your AI Firebase — the page-content list.
|
|
50
|
+
// The build finds content files automatically where the Your AI Firebase
|
|
51
|
+
// Vite plugin runs; in a runtime without it (Google AI Studio) the two lines
|
|
52
|
+
// per page below are the ONLY thing that loads a page's content file.
|
|
53
|
+
// Add two lines for every page. Never remove another page's lines.
|
|
54
|
+
//
|
|
55
|
+
// Example, for the page at /pricing filled by PricingContent.tsx:
|
|
56
|
+
// import PricingContent from './PricingContent';
|
|
57
|
+
// registerMicrocomponent('pricing', PricingContent);
|
|
58
|
+
import { registerMicrocomponent } from 'your-ai-workflow-firebase-os';
|
|
59
|
+
export { registerMicrocomponent };
|
|
60
|
+
`,s=`${r}
|
|
45
61
|
import { StrictMode } from 'react'
|
|
46
62
|
import { createRoot } from 'react-dom/client'
|
|
47
63
|
|
|
@@ -65,10 +81,10 @@ createRoot(document.getElementById('root')!).render(
|
|
|
65
81
|
<App />
|
|
66
82
|
</StrictMode>,
|
|
67
83
|
)
|
|
68
|
-
`,
|
|
84
|
+
`,c=`src/your-ai-workflow-firebase-os`,l=`${c}/configs`,u=`${c}/microcomponents`,d=[`theme.config.ts`,`contactForm.config.ts`,`supportForm.config.ts`,`registry.ts`,`pagesRegistry.ts`],f=e=>e.split(n.sep).join(`/`),p=e=>n.basename(e).replace(`.config.ts`,``).replace(/Tab$/,``).toLowerCase(),m=e=>n.basename(e).replace(`.config.ts`,``).replace(/Page$/,``).toLowerCase(),h=e=>n.basename(e).replace(`.config.ts`,``).replace(/Form$/,``).toLowerCase(),g=e=>{let t=n.basename(e).replace(/\.tsx$/,``).replace(/Content$/,``).replace(/([a-z0-9])([A-Z])/g,`$1_$2`).toLowerCase();return[t,t.replace(/_/g,``)]},_=e=>n.basename(e).replace(/\.config\.ts$/,``);function v(e){let t=n.basename(e);return d.includes(t)?`shipped`:/Tab\.config\.ts$/.test(t)?`tab`:/Page\.config\.ts$/.test(t)?`page`:/Form\.config\.ts$/.test(t)?`form`:`other`}var y=e=>t.existsSync(e)?t.readdirSync(e,{withFileTypes:!0}).filter(e=>e.isFile()).map(e=>e.name).sort():[],b=e=>t.existsSync(n.join(e,c));function x(e,t){let r=f(n.relative(e,t));return r.startsWith(l+`/`)||r.startsWith(u+`/`)}function S(e){let t=[],r=n.join(e,l);for(let e of y(r)){if(!/\.tsx?$/.test(e))continue;let i=n.join(r,e),a=`${l}/${e}`,o=v(e);o===`tab`?t.push({kind:o,file:a,abs:i,name:e,id:p(e)}):o===`page`?t.push({kind:o,file:a,abs:i,name:e,id:m(e)}):o===`form`||/Form\.config\.ts$/.test(e)?t.push({kind:`form`,file:a,abs:i,name:e,id:h(e)}):t.push({kind:`other`,file:a,abs:i,name:e,id:``})}let i=n.join(e,u);for(let e of y(i))e.endsWith(`.tsx`)&&e.replace(/\.tsx$/,``)!==`registry`&&t.push({kind:`microcomponent`,file:`${u}/${e}`,abs:n.join(i,e),name:e,id:g(e)[0]});return t}var C=e=>e.filter(e=>e.kind!==`other`),w=[{test:e=>/Content\.tsx$/.test(e),home:u},{test:e=>/(Tab|Page|Form)\.config\.tsx?$/.test(e),home:l}],T=new Set([`node_modules`,`.git`,`dist`,`build`]);function E(e){let r=[],i=n.join(e,`src`),a=(i,o)=>{if(!(o>6||!t.existsSync(i)))for(let s of t.readdirSync(i,{withFileTypes:!0})){let t=n.join(i,s.name),c=f(n.relative(e,t));if(s.isDirectory()){T.has(s.name)||a(t,o+1);continue}if(!(c===`${l}/${s.name}`||c===`${u}/${s.name}`)){for(let{test:e,home:t}of w)if(e(s.name)){r.push(`${c}: files like this are only found directly in ${t}/ — move it to ${t}/${s.name}.`);break}}}};return a(i,0),r.sort()}var D=e=>{let t=n.basename(e);return w.some(e=>e.test(t))},O=e=>JSON.stringify(e);function k(e){let t=[],n=[],r=[],i=[];return C(e).forEach((e,a)=>{let o=`m${a}`;if(t.push(`import * as ${o} from ${O(f(e.abs))};`),e.kind===`tab`)n.push(`{
|
|
69
85
|
const configVal = pickConfig(${o});
|
|
70
86
|
if (configVal) {
|
|
71
|
-
const tabId = ${
|
|
87
|
+
const tabId = ${O(e.id)};
|
|
72
88
|
const finalTab = {
|
|
73
89
|
config: {
|
|
74
90
|
...configVal,
|
|
@@ -86,7 +102,7 @@ createRoot(document.getElementById('root')!).render(
|
|
|
86
102
|
}`);else if(e.kind===`page`)n.push(`{
|
|
87
103
|
const configVal = pickConfig(${o});
|
|
88
104
|
if (configVal) {
|
|
89
|
-
const pageId = ${
|
|
105
|
+
const pageId = ${O(e.id)};
|
|
90
106
|
const finalPage = {
|
|
91
107
|
config: {
|
|
92
108
|
...configVal,
|
|
@@ -104,20 +120,20 @@ createRoot(document.getElementById('root')!).render(
|
|
|
104
120
|
}`);else if(e.kind===`form`)r.push(`{
|
|
105
121
|
const configVal = pickConfig(${o});
|
|
106
122
|
if (configVal) {
|
|
107
|
-
const formId = ${
|
|
123
|
+
const formId = ${O(e.id)};
|
|
108
124
|
// The form's id is its file name; systemName always follows the file.
|
|
109
125
|
const finalConfig = { ...configVal, systemName: formId };
|
|
110
126
|
forms[formId] = finalConfig;
|
|
111
127
|
forms[finalConfig.systemName] = finalConfig;
|
|
112
128
|
forms[finalConfig.systemName.toLowerCase()] = finalConfig;
|
|
113
129
|
}
|
|
114
|
-
}`);else if(e.kind===`microcomponent`){let[t,n]=
|
|
115
|
-
microcomponents[${
|
|
130
|
+
}`);else if(e.kind===`microcomponent`){let[t,n]=g(e.name);i.push(`if (${o} && ${o}.default) {
|
|
131
|
+
microcomponents[${O(t)}] = ${o}.default;
|
|
116
132
|
// Also answer to the squashed form ("mobile_apps" -> "mobileapps"): a page id
|
|
117
133
|
// derived from a file name (mobileAppsPage.config.ts -> "mobileapps") has no
|
|
118
134
|
// underscores, and the page must still find MobileAppsContent.tsx.
|
|
119
|
-
microcomponents[${
|
|
120
|
-
}`)}}),`// Generated by Your AI Firebase from the files in ${
|
|
135
|
+
microcomponents[${O(n)}] = ${o}.default;
|
|
136
|
+
}`)}}),`// Generated by Your AI Firebase from the files in ${c}/.
|
|
121
137
|
// Never written to disk; never edit. Add or remove a file and it updates itself.
|
|
122
138
|
${t.join(`
|
|
123
139
|
`)}
|
|
@@ -157,4 +173,4 @@ if (typeof window !== 'undefined') {
|
|
|
157
173
|
export const pagesRegistry = pages;
|
|
158
174
|
export const formsRegistry = forms;
|
|
159
175
|
export const microcomponentRegistry = microcomponents;
|
|
160
|
-
`}var
|
|
176
|
+
`}var A=e=>k(S(e)),j=e=>e.split(`/`).pop()||e,M=e=>/\/configs\/[^/]+$/.test(e),N=e=>/\/microcomponents\/[^/]+\.tsx$/.test(e),P=e=>e.replace(/\/\*[\s\S]*?\*\//g,``).replace(/(^|[^:\\'"`])\/\/.*$/gm,`$1`),F=(e,t)=>{let n=RegExp(`(?:^|[\\s,{])${t}\\s*:\\s*([^,\\n}]+)`,`g`),r=[],i;for(;i=n.exec(e);)r.push(i[1].trim());return r},I=e=>{let t=e.match(/^(['"`])([^'"`]*)\1$/);return t?t[2]:null},L=e=>/export\s+(?:const|let|var|function|class)\s+\w*Config\b/.test(e)||/export\s*\{[^}]*\b\w*Config\b[^}]*\}/.test(e),R=e=>/export\s+default\b/.test(e),z=e=>{let t=F(e,`route`);return{first:t[0],count:t.length}};function B(e){let t=[],n=[],r=new Map,i=new Set;for(let{file:t}of e)if(N(t))for(let e of g(j(t)))i.add(e);for(let{file:a,source:o}of e){let e=j(a),s=P(o);if(M(a)){let n=v(e);if(n===`shipped`)continue;if(n===`other`){t.push(`${a}: rename it to somethingTab.config.ts (a dashboard page), somethingPage.config.ts (a page for anyone) or somethingForm.config.ts (a form).`);continue}if(!L(s)&&!R(s)&&t.push(`${a}: export one const named ${_(e)}Config.`),n===`tab`||n===`page`){let{first:o,count:c}=z(s),l=o===void 0?null:I(o);if(c===0||l===null||!l.startsWith(`/`))t.push(`${a}: route must be one string starting with /, e.g. route: '/onboarding'. A page has exactly one web address.`);else{let e=r.get(l);e?t.push(`${a}: route '${l}' is already used by ${e}. One page, one file, one address.`):r.set(l,a)}let u=F(s,`template`)[0],d=u===void 0?null:I(u);if(!d||![`board`,`table`,`calendar`,`drive`,`inline_form`,`popup_form`].includes(d)){let r=n===`tab`?p(e):m(e),o=F(s,n===`tab`?`tabName`:`pageName`)[0],c=o===void 0?null:I(o),l=e=>e.toLowerCase().replace(/[^a-z0-9]+/g,`_`).replace(/^_|_$/g,``);if(![r,...c?[l(c),l(c).replace(/_/g,``)]:[]].some(e=>i.has(e))){let n=_(e).replace(/(Tab|Page)$/,``),r=(c||n).split(/[^a-zA-Z0-9]+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(``);t.push(`${a}: no content file matches this page, so it renders empty — create src/your-ai-workflow-firebase-os/microcomponents/${r}Content.tsx with export default.`)}}}if(n===`tab`){let e=F(s,`pageType`)[0],n=e===void 0?null:I(e);n!==`user`&&n!==`internal`&&n!==`admin`&&t.push(`${a}: pageType must be 'user', 'internal' or 'admin'. A dashboard page is never public.`)}if(n===`form`){let n=h(e),r=F(s,`systemName`)[0];r!==void 0&&I(r)!==n&&t.push(`${a}: systemName must be '${n}'.`)}continue}if(N(a)){R(s)||t.push(`${a}: add export default.`),(/<form\b/.test(s)||/\bonSubmit\b/.test(s))&&!/ContactPopup/.test(s)&&n.push(`${a}: forms are *Form.config.ts files shown with <ContactPopup formId="…" />; a hand-written form never reaches the Inbox.`),/<style[\s>]/.test(s)&&t.push(`${a}: a <style> tag is global CSS and restyles every page of the app — delete it and style with theme classes (bg-background, text-foreground, glass-panel, btn-primary).`);let e=s.match(/\b(?:bg-(?:white|black)|(?:bg|text|border)-(?:gray|slate|zinc|neutral|stone)-\d+)\b/);e&&n.push(`${a}: ${e[0]} is a hard-coded colour that ignores the owner's theme and stays wrong in light or dark mode — use bg-background, text-foreground, border-[var(--panel-border)], glass-panel or btn-primary.`)}}return{errors:t,warnings:n}}function V(e,t){return B(e.map(e=>({file:e.file,source:t(e.abs)})))}var H=i,U=`\0`+H,W=[{rel:`src/App.tsx`,source:a},{rel:`src/main.tsx`,source:s}],G=e=>`${e} is owned by Your AI Firebase; your edit was discarded.`,K=e=>e.replace(/[?#].*$/,``),q=e=>n.normalize(e).split(n.sep).join(`/`),J={info:e=>console.log(e),warn:e=>console.warn(e),error:e=>console.error(e)};function Y(e,r=J){let i=[];for(let{rel:a,source:o}of W){let s=n.join(e,a),c=null;try{c=t.readFileSync(s,`utf8`)}catch{c=null}c!==o&&(t.mkdirSync(n.dirname(s),{recursive:!0}),t.writeFileSync(s,o),i.push(a),c!==null&&r.warn(G(a)))}return i}function X(e){let r=n.join(e,u,`registry.ts`);return t.existsSync(r)?!1:(t.mkdirSync(n.dirname(r),{recursive:!0}),t.writeFileSync(r,o),!0)}var Z=(e,t)=>{let r=q(K(t));for(let{rel:t,source:i}of W)if(r===q(n.join(e,t)))return i;return null};function Q(){let e=process.cwd(),n=!1,r=`build`,i=J,a=()=>{let n=V(S(e),e=>t.readFileSync(e,`utf8`));return{...n,errors:[...n.errors,...E(e)]}};return{name:`your-ai-firebase`,enforce:`pre`,configResolved(t){e=t.root,r=t.command,i=t.logger,n=b(e),n&&(Y(e,i),X(e))},resolveId(e){return e===H?U:null},buildStart(){if(!n)return;let{errors:e,warnings:t}=a();for(let e of t)this.warn(e);if(e.length!==0)if(r===`build`)this.error(e[0]);else for(let t of e)i.error(t)},load(t){if(!n)return null;if(t===U){let t=S(e),{errors:n}=a();return n.length&&this.error(n[0]),k(t)}return Z(e,t)},configureServer(t){if(!n)return;let r=()=>{let e=t.moduleGraph.getModuleById(U);e&&t.moduleGraph.invalidateModule(e),t.ws.send({type:`full-reload`,path:`*`})},i=n=>{let i=q(n);if(Z(e,i)!==null){Y(e,t.config.logger);return}if(!x(e,i)&&!D(i))return;r();let{errors:o,warnings:s}=a();for(let e of s)t.config.logger.warn(e);for(let e of o)t.config.logger.error(e)};t.watcher.on(`add`,i),t.watcher.on(`unlink`,i),t.watcher.on(`change`,i)}}}exports.CANONICAL_APP_TSX=a,exports.CANONICAL_MAIN_TSX=s,exports.CONFIGS_DIR=l,exports.CONSUMER_DIR=c,exports.CONSUMER_REGISTRY_TS=o,exports.MICROCOMPONENTS_DIR=u,exports.OWNED_BANNER=r,exports.RESOLVED_VIRTUAL_ID=U,exports.SHIPPED_CONFIG_FILES=d,exports.VIRTUAL_ID=H,exports.VIRTUAL_REGISTRIES_ID=i,exports.classifyConfigFile=v,exports.discover=S,exports.ensureConsumerRegistry=X,exports.fileIdFromConfigFile=_,exports.formIdFromFile=h,exports.isConsumerRoot=b,exports.isDiscoveredPath=x,exports.microcomponentKeysFromFile=g,exports.ownedMessage=G,exports.pageIdFromFile=m,exports.registrable=C,exports.restoreOwnedFiles=Y,exports.stripComments=P,exports.tabIdFromFile=p,exports.validate=B,exports.validateDiscovered=V,exports.virtualModuleSource=A,exports.virtualModuleSourceFor=k,exports.yourAiFirebase=Q;
|
package/dist/vite.es.js
CHANGED
|
@@ -9,6 +9,11 @@ import { FirebaseOS } from 'your-ai-workflow-firebase-os';
|
|
|
9
9
|
import { Home } from './your-ai-workflow-firebase-os/Home';
|
|
10
10
|
import { themeConfig } from './your-ai-workflow-firebase-os/configs/theme.config';
|
|
11
11
|
|
|
12
|
+
// The page-content list. In a build with the Your AI Firebase plugin this is
|
|
13
|
+
// a safety net (content files are found automatically); in a runtime without
|
|
14
|
+
// the plugin (Google AI Studio) its registrations are what loads them.
|
|
15
|
+
import './your-ai-workflow-firebase-os/microcomponents/registry';
|
|
16
|
+
|
|
12
17
|
// Local Configuration Defaults (The Final Boss)
|
|
13
18
|
import { contactFormConfig } from './your-ai-workflow-firebase-os/configs/contactForm.config';
|
|
14
19
|
import { supportFormConfig } from './your-ai-workflow-firebase-os/configs/supportForm.config';
|
|
@@ -44,7 +49,7 @@ export default function App() {
|
|
|
44
49
|
/>
|
|
45
50
|
);
|
|
46
51
|
}
|
|
47
|
-
`, a = `${n}
|
|
52
|
+
`, a = "// Your AI Firebase — the page-content list.\n// The build finds content files automatically where the Your AI Firebase\n// Vite plugin runs; in a runtime without it (Google AI Studio) the two lines\n// per page below are the ONLY thing that loads a page's content file.\n// Add two lines for every page. Never remove another page's lines.\n//\n// Example, for the page at /pricing filled by PricingContent.tsx:\n// import PricingContent from './PricingContent';\n// registerMicrocomponent('pricing', PricingContent);\nimport { registerMicrocomponent } from 'your-ai-workflow-firebase-os';\nexport { registerMicrocomponent };\n", o = `${n}
|
|
48
53
|
import { StrictMode } from 'react'
|
|
49
54
|
import { createRoot } from 'react-dom/client'
|
|
50
55
|
|
|
@@ -68,48 +73,48 @@ createRoot(document.getElementById('root')!).render(
|
|
|
68
73
|
<App />
|
|
69
74
|
</StrictMode>,
|
|
70
75
|
)
|
|
71
|
-
`,
|
|
76
|
+
`, s = "src/your-ai-workflow-firebase-os", c = `${s}/configs`, l = `${s}/microcomponents`, u = [
|
|
72
77
|
"theme.config.ts",
|
|
73
78
|
"contactForm.config.ts",
|
|
74
79
|
"supportForm.config.ts",
|
|
75
80
|
"registry.ts",
|
|
76
81
|
"pagesRegistry.ts"
|
|
77
|
-
],
|
|
82
|
+
], d = (e) => e.split(t.sep).join("/"), f = (e) => t.basename(e).replace(".config.ts", "").replace(/Tab$/, "").toLowerCase(), p = (e) => t.basename(e).replace(".config.ts", "").replace(/Page$/, "").toLowerCase(), m = (e) => t.basename(e).replace(".config.ts", "").replace(/Form$/, "").toLowerCase(), h = (e) => {
|
|
78
83
|
let n = t.basename(e).replace(/\.tsx$/, "").replace(/Content$/, "").replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
79
84
|
return [n, n.replace(/_/g, "")];
|
|
80
|
-
},
|
|
81
|
-
function
|
|
85
|
+
}, g = (e) => t.basename(e).replace(/\.config\.ts$/, "");
|
|
86
|
+
function _(e) {
|
|
82
87
|
let n = t.basename(e);
|
|
83
|
-
return
|
|
88
|
+
return u.includes(n) ? "shipped" : /Tab\.config\.ts$/.test(n) ? "tab" : /Page\.config\.ts$/.test(n) ? "page" : /Form\.config\.ts$/.test(n) ? "form" : "other";
|
|
84
89
|
}
|
|
85
|
-
var
|
|
86
|
-
function
|
|
87
|
-
let r =
|
|
88
|
-
return r.startsWith(
|
|
90
|
+
var v = (t) => e.existsSync(t) ? e.readdirSync(t, { withFileTypes: !0 }).filter((e) => e.isFile()).map((e) => e.name).sort() : [], y = (n) => e.existsSync(t.join(n, s));
|
|
91
|
+
function b(e, n) {
|
|
92
|
+
let r = d(t.relative(e, n));
|
|
93
|
+
return r.startsWith(c + "/") || r.startsWith(l + "/");
|
|
89
94
|
}
|
|
90
|
-
function
|
|
91
|
-
let n = [], r = t.join(e,
|
|
92
|
-
for (let e of
|
|
95
|
+
function x(e) {
|
|
96
|
+
let n = [], r = t.join(e, c);
|
|
97
|
+
for (let e of v(r)) {
|
|
93
98
|
if (!/\.tsx?$/.test(e)) continue;
|
|
94
|
-
let i = t.join(r, e), a = `${
|
|
99
|
+
let i = t.join(r, e), a = `${c}/${e}`, o = _(e);
|
|
95
100
|
o === "tab" ? n.push({
|
|
96
101
|
kind: o,
|
|
97
102
|
file: a,
|
|
98
103
|
abs: i,
|
|
99
104
|
name: e,
|
|
100
|
-
id:
|
|
105
|
+
id: f(e)
|
|
101
106
|
}) : o === "page" ? n.push({
|
|
102
107
|
kind: o,
|
|
103
108
|
file: a,
|
|
104
109
|
abs: i,
|
|
105
110
|
name: e,
|
|
106
|
-
id:
|
|
111
|
+
id: p(e)
|
|
107
112
|
}) : o === "form" || /Form\.config\.ts$/.test(e) ? n.push({
|
|
108
113
|
kind: "form",
|
|
109
114
|
file: a,
|
|
110
115
|
abs: i,
|
|
111
116
|
name: e,
|
|
112
|
-
id:
|
|
117
|
+
id: m(e)
|
|
113
118
|
}) : n.push({
|
|
114
119
|
kind: "other",
|
|
115
120
|
file: a,
|
|
@@ -118,25 +123,58 @@ function b(e) {
|
|
|
118
123
|
id: ""
|
|
119
124
|
});
|
|
120
125
|
}
|
|
121
|
-
let i = t.join(e,
|
|
122
|
-
for (let e of
|
|
126
|
+
let i = t.join(e, l);
|
|
127
|
+
for (let e of v(i)) e.endsWith(".tsx") && e.replace(/\.tsx$/, "") !== "registry" && n.push({
|
|
123
128
|
kind: "microcomponent",
|
|
124
|
-
file: `${
|
|
129
|
+
file: `${l}/${e}`,
|
|
125
130
|
abs: t.join(i, e),
|
|
126
131
|
name: e,
|
|
127
|
-
id:
|
|
132
|
+
id: h(e)[0]
|
|
128
133
|
});
|
|
129
134
|
return n;
|
|
130
135
|
}
|
|
131
|
-
var
|
|
132
|
-
|
|
136
|
+
var S = (e) => e.filter((e) => e.kind !== "other"), C = [{
|
|
137
|
+
test: (e) => /Content\.tsx$/.test(e),
|
|
138
|
+
home: l
|
|
139
|
+
}, {
|
|
140
|
+
test: (e) => /(Tab|Page|Form)\.config\.tsx?$/.test(e),
|
|
141
|
+
home: c
|
|
142
|
+
}], w = new Set([
|
|
143
|
+
"node_modules",
|
|
144
|
+
".git",
|
|
145
|
+
"dist",
|
|
146
|
+
"build"
|
|
147
|
+
]);
|
|
148
|
+
function T(n) {
|
|
149
|
+
let r = [], i = t.join(n, "src"), a = (i, o) => {
|
|
150
|
+
if (!(o > 6 || !e.existsSync(i))) for (let s of e.readdirSync(i, { withFileTypes: !0 })) {
|
|
151
|
+
let e = t.join(i, s.name), u = d(t.relative(n, e));
|
|
152
|
+
if (s.isDirectory()) {
|
|
153
|
+
w.has(s.name) || a(e, o + 1);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (!(u === `${c}/${s.name}` || u === `${l}/${s.name}`)) {
|
|
157
|
+
for (let { test: e, home: t } of C) if (e(s.name)) {
|
|
158
|
+
r.push(`${u}: files like this are only found directly in ${t}/ — move it to ${t}/${s.name}.`);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
return a(i, 0), r.sort();
|
|
165
|
+
}
|
|
166
|
+
var E = (e) => {
|
|
167
|
+
let n = t.basename(e);
|
|
168
|
+
return C.some((e) => e.test(n));
|
|
169
|
+
}, D = (e) => JSON.stringify(e);
|
|
170
|
+
function O(e) {
|
|
133
171
|
let t = [], n = [], r = [], i = [];
|
|
134
|
-
return
|
|
172
|
+
return S(e).forEach((e, a) => {
|
|
135
173
|
let o = `m${a}`;
|
|
136
|
-
if (t.push(`import * as ${o} from ${
|
|
174
|
+
if (t.push(`import * as ${o} from ${D(d(e.abs))};`), e.kind === "tab") n.push(`{
|
|
137
175
|
const configVal = pickConfig(${o});
|
|
138
176
|
if (configVal) {
|
|
139
|
-
const tabId = ${
|
|
177
|
+
const tabId = ${D(e.id)};
|
|
140
178
|
const finalTab = {
|
|
141
179
|
config: {
|
|
142
180
|
...configVal,
|
|
@@ -155,7 +193,7 @@ function C(e) {
|
|
|
155
193
|
else if (e.kind === "page") n.push(`{
|
|
156
194
|
const configVal = pickConfig(${o});
|
|
157
195
|
if (configVal) {
|
|
158
|
-
const pageId = ${
|
|
196
|
+
const pageId = ${D(e.id)};
|
|
159
197
|
const finalPage = {
|
|
160
198
|
config: {
|
|
161
199
|
...configVal,
|
|
@@ -174,7 +212,7 @@ function C(e) {
|
|
|
174
212
|
else if (e.kind === "form") r.push(`{
|
|
175
213
|
const configVal = pickConfig(${o});
|
|
176
214
|
if (configVal) {
|
|
177
|
-
const formId = ${
|
|
215
|
+
const formId = ${D(e.id)};
|
|
178
216
|
// The form's id is its file name; systemName always follows the file.
|
|
179
217
|
const finalConfig = { ...configVal, systemName: formId };
|
|
180
218
|
forms[formId] = finalConfig;
|
|
@@ -183,16 +221,16 @@ function C(e) {
|
|
|
183
221
|
}
|
|
184
222
|
}`);
|
|
185
223
|
else if (e.kind === "microcomponent") {
|
|
186
|
-
let [t, n] =
|
|
224
|
+
let [t, n] = h(e.name);
|
|
187
225
|
i.push(`if (${o} && ${o}.default) {
|
|
188
|
-
microcomponents[${
|
|
226
|
+
microcomponents[${D(t)}] = ${o}.default;
|
|
189
227
|
// Also answer to the squashed form ("mobile_apps" -> "mobileapps"): a page id
|
|
190
228
|
// derived from a file name (mobileAppsPage.config.ts -> "mobileapps") has no
|
|
191
229
|
// underscores, and the page must still find MobileAppsContent.tsx.
|
|
192
|
-
microcomponents[${
|
|
230
|
+
microcomponents[${D(n)}] = ${o}.default;
|
|
193
231
|
}`);
|
|
194
232
|
}
|
|
195
|
-
}), `// Generated by Your AI Firebase from the files in ${
|
|
233
|
+
}), `// Generated by Your AI Firebase from the files in ${s}/.
|
|
196
234
|
// Never written to disk; never edit. Add or remove a file and it updates itself.
|
|
197
235
|
${t.join("\n")}
|
|
198
236
|
|
|
@@ -230,67 +268,67 @@ export const formsRegistry = forms;
|
|
|
230
268
|
export const microcomponentRegistry = microcomponents;
|
|
231
269
|
`;
|
|
232
270
|
}
|
|
233
|
-
var
|
|
271
|
+
var k = (e) => O(x(e)), A = (e) => e.split("/").pop() || e, j = (e) => /\/configs\/[^/]+$/.test(e), M = (e) => /\/microcomponents\/[^/]+\.tsx$/.test(e), N = (e) => e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:\\'"`])\/\/.*$/gm, "$1"), P = (e, t) => {
|
|
234
272
|
let n = RegExp(`(?:^|[\\s,{])${t}\\s*:\\s*([^,\\n}]+)`, "g"), r = [], i;
|
|
235
273
|
for (; i = n.exec(e);) r.push(i[1].trim());
|
|
236
274
|
return r;
|
|
237
|
-
},
|
|
275
|
+
}, F = (e) => {
|
|
238
276
|
let t = e.match(/^(['"`])([^'"`]*)\1$/);
|
|
239
277
|
return t ? t[2] : null;
|
|
240
|
-
},
|
|
241
|
-
let t =
|
|
278
|
+
}, I = (e) => /export\s+(?:const|let|var|function|class)\s+\w*Config\b/.test(e) || /export\s*\{[^}]*\b\w*Config\b[^}]*\}/.test(e), L = (e) => /export\s+default\b/.test(e), R = (e) => {
|
|
279
|
+
let t = P(e, "route");
|
|
242
280
|
return {
|
|
243
281
|
first: t[0],
|
|
244
282
|
count: t.length
|
|
245
283
|
};
|
|
246
284
|
};
|
|
247
|
-
function
|
|
285
|
+
function z(e) {
|
|
248
286
|
let t = [], n = [], r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set();
|
|
249
|
-
for (let { file: t } of e) if (
|
|
287
|
+
for (let { file: t } of e) if (M(t)) for (let e of h(A(t))) i.add(e);
|
|
250
288
|
for (let { file: a, source: o } of e) {
|
|
251
|
-
let e =
|
|
252
|
-
if (
|
|
253
|
-
let n =
|
|
289
|
+
let e = A(a), s = N(o);
|
|
290
|
+
if (j(a)) {
|
|
291
|
+
let n = _(e);
|
|
254
292
|
if (n === "shipped") continue;
|
|
255
293
|
if (n === "other") {
|
|
256
294
|
t.push(`${a}: rename it to somethingTab.config.ts (a dashboard page), somethingPage.config.ts (a page for anyone) or somethingForm.config.ts (a form).`);
|
|
257
295
|
continue;
|
|
258
296
|
}
|
|
259
|
-
if (!
|
|
260
|
-
let { first: o, count: c } =
|
|
297
|
+
if (!I(s) && !L(s) && t.push(`${a}: export one const named ${g(e)}Config.`), n === "tab" || n === "page") {
|
|
298
|
+
let { first: o, count: c } = R(s), l = o === void 0 ? null : F(o);
|
|
261
299
|
if (c === 0 || l === null || !l.startsWith("/")) t.push(`${a}: route must be one string starting with /, e.g. route: '/onboarding'. A page has exactly one web address.`);
|
|
262
300
|
else {
|
|
263
301
|
let e = r.get(l);
|
|
264
302
|
e ? t.push(`${a}: route '${l}' is already used by ${e}. One page, one file, one address.`) : r.set(l, a);
|
|
265
303
|
}
|
|
266
|
-
let u =
|
|
267
|
-
if (!
|
|
304
|
+
let u = P(s, "template")[0], d = u === void 0 ? null : F(u);
|
|
305
|
+
if (!d || ![
|
|
268
306
|
"board",
|
|
269
307
|
"table",
|
|
270
308
|
"calendar",
|
|
271
309
|
"drive",
|
|
272
310
|
"inline_form",
|
|
273
311
|
"popup_form"
|
|
274
|
-
].includes(
|
|
275
|
-
let r = n === "tab" ?
|
|
312
|
+
].includes(d)) {
|
|
313
|
+
let r = n === "tab" ? f(e) : p(e), o = P(s, n === "tab" ? "tabName" : "pageName")[0], c = o === void 0 ? null : F(o), l = (e) => e.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
|
|
276
314
|
if (![r, ...c ? [l(c), l(c).replace(/_/g, "")] : []].some((e) => i.has(e))) {
|
|
277
|
-
let n =
|
|
315
|
+
let n = g(e).replace(/(Tab|Page)$/, ""), r = (c || n).split(/[^a-zA-Z0-9]+/).filter(Boolean).map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join("");
|
|
278
316
|
t.push(`${a}: no content file matches this page, so it renders empty — create src/your-ai-workflow-firebase-os/microcomponents/${r}Content.tsx with export default.`);
|
|
279
317
|
}
|
|
280
318
|
}
|
|
281
319
|
}
|
|
282
320
|
if (n === "tab") {
|
|
283
|
-
let e =
|
|
321
|
+
let e = P(s, "pageType")[0], n = e === void 0 ? null : F(e);
|
|
284
322
|
n !== "user" && n !== "internal" && n !== "admin" && t.push(`${a}: pageType must be 'user', 'internal' or 'admin'. A dashboard page is never public.`);
|
|
285
323
|
}
|
|
286
324
|
if (n === "form") {
|
|
287
|
-
let n =
|
|
288
|
-
r !== void 0 &&
|
|
325
|
+
let n = m(e), r = P(s, "systemName")[0];
|
|
326
|
+
r !== void 0 && F(r) !== n && t.push(`${a}: systemName must be '${n}'.`);
|
|
289
327
|
}
|
|
290
328
|
continue;
|
|
291
329
|
}
|
|
292
|
-
if (
|
|
293
|
-
|
|
330
|
+
if (M(a)) {
|
|
331
|
+
L(s) || t.push(`${a}: add export default.`), (/<form\b/.test(s) || /\bonSubmit\b/.test(s)) && !/ContactPopup/.test(s) && n.push(`${a}: forms are *Form.config.ts files shown with <ContactPopup formId="…" />; a hand-written form never reaches the Inbox.`), /<style[\s>]/.test(s) && t.push(`${a}: a <style> tag is global CSS and restyles every page of the app — delete it and style with theme classes (bg-background, text-foreground, glass-panel, btn-primary).`);
|
|
294
332
|
let e = s.match(/\b(?:bg-(?:white|black)|(?:bg|text|border)-(?:gray|slate|zinc|neutral|stone)-\d+)\b/);
|
|
295
333
|
e && n.push(`${a}: ${e[0]} is a hard-coded colour that ignores the owner's theme and stays wrong in light or dark mode — use bg-background, text-foreground, border-[var(--panel-border)], glass-panel or btn-primary.`);
|
|
296
334
|
}
|
|
@@ -300,53 +338,63 @@ function P(e) {
|
|
|
300
338
|
warnings: n
|
|
301
339
|
};
|
|
302
340
|
}
|
|
303
|
-
function
|
|
304
|
-
return
|
|
341
|
+
function B(e, t) {
|
|
342
|
+
return z(e.map((e) => ({
|
|
305
343
|
file: e.file,
|
|
306
344
|
source: t(e.abs)
|
|
307
345
|
})));
|
|
308
346
|
}
|
|
309
347
|
//#endregion
|
|
310
348
|
//#region src/vite/plugin.ts
|
|
311
|
-
var
|
|
349
|
+
var V = r, H = "\0" + V, U = [{
|
|
312
350
|
rel: "src/App.tsx",
|
|
313
351
|
source: i
|
|
314
352
|
}, {
|
|
315
353
|
rel: "src/main.tsx",
|
|
316
|
-
source:
|
|
317
|
-
}],
|
|
354
|
+
source: o
|
|
355
|
+
}], W = (e) => `${e} is owned by Your AI Firebase; your edit was discarded.`, G = (e) => e.replace(/[?#].*$/, ""), K = (e) => t.normalize(e).split(t.sep).join("/"), q = {
|
|
318
356
|
info: (e) => console.log(e),
|
|
319
357
|
warn: (e) => console.warn(e),
|
|
320
358
|
error: (e) => console.error(e)
|
|
321
359
|
};
|
|
322
|
-
function
|
|
360
|
+
function J(n, r = q) {
|
|
323
361
|
let i = [];
|
|
324
|
-
for (let { rel: a, source: o } of
|
|
362
|
+
for (let { rel: a, source: o } of U) {
|
|
325
363
|
let s = t.join(n, a), c = null;
|
|
326
364
|
try {
|
|
327
365
|
c = e.readFileSync(s, "utf8");
|
|
328
366
|
} catch {
|
|
329
367
|
c = null;
|
|
330
368
|
}
|
|
331
|
-
c !== o && (e.mkdirSync(t.dirname(s), { recursive: !0 }), e.writeFileSync(s, o), i.push(a), c !== null && r.warn(
|
|
369
|
+
c !== o && (e.mkdirSync(t.dirname(s), { recursive: !0 }), e.writeFileSync(s, o), i.push(a), c !== null && r.warn(W(a)));
|
|
332
370
|
}
|
|
333
371
|
return i;
|
|
334
372
|
}
|
|
335
|
-
|
|
336
|
-
let r =
|
|
337
|
-
|
|
373
|
+
function Y(n) {
|
|
374
|
+
let r = t.join(n, l, "registry.ts");
|
|
375
|
+
return e.existsSync(r) ? !1 : (e.mkdirSync(t.dirname(r), { recursive: !0 }), e.writeFileSync(r, a), !0);
|
|
376
|
+
}
|
|
377
|
+
var X = (e, n) => {
|
|
378
|
+
let r = K(G(n));
|
|
379
|
+
for (let { rel: n, source: i } of U) if (r === K(t.join(e, n))) return i;
|
|
338
380
|
return null;
|
|
339
381
|
};
|
|
340
|
-
function
|
|
341
|
-
let t = process.cwd(), n = !1, r = "build", i =
|
|
382
|
+
function Z() {
|
|
383
|
+
let t = process.cwd(), n = !1, r = "build", i = q, a = () => {
|
|
384
|
+
let n = B(x(t), (t) => e.readFileSync(t, "utf8"));
|
|
385
|
+
return {
|
|
386
|
+
...n,
|
|
387
|
+
errors: [...n.errors, ...T(t)]
|
|
388
|
+
};
|
|
389
|
+
};
|
|
342
390
|
return {
|
|
343
391
|
name: "your-ai-firebase",
|
|
344
392
|
enforce: "pre",
|
|
345
393
|
configResolved(e) {
|
|
346
|
-
t = e.root, r = e.command, i = e.logger, n =
|
|
394
|
+
t = e.root, r = e.command, i = e.logger, n = y(t), n && (J(t, i), Y(t));
|
|
347
395
|
},
|
|
348
396
|
resolveId(e) {
|
|
349
|
-
return e ===
|
|
397
|
+
return e === V ? H : null;
|
|
350
398
|
},
|
|
351
399
|
buildStart() {
|
|
352
400
|
if (!n) return;
|
|
@@ -355,29 +403,29 @@ function G() {
|
|
|
355
403
|
if (e.length !== 0) if (r === "build") this.error(e[0]);
|
|
356
404
|
else for (let t of e) i.error(t);
|
|
357
405
|
},
|
|
358
|
-
load(
|
|
406
|
+
load(e) {
|
|
359
407
|
if (!n) return null;
|
|
360
|
-
if (
|
|
361
|
-
let
|
|
362
|
-
return
|
|
408
|
+
if (e === H) {
|
|
409
|
+
let e = x(t), { errors: n } = a();
|
|
410
|
+
return n.length && this.error(n[0]), O(e);
|
|
363
411
|
}
|
|
364
|
-
return
|
|
412
|
+
return X(t, e);
|
|
365
413
|
},
|
|
366
414
|
configureServer(e) {
|
|
367
415
|
if (!n) return;
|
|
368
416
|
let r = () => {
|
|
369
|
-
let t = e.moduleGraph.getModuleById(
|
|
417
|
+
let t = e.moduleGraph.getModuleById(H);
|
|
370
418
|
t && e.moduleGraph.invalidateModule(t), e.ws.send({
|
|
371
419
|
type: "full-reload",
|
|
372
420
|
path: "*"
|
|
373
421
|
});
|
|
374
422
|
}, i = (n) => {
|
|
375
|
-
let i =
|
|
376
|
-
if (
|
|
377
|
-
|
|
423
|
+
let i = K(n);
|
|
424
|
+
if (X(t, i) !== null) {
|
|
425
|
+
J(t, e.config.logger);
|
|
378
426
|
return;
|
|
379
427
|
}
|
|
380
|
-
if (!
|
|
428
|
+
if (!b(t, i) && !E(i)) return;
|
|
381
429
|
r();
|
|
382
430
|
let { errors: o, warnings: s } = a();
|
|
383
431
|
for (let t of s) e.config.logger.warn(t);
|
|
@@ -388,4 +436,4 @@ function G() {
|
|
|
388
436
|
};
|
|
389
437
|
}
|
|
390
438
|
//#endregion
|
|
391
|
-
export { i as CANONICAL_APP_TSX,
|
|
439
|
+
export { i as CANONICAL_APP_TSX, o as CANONICAL_MAIN_TSX, c as CONFIGS_DIR, s as CONSUMER_DIR, a as CONSUMER_REGISTRY_TS, l as MICROCOMPONENTS_DIR, n as OWNED_BANNER, H as RESOLVED_VIRTUAL_ID, u as SHIPPED_CONFIG_FILES, V as VIRTUAL_ID, r as VIRTUAL_REGISTRIES_ID, _ as classifyConfigFile, x as discover, Y as ensureConsumerRegistry, g as fileIdFromConfigFile, m as formIdFromFile, y as isConsumerRoot, b as isDiscoveredPath, h as microcomponentKeysFromFile, W as ownedMessage, p as pageIdFromFile, S as registrable, J as restoreOwnedFiles, N as stripComments, f as tabIdFromFile, z as validate, B as validateDiscovered, k as virtualModuleSource, O as virtualModuleSourceFor, Z as yourAiFirebase };
|