@stacksjs/config 0.70.293 → 0.70.296

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/config.d.ts CHANGED
@@ -93,6 +93,7 @@ export declare let queue: StacksOptions['queue'];
93
93
  export declare let security: StacksOptions['security'];
94
94
  export declare let saas: StacksOptions['saas'];
95
95
  export declare let searchEngine: StacksOptions['searchEngine'];
96
+ export declare let server: StacksOptions['server'];
96
97
  export declare let services: StacksOptions['services'];
97
98
  export declare let filesystems: StacksOptions['filesystems'];
98
99
  export declare let team: StacksOptions['team'];
package/dist/config.js CHANGED
@@ -1 +1 @@
1
- import{defaults}from"./defaults";import{overrides,overridesReady}from"./overrides";function readMerged(prop){const o=overrides[prop];if(o!==void 0&&(typeof o!=="object"||Object.keys(o).length>0))return o;return defaults[prop]}const proxyTarget=function configProxyTarget(){};export const config=new Proxy(proxyTarget,{get(_t,prop){return readMerged(prop)},has(_t,prop){return prop in overrides||prop in defaults},ownKeys(){return Array.from(new Set([...Object.keys(overrides),...Object.keys(defaults)]))},getOwnPropertyDescriptor(_t,prop){if(typeof prop!=="string")return;if(!(prop in overrides)&&!(prop in defaults))return;return{enumerable:!0,configurable:!0,writable:!0,value:readMerged(prop)}},isExtensible(){return!0},preventExtensions(){return!1}});export async function awaitConfig(){await overridesReady;return config}const DB_READY=Symbol.for("@stacksjs/config:databaseReady"),globalScope=globalThis;export async function awaitDatabaseConfig(){await overridesReady;const deadline=Date.now()+5000;while(!globalScope[DB_READY]&&Date.now()<deadline)await new Promise((r)=>setTimeout(r,25));if(!globalScope[DB_READY])console.warn("[config] awaitDatabaseConfig() timed out \u2014 database driver did not signal readiness within 5s");return config}export function markDatabaseReady(){globalScope[DB_READY]=!0}export function getConfig(){return config}export let{ai,analytics,app,auth,realtime,cache,cloud,cli,dashboard,database,dns,docs,email,errors,featureFlags,git,hashing,library,logging,notification,payment,ports,queue,security,saas,searchEngine,services,filesystems,team,ui}=config;overridesReady.then(()=>{ai=config.ai;analytics=config.analytics;app=config.app;auth=config.auth;realtime=config.realtime;cache=config.cache;cloud=config.cloud;cli=config.cli;dashboard=config.dashboard;database=config.database;dns=config.dns;docs=config.docs;email=config.email;errors=config.errors;featureFlags=config.featureFlags;git=config.git;hashing=config.hashing;library=config.library;logging=config.logging;notification=config.notification;payment=config.payment;ports=config.ports;queue=config.queue;security=config.security;saas=config.saas;searchEngine=config.searchEngine;services=config.services;filesystems=config.filesystems;team=config.team;ui=config.ui}).catch(()=>{});export*from"./helpers";export{defaults,overrides,overridesReady};export function determineAppEnv(){const env=config.app?.env;if(env==="local"||env==="development")return"dev";if(env==="staging")return"stage";if(env==="production")return"prod";if(!env)throw Error("Couldn't determine app environment");return env}
1
+ import{defaults}from"./defaults";import{overrides,overridesReady}from"./overrides";function readMerged(prop){const o=overrides[prop];if(o!==void 0&&(typeof o!=="object"||Object.keys(o).length>0))return o;return defaults[prop]}const proxyTarget=function configProxyTarget(){};export const config=new Proxy(proxyTarget,{get(_t,prop){return readMerged(prop)},has(_t,prop){return prop in overrides||prop in defaults},ownKeys(){return Array.from(new Set([...Object.keys(overrides),...Object.keys(defaults)]))},getOwnPropertyDescriptor(_t,prop){if(typeof prop!=="string")return;if(!(prop in overrides)&&!(prop in defaults))return;return{enumerable:!0,configurable:!0,writable:!0,value:readMerged(prop)}},isExtensible(){return!0},preventExtensions(){return!1}});export async function awaitConfig(){await overridesReady;return config}const DB_READY=Symbol.for("@stacksjs/config:databaseReady"),globalScope=globalThis;export async function awaitDatabaseConfig(){await overridesReady;const deadline=Date.now()+5000;while(!globalScope[DB_READY]&&Date.now()<deadline)await new Promise((r)=>setTimeout(r,25));if(!globalScope[DB_READY])console.warn("[config] awaitDatabaseConfig() timed out \u2014 database driver did not signal readiness within 5s");return config}export function markDatabaseReady(){globalScope[DB_READY]=!0}export function getConfig(){return config}export let{ai,analytics,app,auth,realtime,cache,cloud,cli,dashboard,database,dns,docs,email,errors,featureFlags,git,hashing,library,logging,notification,payment,ports,queue,security,saas,searchEngine,server,services,filesystems,team,ui}=config;overridesReady.then(()=>{ai=config.ai;analytics=config.analytics;app=config.app;auth=config.auth;realtime=config.realtime;cache=config.cache;cloud=config.cloud;cli=config.cli;dashboard=config.dashboard;database=config.database;dns=config.dns;docs=config.docs;email=config.email;errors=config.errors;featureFlags=config.featureFlags;git=config.git;hashing=config.hashing;library=config.library;logging=config.logging;notification=config.notification;payment=config.payment;ports=config.ports;queue=config.queue;security=config.security;saas=config.saas;searchEngine=config.searchEngine;server=config.server;services=config.services;filesystems=config.filesystems;team=config.team;ui=config.ui}).catch(()=>{});export*from"./helpers";export{defaults,overrides,overridesReady};export function determineAppEnv(){const env=config.app?.env;if(env==="local"||env==="development")return"dev";if(env==="staging")return"stage";if(env==="production")return"prod";if(!env)throw Error("Couldn't determine app environment");return env}
package/dist/defaults.js CHANGED
@@ -1,5 +1,5 @@
1
- var {require}=import.meta;import{commandsPath,projectPath,userDatabasePath}from"@stacksjs/path";export const FRAMEWORK_DEFAULTS={awsRegion:"us-east-1",timezone:"UTC",noReplyEmail:"no-reply@stacksjs.com",fallbackDomain:"stacks.localhost"};function deriveAppDefaults(){try{const pkgPath=projectPath("package.json"),raw=(require(pkgPath).name??"").trim();if(!raw)return{name:"Stacks",url:"stacks.localhost"};const slug=raw.replace(/^@[^/]+\//,"").toLowerCase();return{name:slug.replace(/[-_]+/g," ").replace(/(^|\s)\w/g,(c)=>c.toUpperCase()),url:`${slug}.localhost`}}catch{return{name:"Stacks",url:"stacks.localhost"}}}const appDefaults=deriveAppDefaults();export const defaults={cms:{enabled:!1},commerce:{enabled:!1},marketing:{enabled:!1},monitoring:{enabled:!1},ai:{deploy:!1,models:["anthropic.claude-sonnet-4-20250514-v1:0","anthropic.claude-haiku-4-20250514-v1:0","anthropic.claude-3-5-sonnet-20241022-v2:0","amazon.titan-embed-text-v2:0","amazon.titan-text-premier-v1:0","amazon.titan-image-generator-v2:0","meta.llama3-1-70b-instruct-v1:0","meta.llama3-1-8b-instruct-v1:0"]},auth:{username:"email",password:"password",defaultTokenName:"auth-token",tokenExpiry:3600000,refreshTokenExpiry:2592000000,defaultAbilities:["*"]},realtime:{driver:"pusher"},analytics:{driver:void 0},app:{name:appDefaults.name,description:"A Stacks application.",env:"local",url:appDefaults.url,debug:!0,key:"",timezone:FRAMEWORK_DEFAULTS.timezone,locale:"en",fallbackLocale:"en",cipher:"AES-256-CBC",docMode:!1,redirectUrls:[],maintenanceMode:!1,comingSoonMode:!1,comingSoonSecret:""},cli:{name:"My Custom CLI",command:"my-custom-cli",description:"Stacks is a full-stack framework for TypeScript.",source:commandsPath(),deploy:!1},cache:{driver:"memory",prefix:"stx",ttl:3600,maxKeys:-1,useClones:!0,drivers:{redis:{host:"localhost",port:6379,username:"",password:"",database:0,tls:!1},memory:{maxKeys:-1,checkPeriod:600,deleteOnExpire:!0}}},featureFlags:{default:"memory",missing:"false",drivers:{memory:{cloneValues:!0},database:{table:"feature_flags",autoCreate:!1}}},cloud:{infrastructure:{type:"serverless",driver:"aws",environments:["production","staging","development"],firewall:{enabled:!0,countryCodes:[],ipAddresses:[],queryString:[],httpHeaders:[],rateLimitPerMinute:1000,useIpReputationLists:!0,useKnownBadInputsRuleSet:!0},cdn:{allowedMethods:"GET_HEAD",cachedMethods:"GET_HEAD",minTtl:0,defaultTtl:86400,maxTtl:31536000,compress:!0,priceClass:"PriceClass_All",originShieldRegion:FRAMEWORK_DEFAULTS.awsRegion,cookieBehavior:"none",allowList:{cookies:[],headers:[],queryStrings:[]},realtimeLogs:{enabled:!0,samplingRate:2}},fileSystem:!1,storage:{}},sites:{root:"",path:""}},dashboard:{sections:{library:{enabled:!0},content:{enabled:!0},commerce:{enabled:!0},marketing:{enabled:!0},analytics:{enabled:!0},management:{enabled:!0},utilities:{enabled:!0}}},database:{default:"sqlite",logging:!1,connections:{sqlite:{database:userDatabasePath("stacks.sqlite"),prefix:""}},migrations:"migrations",migrationLocks:"migration_locks"},dns:{driver:"aws",a:[],aaaa:[],cname:[],mx:[],txt:[]},docs:{lang:"en-US",lastUpdated:!0,deploy:!1,themeConfig:{editLink:{pattern:"https://github.com/stacksjs/stacks/edit/main/docs/docs/:path",text:"Edit this page on GitHub"},footer:{message:"Released under the MIT License.",copyright:"Copyright \xA9 2024-present Stacks.js, Inc."}}},email:{from:{name:"Stacks",address:FRAMEWORK_DEFAULTS.noReplyEmail},mailboxes:[],server:{enabled:!0,scan:!0}},errors:{messages:{string:"The {{ field }} field must be a string",email:"The {{ field }} field must be a valid email address",regex:"The {{ field }} field format is invalid",url:"The {{ field }} field must be a valid URL",activeUrl:"The {{ field }} field must be a valid URL",alpha:"The {{ field }} field must contain only letters",alphaNumeric:"The {{ field }} field must contain only letters and numbers","min(":"The {{ field }} field must have at least {{ min }} characters",maxLength:"The {{ field }} field must not be greater than {{ max }} characters",fixedLength:"The {{ field }} field must be {{ size }} characters long",confirmed:"The {{ field }} field and {{ otherField }} field must be the same",endsWith:"The {{ field }} field must end with {{ substring }}",startsWith:"The {{ field }} field must start with {{ substring }}",sameAs:"The {{ field }} field and {{ otherField }} field must be the same",notSameAs:"The {{ field }} field and {{ otherField }} field must be different",in:"The selected {{ field }} is invalid",notIn:"The selected {{ field }} is invalid",ipAddress:"The {{ field }} field must be a valid IP address",uuid:"The {{ field }} field must be a valid UUID",ascii:"The {{ field }} field must only contain ASCII characters",creditCard:"The {{ field }} field must be a valid {{ providersList }} card number",hexCode:"The {{ field }} field must be a valid hex color code",iban:"The {{ field }} field must be a valid IBAN number",jwt:"The {{ field }} field must be a valid JWT token",coordinates:"The {{ field }} field must contain latitude and longitude coordinates",mobile:"The {{ field }} field must be a valid mobile phone number",passport:"The {{ field }} field must be a valid passport number",postalCode:"The {{ field }} field must be a valid postal code",boolean:"The value must be a boolean",number:"The {{ field }} field must be a number",min:"The {{ field }} field must be at least {{ min }}",max:"The {{ field }} field must not be greater than {{ max }}",range:"The {{ field }} field must be between {{ min }} and {{ max }}",positive:"The {{ field }} field must be positive",negative:"The {{ field }} field must be negative",decimal:"The {{ field }} field must have {{ digits }} decimal places",withoutDecimals:"The {{ field }} field must not have decimal places",date:"The {{ field }} field must be a datetime value","date.equals":"The {{ field }} field must be a date equal to {{ expectedValue }}","date.after":"The {{ field }} field must be a date after {{ expectedValue }}","date.before":"The {{ field }} field must be a date before {{ expectedValue }}","date.afterOrEqual":"The {{ field }} field must be a date after or equal to {{ expectedValue }}","date.beforeOrEqual":"The {{ field }} field must be a date before or equal to {{ expectedValue }}","date.sameAs":"The {{ field }} field and {{ otherField }} field must be the same","date.notSameAs":"The {{ field }} field and {{ otherField }} field must be different","date.afterField":"The {{ field }} field must be a date after {{ otherField }}",accepted:"The {{ field }} field must be accepted",enum:"The selected {{ field }} is invalid",literal:"The {{ field }} field must be {{ expectedValue }}",object:"The {{ field }} field must be an object",record:"The {{ field }} field must be an object","record.min(":"The {{ field }} field must have at least {{ min }} items","record.maxLength":"The {{ field }} field must not have more than {{ max }} items","record.fixedLength":"The {{ field }} field must contain {{ size }} items",array:"The {{ field }} field must be an array","array.min(":"The {{ field }} field must have at least {{ min }} items","array.maxLength":"The {{ field }} field must not have more than {{ max }} items","array.fixedLength":"The {{ field }} field must contain {{ size }} items",notEmpty:"The {{ field }} field must not be empty",distinct:"The {{ field }} field has duplicate values",tuple:"The {{ field }} field must be an array",union:"Invalid value provided for {{ field }} field",unionGroup:"Invalid value provided for {{ field }} field",unionOfTypes:"Invalid value provided for {{ field }} field"}},git:{hooks:{"pre-commit":"lint-staged"},scopes:["","ci","deps","dx","release","docs","test","core","actions","arrays","auth","build","cache","cli","cloud","collections","config","database","datetime","docs","errors","git","lint","modules","notifications","objects","path","realtime","router","buddy","security","server","storage","strings","tests","types","ui","utils"],messages:{type:"Select the type of change that you're committing:",scope:"Select the SCOPE of this change (optional):",customScope:"Select the SCOPE of this change:",subject:`Write a SHORT, IMPERATIVE tense description of the change:
1
+ var {require}=import.meta;import{commandsPath,projectPath,userDatabasePath}from"@stacksjs/path";export const FRAMEWORK_DEFAULTS={awsRegion:"us-east-1",timezone:"UTC",noReplyEmail:"no-reply@stacksjs.com",fallbackDomain:"stacks.localhost"};function deriveAppDefaults(){try{const pkgPath=projectPath("package.json"),raw=(require(pkgPath).name??"").trim();if(!raw)return{name:"Stacks",url:"stacks.localhost"};const slug=raw.replace(/^@[^/]+\//,"").toLowerCase();return{name:slug.replace(/[-_]+/g," ").replace(/(^|\s)\w/g,(c)=>c.toUpperCase()),url:`${slug}.localhost`}}catch{return{name:"Stacks",url:"stacks.localhost"}}}const appDefaults=deriveAppDefaults();export const defaults={cms:{enabled:!1},commerce:{enabled:!1},marketing:{enabled:!1},monitoring:{enabled:!1},ai:{deploy:!1,models:["anthropic.claude-sonnet-4-20250514-v1:0","anthropic.claude-haiku-4-20250514-v1:0","anthropic.claude-3-5-sonnet-20241022-v2:0","amazon.titan-embed-text-v2:0","amazon.titan-text-premier-v1:0","amazon.titan-image-generator-v2:0","meta.llama3-1-70b-instruct-v1:0","meta.llama3-1-8b-instruct-v1:0"]},auth:{username:"email",password:"password",defaultTokenName:"auth-token",cookie:{name:"auth-token"},tokenExpiry:3600000,refreshTokenExpiry:2592000000,defaultAbilities:["*"]},realtime:{driver:"pusher"},analytics:{driver:void 0},app:{name:appDefaults.name,description:"A Stacks application.",env:"local",url:appDefaults.url,debug:!0,key:"",timezone:FRAMEWORK_DEFAULTS.timezone,locale:"en",fallbackLocale:"en",cipher:"AES-256-CBC",docMode:!1,redirectUrls:[],maintenanceMode:!1,comingSoonMode:!1,comingSoonSecret:""},cli:{name:"My Custom CLI",command:"my-custom-cli",description:"Stacks is a full-stack framework for TypeScript.",source:commandsPath(),deploy:!1},cache:{driver:"memory",prefix:"stx",ttl:3600,maxKeys:-1,useClones:!0,drivers:{redis:{host:"localhost",port:6379,username:"",password:"",database:0,tls:!1},memory:{maxKeys:-1,checkPeriod:600,deleteOnExpire:!0}}},featureFlags:{default:"memory",missing:"false",drivers:{memory:{cloneValues:!0},database:{table:"feature_flags",autoCreate:!1}}},cloud:{infrastructure:{type:"serverless",driver:"aws",environments:["production","staging","development"],firewall:{enabled:!0,countryCodes:[],ipAddresses:[],queryString:[],httpHeaders:[],rateLimitPerMinute:1000,useIpReputationLists:!0,useKnownBadInputsRuleSet:!0},cdn:{allowedMethods:"GET_HEAD",cachedMethods:"GET_HEAD",minTtl:0,defaultTtl:86400,maxTtl:31536000,compress:!0,priceClass:"PriceClass_All",originShieldRegion:FRAMEWORK_DEFAULTS.awsRegion,cookieBehavior:"none",allowList:{cookies:[],headers:[],queryStrings:[]},realtimeLogs:{enabled:!0,samplingRate:2}},fileSystem:!1,storage:{}},sites:{root:"",path:""}},dashboard:{sections:{library:{enabled:!0},content:{enabled:!0},commerce:{enabled:!0},marketing:{enabled:!0},analytics:{enabled:!0},management:{enabled:!0},utilities:{enabled:!0}}},database:{default:"sqlite",logging:!1,connections:{sqlite:{database:userDatabasePath("stacks.sqlite"),prefix:""}},migrations:"migrations",migrationLocks:"migration_locks"},dns:{driver:"aws",a:[],aaaa:[],cname:[],mx:[],txt:[]},docs:{lang:"en-US",lastUpdated:!0,deploy:!1,themeConfig:{editLink:{pattern:"https://github.com/stacksjs/stacks/edit/main/docs/docs/:path",text:"Edit this page on GitHub"},footer:{message:"Released under the MIT License.",copyright:"Copyright \xA9 2024-present Stacks.js, Inc."}}},email:{from:{name:"Stacks",address:FRAMEWORK_DEFAULTS.noReplyEmail},mailboxes:[],server:{enabled:!0,scan:!0}},errors:{messages:{string:"The {{ field }} field must be a string",email:"The {{ field }} field must be a valid email address",regex:"The {{ field }} field format is invalid",url:"The {{ field }} field must be a valid URL",activeUrl:"The {{ field }} field must be a valid URL",alpha:"The {{ field }} field must contain only letters",alphaNumeric:"The {{ field }} field must contain only letters and numbers","min(":"The {{ field }} field must have at least {{ min }} characters",maxLength:"The {{ field }} field must not be greater than {{ max }} characters",fixedLength:"The {{ field }} field must be {{ size }} characters long",confirmed:"The {{ field }} field and {{ otherField }} field must be the same",endsWith:"The {{ field }} field must end with {{ substring }}",startsWith:"The {{ field }} field must start with {{ substring }}",sameAs:"The {{ field }} field and {{ otherField }} field must be the same",notSameAs:"The {{ field }} field and {{ otherField }} field must be different",in:"The selected {{ field }} is invalid",notIn:"The selected {{ field }} is invalid",ipAddress:"The {{ field }} field must be a valid IP address",uuid:"The {{ field }} field must be a valid UUID",ascii:"The {{ field }} field must only contain ASCII characters",creditCard:"The {{ field }} field must be a valid {{ providersList }} card number",hexCode:"The {{ field }} field must be a valid hex color code",iban:"The {{ field }} field must be a valid IBAN number",jwt:"The {{ field }} field must be a valid JWT token",coordinates:"The {{ field }} field must contain latitude and longitude coordinates",mobile:"The {{ field }} field must be a valid mobile phone number",passport:"The {{ field }} field must be a valid passport number",postalCode:"The {{ field }} field must be a valid postal code",boolean:"The value must be a boolean",number:"The {{ field }} field must be a number",min:"The {{ field }} field must be at least {{ min }}",max:"The {{ field }} field must not be greater than {{ max }}",range:"The {{ field }} field must be between {{ min }} and {{ max }}",positive:"The {{ field }} field must be positive",negative:"The {{ field }} field must be negative",decimal:"The {{ field }} field must have {{ digits }} decimal places",withoutDecimals:"The {{ field }} field must not have decimal places",date:"The {{ field }} field must be a datetime value","date.equals":"The {{ field }} field must be a date equal to {{ expectedValue }}","date.after":"The {{ field }} field must be a date after {{ expectedValue }}","date.before":"The {{ field }} field must be a date before {{ expectedValue }}","date.afterOrEqual":"The {{ field }} field must be a date after or equal to {{ expectedValue }}","date.beforeOrEqual":"The {{ field }} field must be a date before or equal to {{ expectedValue }}","date.sameAs":"The {{ field }} field and {{ otherField }} field must be the same","date.notSameAs":"The {{ field }} field and {{ otherField }} field must be different","date.afterField":"The {{ field }} field must be a date after {{ otherField }}",accepted:"The {{ field }} field must be accepted",enum:"The selected {{ field }} is invalid",literal:"The {{ field }} field must be {{ expectedValue }}",object:"The {{ field }} field must be an object",record:"The {{ field }} field must be an object","record.min(":"The {{ field }} field must have at least {{ min }} items","record.maxLength":"The {{ field }} field must not have more than {{ max }} items","record.fixedLength":"The {{ field }} field must contain {{ size }} items",array:"The {{ field }} field must be an array","array.min(":"The {{ field }} field must have at least {{ min }} items","array.maxLength":"The {{ field }} field must not have more than {{ max }} items","array.fixedLength":"The {{ field }} field must contain {{ size }} items",notEmpty:"The {{ field }} field must not be empty",distinct:"The {{ field }} field has duplicate values",tuple:"The {{ field }} field must be an array",union:"Invalid value provided for {{ field }} field",unionGroup:"Invalid value provided for {{ field }} field",unionOfTypes:"Invalid value provided for {{ field }} field"}},git:{hooks:{"pre-commit":"lint-staged"},scopes:["","ci","deps","dx","release","docs","test","core","actions","arrays","auth","build","cache","cli","cloud","collections","config","database","datetime","docs","errors","git","lint","modules","notifications","objects","path","realtime","router","buddy","security","server","storage","strings","tests","types","ui","utils"],messages:{type:"Select the type of change that you're committing:",scope:"Select the SCOPE of this change (optional):",customScope:"Select the SCOPE of this change:",subject:`Write a SHORT, IMPERATIVE tense description of the change:
2
2
  `,body:`Provide a LONGER description of the change (optional). Use "|" to break new line:
3
3
  `,breaking:`List any BREAKING CHANGES (optional). Use "|" to break new line:
4
4
  `,footerPrefixesSelect:"Select the ISSUES type of the change list by this change (optional):",customFooterPrefixes:"Input ISSUES prefix:",footer:`List any ISSUES by this change. E.g.: #31, #34:
5
- `,confirmCommit:"Are you sure you want to proceed with the commit above?"},types:[{value:"feat",name:"feat: \u2728 A new feature",emoji:":sparkles:"},{value:"fix",name:"fix: \uD83D\uDC1B A bug fix",emoji:":bug:"},{value:"docs",name:"docs: \uD83D\uDCDD Documentation only changes",emoji:":memo:"},{value:"style",name:"style: \uD83D\uDC84 Changes that do not affect the meaning of the code",emoji:":lipstick:"},{value:"refactor",name:"refactor: \u267B\uFE0F A code change that neither fixes a bug nor adds a feature",emoji:":recycle:"},{value:"perf",name:"perf: \u26A1\uFE0F A code change that improves performance",emoji:":zap:"},{value:"test",name:"test: \u2705 Adding missing tests or adjusting existing tests",emoji:":white_check_mark:"},{value:"build",name:"build: \uD83D\uDCE6\uFE0F Changes that affect the build system or external dependencies",emoji:":package:"},{value:"ci",name:"ci: \uD83C\uDFA1 Changes to our CI configuration files and scripts",emoji:":ferris_wheel:"},{value:"chore",name:"chore: \uD83D\uDD28 Other changes that don't modify src or test files",emoji:":hammer:"},{value:"revert",name:"revert: \u23EA\uFE0F Reverts a previous commit",emoji:":rewind:"}]},hashing:{driver:"bcrypt",bcrypt:{rounds:12},argon2:{memory:65536,time:2}},images:{social:{enabled:!1,outputDir:"public/social",publicPath:"/social",presets:["og","square","portrait"]},appStore:{enabled:!1,outputDir:"resources/app-store/screenshots"},appIcons:{enabled:!1,outputDir:"resources/app-icons",platforms:["ios","macos"],faviconDir:"public"}},library:{name:"hello-world",owner:"@stacksjs",repository:"stacksjs/stacks",license:"MIT",author:"",contributors:[],defaultLanguage:"en",webComponents:{name:"hello-world-elements",description:"Your framework agnostic web component library description.",keywords:["custom-elements","web-components","library","framework-agnostic","typescript","javascript"],tags:[{name:["HelloWorld","AppHelloWorld"],description:"The Hello World custom element, built via this framework.",attributes:[{name:"greeting",description:"The greeting."}]}]},functions:{name:"hello-world-fx",description:"Your function library description.",keywords:["functions","composables","library","typescript","javascript"],shouldGenerateSourcemap:!1,files:["counter","dark"]}},logging:{logsPath:"storage/logs/stacks.log",deploymentsPath:"storage/logs/deployments.log"},notification:{default:"email"},payment:{driver:"stripe"},ports:{frontend:3000,backend:3001,admin:3002,library:3003,desktop:3004,email:3005,docs:3006,inspect:3007,api:3008,systemTray:3009,database:3010},queue:{default:"sync",connections:{sync:{driver:"sync"},database:{driver:"database",table:"jobs",queue:"default",retryAfter:90},redis:{driver:"redis",queue:"default",retryAfter:90},sqs:{driver:"sqs",key:"",secret:"",prefix:"",suffix:"",queue:"default",region:FRAMEWORK_DEFAULTS.awsRegion}}},saas:{plans:[{productName:"Stacks Hobby",description:"All the Stacks features.",pricing:[{key:"stacks_hobby_monthly",price:3900,interval:"month",currency:"usd"},{key:"stacks_hobby_yearly",price:37900,interval:"year",currency:"usd"}],metadata:{createdBy:"admin",version:"1.0.0"}},{productName:"Stacks Pro",description:"All the Stacks features, including being able to invite team members.",pricing:[{key:"stacks_pro_monthly",price:5900,interval:"month",currency:"usd"},{key:"stacks_pro_yearly",price:57900,interval:"year",currency:"usd"}],metadata:{createdBy:"admin",version:"1.0.0"}}],webhook:{endpoint:"/webhooks/stripe",secret:""},currencies:["usd"],coupons:[{code:"SUMMER2024",amountOff:500,duration:"once"}],products:[{name:"Stacks Pro",description:"All the Stacks features.",images:["url_to_image"]}]},searchEngine:{driver:"opensearch"},security:{firewall:{enabled:!0,countryCodes:[],ipAddresses:[],queryString:[],httpHeaders:[],rateLimitPerMinute:1000,useIpReputationLists:!0,useKnownBadInputsRuleSet:!0}},services:{aws:{accountId:"",appId:"",apiKey:"",region:FRAMEWORK_DEFAULTS.awsRegion},algolia:{appId:"",apiKey:""},meilisearch:{appId:"",apiKey:""},stripe:{appId:"",apiKey:""}},filesystems:{driver:"s3"},team:{name:"",members:{}},ui:{shortcuts:[["btn","inline-flex items-center px-4 py-2 ml-2 border border-transparent shadow-sm text-base font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 cursor-pointer"]],safelist:"prose prose-sm m-auto text-left",trigger:":stx:",classPrefix:"stx-",reset:"tailwind",icons:["hugeicons"],fonts:{email:{title:"Mona",text:"Hubot"},desktop:{title:"Mona",text:"Hubot"},mobile:{title:"Mona",text:"Hubot"},web:{title:"Mona",text:"Hubot"}}}};export default defaults;
5
+ `,confirmCommit:"Are you sure you want to proceed with the commit above?"},types:[{value:"feat",name:"feat: \u2728 A new feature",emoji:":sparkles:"},{value:"fix",name:"fix: \uD83D\uDC1B A bug fix",emoji:":bug:"},{value:"docs",name:"docs: \uD83D\uDCDD Documentation only changes",emoji:":memo:"},{value:"style",name:"style: \uD83D\uDC84 Changes that do not affect the meaning of the code",emoji:":lipstick:"},{value:"refactor",name:"refactor: \u267B\uFE0F A code change that neither fixes a bug nor adds a feature",emoji:":recycle:"},{value:"perf",name:"perf: \u26A1\uFE0F A code change that improves performance",emoji:":zap:"},{value:"test",name:"test: \u2705 Adding missing tests or adjusting existing tests",emoji:":white_check_mark:"},{value:"build",name:"build: \uD83D\uDCE6\uFE0F Changes that affect the build system or external dependencies",emoji:":package:"},{value:"ci",name:"ci: \uD83C\uDFA1 Changes to our CI configuration files and scripts",emoji:":ferris_wheel:"},{value:"chore",name:"chore: \uD83D\uDD28 Other changes that don't modify src or test files",emoji:":hammer:"},{value:"revert",name:"revert: \u23EA\uFE0F Reverts a previous commit",emoji:":rewind:"}]},hashing:{driver:"bcrypt",bcrypt:{rounds:12},argon2:{memory:65536,time:2}},images:{social:{enabled:!1,outputDir:"public/social",publicPath:"/social",presets:["og","square","portrait"]},appStore:{enabled:!1,outputDir:"resources/app-store/screenshots"},appIcons:{enabled:!1,outputDir:"resources/app-icons",platforms:["ios","macos"],faviconDir:"public"}},library:{name:"hello-world",owner:"@stacksjs",repository:"stacksjs/stacks",license:"MIT",author:"",contributors:[],defaultLanguage:"en",webComponents:{name:"hello-world-elements",description:"Your framework agnostic web component library description.",keywords:["custom-elements","web-components","library","framework-agnostic","typescript","javascript"],tags:[{name:["HelloWorld","AppHelloWorld"],description:"The Hello World custom element, built via this framework.",attributes:[{name:"greeting",description:"The greeting."}]}]},functions:{name:"hello-world-fx",description:"Your function library description.",keywords:["functions","composables","library","typescript","javascript"],shouldGenerateSourcemap:!1,files:["counter","dark"]}},logging:{logsPath:"storage/logs/stacks.log",deploymentsPath:"storage/logs/deployments.log"},notification:{default:"email"},payment:{driver:"stripe"},server:{proxy:{}},ports:{frontend:3000,backend:3001,admin:3002,library:3003,desktop:3004,email:3005,docs:3006,inspect:3007,api:3008,systemTray:3009,database:3010},queue:{default:"sync",connections:{sync:{driver:"sync"},database:{driver:"database",table:"jobs",queue:"default",retryAfter:90},redis:{driver:"redis",queue:"default",retryAfter:90},sqs:{driver:"sqs",key:"",secret:"",prefix:"",suffix:"",queue:"default",region:FRAMEWORK_DEFAULTS.awsRegion}}},saas:{plans:[{productName:"Stacks Hobby",description:"All the Stacks features.",pricing:[{key:"stacks_hobby_monthly",price:3900,interval:"month",currency:"usd"},{key:"stacks_hobby_yearly",price:37900,interval:"year",currency:"usd"}],metadata:{createdBy:"admin",version:"1.0.0"}},{productName:"Stacks Pro",description:"All the Stacks features, including being able to invite team members.",pricing:[{key:"stacks_pro_monthly",price:5900,interval:"month",currency:"usd"},{key:"stacks_pro_yearly",price:57900,interval:"year",currency:"usd"}],metadata:{createdBy:"admin",version:"1.0.0"}}],webhook:{endpoint:"/webhooks/stripe",secret:""},currencies:["usd"],coupons:[{code:"SUMMER2024",amountOff:500,duration:"once"}],products:[{name:"Stacks Pro",description:"All the Stacks features.",images:["url_to_image"]}]},searchEngine:{driver:"opensearch"},security:{firewall:{enabled:!0,countryCodes:[],ipAddresses:[],queryString:[],httpHeaders:[],rateLimitPerMinute:1000,useIpReputationLists:!0,useKnownBadInputsRuleSet:!0}},services:{aws:{accountId:"",appId:"",apiKey:"",region:FRAMEWORK_DEFAULTS.awsRegion},algolia:{appId:"",apiKey:""},meilisearch:{appId:"",apiKey:""},stripe:{appId:"",apiKey:""}},filesystems:{driver:"s3"},team:{name:"",members:{}},ui:{shortcuts:[["btn","inline-flex items-center px-4 py-2 ml-2 border border-transparent shadow-sm text-base font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 cursor-pointer"]],safelist:"prose prose-sm m-auto text-left",trigger:":stx:",classPrefix:"stx-",reset:"tailwind",icons:["hugeicons"],fonts:{email:{title:"Mona",text:"Hubot"},desktop:{title:"Mona",text:"Hubot"},mobile:{title:"Mona",text:"Hubot"},web:{title:"Mona",text:"Hubot"}}}};export default defaults;
package/dist/index.d.ts CHANGED
@@ -12,4 +12,13 @@ export * from './config';
12
12
  export { FRAMEWORK_DEFAULTS } from './defaults';
13
13
  export { validateConfig, reportConfigIssues, type ConfigValidationIssue } from './validators';
14
14
  export { feature, enableFeature, disableFeature, resetFeature, listFeatures } from './features';
15
+ export { resolveViewPatterns, type DefaultViewsSetting, type ViewPatternResolution } from './views';
16
+ export {
17
+ createRequestContext,
18
+ installRequestContext,
19
+ parseCookieHeader,
20
+ useRequestEvent,
21
+ type RequestContextSnapshot,
22
+ type StacksRequestContext,
23
+ } from './request-context';
15
24
  export * from './capabilities';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export*from"./config";export{FRAMEWORK_DEFAULTS}from"./defaults";export{validateConfig,reportConfigIssues}from"./validators";export{feature,enableFeature,disableFeature,resetFeature,listFeatures}from"./features";export*from"./capabilities";
1
+ export*from"./config";export{FRAMEWORK_DEFAULTS}from"./defaults";export{validateConfig,reportConfigIssues}from"./validators";export{feature,enableFeature,disableFeature,resetFeature,listFeatures}from"./features";export{resolveViewPatterns}from"./views";export{createRequestContext,installRequestContext,parseCookieHeader,useRequestEvent}from"./request-context";export*from"./capabilities";
package/dist/overrides.js CHANGED
@@ -1,4 +1,4 @@
1
- import{resolve}from"node:path";import{pathToFileURL}from"node:url";import{validateConfig}from"./validators";const skipConfigLoading=process.env.SKIP_CONFIG_LOADING==="true",skipConfigValidation=process.env.SKIP_CONFIG_VALIDATION==="true",OVERRIDES_KEY=Symbol.for("@stacksjs/config:overrides"),READY_KEY=Symbol.for("@stacksjs/config:overridesReady");function defaultsForOverrides(){return{ai:{},analytics:{},app:{name:process.env.APP_NAME||"Stacks",env:process.env.APP_ENV||"production"},auth:{},cache:{},cli:{},cloud:{},cms:{},commerce:{},dashboard:{},database:{},dns:{},realtime:{},email:{},errors:{},featureFlags:{},git:{},hashing:{},images:{},library:{},logging:{},marketing:{},monitoring:{},notification:{},queue:{},payment:{},ports:{},saas:{},searchEngine:{},security:{},services:{},filesystems:{},team:{},ui:{}}}const globalScope=globalThis,sharedOverrides=globalScope[OVERRIDES_KEY];export const overrides=sharedOverrides??(()=>{const created=defaultsForOverrides();globalScope[OVERRIDES_KEY]=created;return created})();const userConfigs=[["ai","ai"],["analytics","analytics"],["app","app"],["auth","auth"],["cache","cache"],["cli","cli"],["cloud","cloud"],["cms","cms"],["commerce","commerce"],["dashboard","dashboard"],["database","database"],["dns","dns"],["docs","docs"],["email","email"],["errors","errors"],["featureFlags","feature-flags"],["git","git"],["hashing","hashing"],["images","images"],["library","library"],["logging","logging"],["marketing","marketing"],["monitoring","monitoring"],["notification","notification"],["payment","payment"],["ports","ports"],["queue","queue"],["realtime","realtime"],["saas","saas"],["searchEngine","search-engine"],["security","security"],["services","services"],["filesystems","filesystems"],["team","team"],["ui","ui"]];export function userConfigUrl(name,cwd=process.cwd()){return pathToFileURL(resolve(cwd,"config",`${name}.ts`)).href}const sharedReady=globalScope[READY_KEY];export const overridesReady=sharedReady??(()=>{const promise=skipConfigLoading?Promise.resolve(overrides):Promise.all(userConfigs.map(async([key,name])=>{const modulePath=userConfigUrl(name);try{const mod=await import(modulePath);if(mod?.default!==void 0)overrides[key]=mod.default}catch(err){const code=err?.code,msg=err?.message??String(err);if(!(code==="ERR_MODULE_NOT_FOUND"||code==="MODULE_NOT_FOUND"||/Cannot find module/i.test(msg)))console.warn(`[config] Failed to load ${String(key)} config from ${modulePath}: ${msg}`)}})).then(()=>{if(!skipConfigValidation){const issues=validateConfig(overrides);if(issues.length>0){console.error("[config] Configuration issues detected:");for(const issue of issues)console.error(` \u2022 ${issue.path}: ${issue.message}`);const summary=issues.map((i)=>` \u2022 ${i.path}: ${i.message}`).join(`
1
+ import{resolve}from"node:path";import{pathToFileURL}from"node:url";import{defaults}from"./defaults";import{validateConfig}from"./validators";const skipConfigLoading=process.env.SKIP_CONFIG_LOADING==="true",skipConfigValidation=process.env.SKIP_CONFIG_VALIDATION==="true",OVERRIDES_KEY=Symbol.for("@stacksjs/config:overrides"),READY_KEY=Symbol.for("@stacksjs/config:overridesReady");function defaultsForOverrides(){return{ai:{},analytics:{},app:{...defaults.app,name:process.env.APP_NAME||defaults.app?.name||"Stacks",env:process.env.APP_ENV||"production"},auth:{},cache:{},cli:{},cloud:{},cms:{},commerce:{},dashboard:{},database:{},dns:{},realtime:{},email:{},errors:{},featureFlags:{},git:{},hashing:{},images:{},library:{},logging:{},marketing:{},monitoring:{},notification:{},queue:{},payment:{},ports:{},saas:{},searchEngine:{},security:{},server:{},services:{},filesystems:{},team:{},ui:{}}}const globalScope=globalThis,sharedOverrides=globalScope[OVERRIDES_KEY];export const overrides=sharedOverrides??(()=>{const created=defaultsForOverrides();globalScope[OVERRIDES_KEY]=created;return created})();const userConfigs=[["ai","ai"],["analytics","analytics"],["app","app"],["auth","auth"],["cache","cache"],["cli","cli"],["cloud","cloud"],["cms","cms"],["commerce","commerce"],["dashboard","dashboard"],["database","database"],["dns","dns"],["docs","docs"],["email","email"],["errors","errors"],["featureFlags","feature-flags"],["git","git"],["hashing","hashing"],["images","images"],["library","library"],["logging","logging"],["marketing","marketing"],["monitoring","monitoring"],["notification","notification"],["payment","payment"],["ports","ports"],["queue","queue"],["realtime","realtime"],["saas","saas"],["searchEngine","search-engine"],["security","security"],["server","server"],["services","services"],["filesystems","filesystems"],["team","team"],["ui","ui"]];export function userConfigUrl(name,cwd=process.cwd()){return pathToFileURL(resolve(cwd,"config",`${name}.ts`)).href}const sharedReady=globalScope[READY_KEY];export const overridesReady=sharedReady??(()=>{const promise=skipConfigLoading?Promise.resolve(overrides):Promise.all(userConfigs.map(async([key,name])=>{const modulePath=userConfigUrl(name);try{const mod=await import(modulePath);if(mod?.default!==void 0)overrides[key]=mod.default}catch(err){const code=err?.code,msg=err?.message??String(err);if(!(code==="ERR_MODULE_NOT_FOUND"||code==="MODULE_NOT_FOUND"||/Cannot find module/i.test(msg)))console.warn(`[config] Failed to load ${String(key)} config from ${modulePath}: ${msg}`)}})).then(()=>{if(!skipConfigValidation){const issues=validateConfig(overrides);if(issues.length>0){console.error("[config] Configuration issues detected:");for(const issue of issues)console.error(` \u2022 ${issue.path}: ${issue.message}`);const summary=issues.map((i)=>` \u2022 ${i.path}: ${i.message}`).join(`
2
2
  `);throw Error(`[config] ${issues.length} configuration issue(s) detected at boot:
3
3
  ${summary}
4
4
  Set SKIP_CONFIG_VALIDATION=true to bypass (e.g. when running migrations against partial config).`)}}return overrides});globalScope[READY_KEY]=promise;return promise})();export default overrides;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Parse a `Cookie` header into a record.
3
+ *
4
+ * Was copy-pasted into both servers; identical in both, which is the mild case
5
+ * of the same problem this module exists to fix.
6
+ */
7
+ export declare function parseCookieHeader(header: string | null | undefined): Record<string, string>;
8
+ /**
9
+ * Build the object both servers publish as `globalThis.requestContext`.
10
+ *
11
+ * `read` is called per access rather than captured, because the snapshot is
12
+ * replaced between requests — capturing it would pin the first request's
13
+ * cookies onto every later one.
14
+ */
15
+ export declare function createRequestContext(read: () => RequestContextSnapshot | undefined): StacksRequestContext;
16
+ /**
17
+ * Install the context as the `requestContext` global and return it.
18
+ *
19
+ * Both servers call exactly this, so neither can publish a differently-shaped
20
+ * object by accident.
21
+ */
22
+ export declare function installRequestContext(read: () => RequestContextSnapshot | undefined): StacksRequestContext;
23
+ /**
24
+ * The single accessor (#2232 ask 4), for callers who would rather have one
25
+ * object than reach for ambient globals.
26
+ *
27
+ * Always returns something: with no request in flight every field is its empty
28
+ * value, so a standalone or SSG render reads `useRequestEvent().query.site` and
29
+ * gets `undefined` instead of a ReferenceError.
30
+ */
31
+ export declare function useRequestEvent(): {
32
+ url: string
33
+ path: string
34
+ search: string
35
+ query: Record<string, string>
36
+ cookies: Record<string, string>
37
+ params: Record<string, string>
38
+ locale: string
39
+ ip: string
40
+ host: string
41
+ };
42
+ /**
43
+ * One request object for `<script server>` blocks (stacksjs/stacks#2232).
44
+ *
45
+ * `requestContext` was installed twice — once by the dev views server, once by
46
+ * the production server — with two different backings, two different sets of
47
+ * methods, and no shared type. Both installers were `(globalThis as any)`, so
48
+ * nothing could catch a divergence. Two already shipped:
49
+ *
50
+ * - production's `url()` returned only the query string, so a page doing
51
+ * `new URL(requestContext.url())` worked in dev and threw on the box
52
+ * - production had no `locale()` at all, so a page that branched on locale
53
+ * threw "requestContext.locale is not a function" on the box
54
+ *
55
+ * Both were found by an end-to-end test, not by inspection, because there was
56
+ * nothing to inspect against.
57
+ *
58
+ * A shared TYPE would only have made those detectable. A shared FACTORY makes
59
+ * them impossible: each server supplies a snapshot reader and gets the same
60
+ * object built the same way. The only thing a server still chooses is where
61
+ * the snapshot comes from, which is the one thing that genuinely differs (dev
62
+ * has AsyncLocalStorage available; production established it does not survive
63
+ * into stx-serve's render).
64
+ *
65
+ * Home of convenience: `@stacksjs/config` is the only package both the dev
66
+ * server (`@stacksjs/actions`) and the production server (`@stacksjs/buddy`)
67
+ * already depend on. It is not conceptually config, and moving it later is a
68
+ * re-export away.
69
+ */
70
+ /**
71
+ * What a server knows about the request in flight.
72
+ *
73
+ * Every field optional: a snapshot is assembled by whichever server booted, an
74
+ * older stx may not populate all of them, and a standalone or SSG render has no
75
+ * request at all. Readers below supply a shaped empty value rather than
76
+ * throwing, so a page never needs `typeof requestContext !== 'undefined'`.
77
+ */
78
+ export declare interface RequestContextSnapshot {
79
+ cookies?: Record<string, string>
80
+ url?: string
81
+ path?: string
82
+ search?: string
83
+ locale?: string | null
84
+ params?: Record<string, string>
85
+ ip?: string
86
+ host?: string
87
+ }
88
+ /** What a `<script server>` block sees as `requestContext`. */
89
+ export declare interface StacksRequestContext {
90
+ cookie: (name: string) => string | null
91
+ cookies: () => Record<string, string>
92
+ url: () => string
93
+ path: () => string
94
+ search: () => string
95
+ query: () => Record<string, string>
96
+ params: () => Record<string, string>
97
+ locale: () => string
98
+ ip: () => string
99
+ host: () => string
100
+ }
@@ -0,0 +1 @@
1
+ export function parseCookieHeader(header){const out={};if(!header)return out;for(const part of header.split(";")){const trimmed=part.trim(),eq=trimmed.indexOf("=");if(eq===-1)continue;const key=trimmed.slice(0,eq).trim();if(!key)continue;const value=trimmed.slice(eq+1).trim();try{out[key]=decodeURIComponent(value)}catch{out[key]=value}}return out}export function createRequestContext(read){const snapshot=()=>read()??{},searchOf=()=>{const direct=snapshot().search;if(direct)return direct;const url=snapshot().url??"",mark=url.indexOf("?");return mark===-1?"":url.slice(mark)};return{cookie:(name)=>snapshot().cookies?.[name]??null,cookies:()=>snapshot().cookies??{},url:()=>snapshot().url??"",path:()=>{const direct=snapshot().path;if(direct)return direct;const url=snapshot().url??"";if(!url)return"";try{return new URL(url).pathname}catch{const mark=url.indexOf("?");return mark===-1?url:url.slice(0,mark)}},search:searchOf,query:()=>{const out={},search=searchOf();if(!search)return out;new URLSearchParams(search.startsWith("?")?search.slice(1):search).forEach((value,key)=>{out[key]=value});return out},params:()=>snapshot().params??{},locale:()=>snapshot().locale??"en",ip:()=>snapshot().ip??"",host:()=>snapshot().host??""}}export function installRequestContext(read){const context=createRequestContext(read);globalThis.requestContext=context;return context}export function useRequestEvent(){const context=globalThis.requestContext??createRequestContext(()=>{return});return{url:context.url(),path:context.path(),search:context.search(),query:context.query(),cookies:context.cookies(),params:context.params(),locale:context.locale(),ip:context.ip(),host:context.host()}}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Compose the view patterns for the dev and production servers
3
+ * (stacksjs/stacks#2237).
4
+ *
5
+ * Both servers registered `[userViewsPath, defaultViewsPath]` unconditionally,
6
+ * so every Stacks app served the scaffold's demo storefront as live public
7
+ * routes — `/cart`, `/checkout/payment`, `/orders/:id` — and enumerated them
8
+ * into its sitemap. An analytics SaaS has no business answering `/checkout`.
9
+ *
10
+ * The route registry already lets an app decide what to spread; this is the
11
+ * same lever for views.
12
+ *
13
+ * Shared by both callers on purpose. They are in different packages and have
14
+ * drifted before — `requestContext` is installed twice, differently, which is
15
+ * its own report (#2232) — and a views policy that dev and production disagree
16
+ * about is a defect you only find in production.
17
+ *
18
+ * `exists` is injectable so the resolution is testable without a fixture tree;
19
+ * it defaults to the real filesystem.
20
+ */
21
+ export declare function resolveViewPatterns(userViewsPath: string, defaultViewsPath: string, setting: DefaultViewsSetting | undefined, exists?: (path: string) => boolean): ViewPatternResolution;
22
+ export declare interface ViewPatternResolution {
23
+ patterns: string[]
24
+ missing: string[]
25
+ }
26
+ /**
27
+ * Whether an app serves the framework's default views, and which of them.
28
+ *
29
+ * `true` (the default) keeps every default view registered, which is the
30
+ * behaviour every existing app already has. `false` registers the app's own
31
+ * views only. An array registers just the named subtrees of the defaults
32
+ * directory — `['errors', 'emails']` for an app that wants the error pages and
33
+ * the mail previews but not the demo storefront.
34
+ */
35
+ export type DefaultViewsSetting = boolean | string[];
package/dist/views.js ADDED
@@ -0,0 +1 @@
1
+ import{existsSync}from"node:fs";import{join}from"node:path";export function resolveViewPatterns(userViewsPath,defaultViewsPath,setting,exists=existsSync){if(setting===void 0||setting===!0)return{patterns:[userViewsPath,defaultViewsPath],missing:[]};if(setting===!1)return{patterns:[userViewsPath],missing:[]};if(!Array.isArray(setting))return{patterns:[userViewsPath,defaultViewsPath],missing:[]};const patterns=[userViewsPath],missing=[];for(const name of setting){const cleaned=String(name).replace(/^[/\\]+/,"");if(!cleaned||cleaned.split(/[/\\]/).includes(".."))continue;const candidate=join(defaultViewsPath,cleaned);if(exists(candidate))patterns.push(candidate);else missing.push(cleaned)}return{patterns,missing}}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/config",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.293",
5
+ "version": "0.70.296",
6
6
  "description": "The Stacks config helper methods.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -58,8 +58,8 @@
58
58
  "ts-pantry": "^0.11.0"
59
59
  },
60
60
  "devDependencies": {
61
- "@stacksjs/alias": "0.70.293",
61
+ "@stacksjs/alias": "0.70.296",
62
62
  "better-dx": "^0.2.17",
63
- "@stacksjs/types": "0.70.293"
63
+ "@stacksjs/types": "0.70.296"
64
64
  }
65
65
  }