@stacksjs/server 0.70.258 → 0.70.260

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.
@@ -1,16 +1 @@
1
- export const config = {
2
- app: {
3
- name: process.env.APP_NAME || "Stacks",
4
- env: process.env.APP_ENV || "production",
5
- debug: process.env.APP_DEBUG === "true" || !1,
6
- url: process.env.APP_URL || "https://stacksjs.com"
7
- },
8
- server: {
9
- port: Number(process.env.PORT) || 3000,
10
- host: "0.0.0.0"
11
- },
12
- logging: {
13
- level: process.env.LOG_LEVEL || "info"
14
- }
15
- };
16
- export default config;
1
+ export const config={app:{name:process.env.APP_NAME||"Stacks",env:process.env.APP_ENV||"production",debug:process.env.APP_DEBUG==="true"||!1,url:process.env.APP_URL||"https://stacksjs.com"},server:{port:Number(process.env.PORT)||3000,host:"0.0.0.0"},logging:{level:process.env.LOG_LEVEL||"info"}};export default config;
package/dist/config.js CHANGED
@@ -1,60 +1 @@
1
- import { ports } from "@stacksjs/config";
2
- export function config(options) {
3
- const serversMap = {
4
- frontend: {
5
- host: "localhost",
6
- port: ports.frontend
7
- },
8
- backend: {
9
- host: "localhost",
10
- port: ports.backend
11
- },
12
- api: {
13
- host: "localhost",
14
- port: ports.api
15
- },
16
- admin: {
17
- host: "localhost",
18
- port: ports.admin
19
- },
20
- library: {
21
- host: "localhost",
22
- port: ports.library
23
- },
24
- desktop: {
25
- host: "localhost",
26
- port: ports.desktop
27
- },
28
- docs: {
29
- host: "localhost",
30
- port: ports.docs
31
- },
32
- email: {
33
- host: "localhost",
34
- port: ports.email
35
- },
36
- inspect: {
37
- host: "localhost",
38
- port: ports.inspect
39
- },
40
- "system-tray": {
41
- host: "localhost",
42
- port: ports.systemTray
43
- },
44
- database: {
45
- host: "localhost",
46
- port: ports.database
47
- }
48
- };
49
- if (options.type && options.type in serversMap)
50
- return {
51
- host: serversMap[options.type].host,
52
- port: serversMap[options.type].port,
53
- open: !1
54
- };
55
- return {
56
- host: options.host || "stacks.localhost",
57
- port: options.port || 3000,
58
- open: !1
59
- };
60
- }
1
+ import{ports}from"@stacksjs/config";export function config(options){const serversMap={frontend:{host:"localhost",port:ports.frontend},backend:{host:"localhost",port:ports.backend},api:{host:"localhost",port:ports.api},admin:{host:"localhost",port:ports.admin},library:{host:"localhost",port:ports.library},desktop:{host:"localhost",port:ports.desktop},docs:{host:"localhost",port:ports.docs},email:{host:"localhost",port:ports.email},inspect:{host:"localhost",port:ports.inspect},"system-tray":{host:"localhost",port:ports.systemTray},database:{host:"localhost",port:ports.database}};if(options.type&&options.type in serversMap)return{host:serversMap[options.type].host,port:serversMap[options.type].port,open:!1};return{host:options.host||"stacks.localhost",port:options.port||3000,open:!1}}
@@ -1,38 +1 @@
1
- import { log } from "@stacksjs/logging";
2
- import { response } from "@stacksjs/router";
3
-
4
- export class Controller {
5
- json(data, status = 200) {
6
- return response.json(data, status);
7
- }
8
- success(data) {
9
- return this.json(data, 200);
10
- }
11
- created(data) {
12
- return this.json(data, 201);
13
- }
14
- noContent() {
15
- return response.noContent();
16
- }
17
- error(message, status = 500) {
18
- return this.json({ error: message }, status);
19
- }
20
- notFound(message = "Resource not found") {
21
- return this.error(message, 404);
22
- }
23
- unauthorized(message = "Unauthorized") {
24
- return this.error(message, 401);
25
- }
26
- forbidden(message = "Forbidden") {
27
- return this.error(message, 403);
28
- }
29
- validate(request, rules) {
30
- try {
31
- const result = request.validate(rules);
32
- log.info("Validation result:", result);
33
- return Promise.resolve();
34
- } catch (error) {
35
- return Promise.reject(error);
36
- }
37
- }
38
- }
1
+ import{log}from"@stacksjs/logging";import{response}from"@stacksjs/router";export class Controller{json(data,status=200){return response.json(data,status)}success(data){return this.json(data,200)}created(data){return this.json(data,201)}noContent(){return response.noContent()}error(message,status=500){return this.json({error:message},status)}notFound(message="Resource not found"){return this.error(message,404)}unauthorized(message="Unauthorized"){return this.error(message,401)}forbidden(message="Forbidden"){return this.error(message,403)}validate(request,rules){try{const result=request.validate(rules);log.info("Validation result:",result);return Promise.resolve()}catch(error){return Promise.reject(error)}}}
package/dist/imports.d.ts CHANGED
@@ -1,3 +1,22 @@
1
+ /**
2
+ * Has anything the manifest is built from changed since it was written?
3
+ *
4
+ * The manifest used to be regenerated only when it was missing, so once
5
+ * written it never refreshed. Files moved, were renamed, or were deleted
6
+ * underneath it and the stale entries survived: a project on a
7
+ * months-old manifest carried exports pointing at paths that no longer
8
+ * existed, plus duplicates when a file was moved into a subdirectory of
9
+ * the same name (`functions/commerce/products.ts` becoming
10
+ * `functions/commerce/products/products.ts` produced two `useProducts`
11
+ * exports and the `Cannot export a duplicate name` warning on every boot).
12
+ *
13
+ * Regenerating unconditionally is not the alternative: a watcher on the
14
+ * auto-imports directory sees the write, restarts, writes again, and the
15
+ * dev server loops. Comparing mtimes only writes when something actually
16
+ * moved, and the manifest is the newest file afterwards, so the next boot
17
+ * is a no-op and the loop cannot start.
18
+ */
19
+ export declare function autoImportsAreStale(): boolean;
1
20
  /**
2
21
  * Generate runtime auto-import files for Bun runtime execution.
3
22
  * This creates index files that can be imported to get all auto-imports,
package/dist/imports.js CHANGED
@@ -1,235 +1,9 @@
1
- import { existsSync } from "node:fs";
2
- import { dirname, relative } from "node:path";
3
- import { plugin } from "bun";
4
- import { log } from "@stacksjs/logging";
5
- import { path } from "@stacksjs/path";
6
- import { autoImports, generateRuntimeIndex, generateGlobalsScript } from "bun-plugin-auto-imports";
7
- import { globSync } from "@stacksjs/storage";
8
- import { primitiveAutoImportEntries, primitiveModules } from "./primitive-imports";
9
- const OPTIONAL_MODEL_MODULES = {
10
- commerce: ["config/commerce.ts"],
11
- Content: ["config/cms.ts", "config/blog.ts"],
12
- realtime: ["config/realtime.ts"]
13
- };
14
- function configEnabled(configRelPaths) {
15
- return configRelPaths.some((rel) => existsSync(path.projectPath(rel)));
16
- }
17
- function resolveDefaultModelDirs() {
18
- const root = path.storagePath("framework/defaults/app/Models"), dirs = [root];
19
- for (const [subdir, configPaths] of Object.entries(OPTIONAL_MODEL_MODULES))
20
- if (configEnabled(configPaths))
21
- dirs.push(`${root}/${subdir}`);
22
- return dirs;
23
- }
24
- function scanDirTopLevel(dir) {
25
- try {
26
- return globSync(`${dir}/*.ts`, { ignore: ["**/*.d.ts", "**/index.ts", "**/README*"] });
27
- } catch {
28
- return [];
29
- }
30
- }
31
- function scanDefineModelExports(dir, opts = {}) {
32
- const { recursive = !0 } = opts;
33
- let files = [];
34
- try {
35
- const pattern = recursive ? `${dir}/**/*.ts` : `${dir}/*.ts`;
36
- files = globSync(pattern, { ignore: ["**/*.d.ts", "**/index.ts", "**/README*"] });
37
- } catch {
38
- return [];
39
- }
40
- const exports = [], seen = new Set;
41
- for (const file of files) {
42
- const basename = file.split("/").pop()?.replace(".ts", "") || "";
43
- if (basename && !seen.has(basename)) {
44
- seen.add(basename);
45
- exports.push({ name: basename, file, isDefault: !0 });
46
- }
47
- }
48
- return exports;
49
- }
50
- const GLOBAL_SHADOW_BLOCKLIST = new Set([
51
- "Error",
52
- "Request",
53
- "Response",
54
- "URL",
55
- "Map",
56
- "Set",
57
- "Object",
58
- "Array",
59
- "Number",
60
- "String",
61
- "Date",
62
- "Promise",
63
- "Symbol"
64
- ]);
65
- async function generateDefineModelIndex(entries, outputPath) {
66
- const lines = ["// Generated by bun-plugin-auto-imports"], seen = new Set;
67
- for (const entry of entries) {
68
- const dir = typeof entry === "string" ? entry : entry.dir, recursive = typeof entry === "string" ? !0 : entry.recursive;
69
- let files = [];
70
- try {
71
- const pattern = recursive ? `${dir}/**/*.ts` : `${dir}/*.ts`;
72
- files = globSync(pattern, { ignore: ["**/*.d.ts", "**/index.ts", "**/README*"] });
73
- } catch {
74
- continue;
75
- }
76
- for (const file of files) {
77
- const basename = file.split("/").pop()?.replace(".ts", "") || "";
78
- if (!basename || seen.has(basename))
79
- continue;
80
- seen.add(basename);
81
- const relativePath = relative(dirname(outputPath), file).replace(/\.ts$/, "");
82
- if (GLOBAL_SHADOW_BLOCKLIST.has(basename)) {
83
- lines.push(`// Skipped '${basename}' \u2014 would shadow a built-in global. Import directly if needed.`);
84
- lines.push(`// export { default as ${basename} } from '${relativePath}'`);
85
- continue;
86
- }
87
- lines.push(`export { default as ${basename} } from '${relativePath}'`);
88
- }
89
- }
90
- await Bun.write(outputPath, lines.join(`
91
- `) + `
92
- `);
93
- }
94
- export async function generateAutoImportFiles() {
95
- await generateServerAutoImportTypes();
96
- const userFunctionsPath = path.resourcesPath("functions"), defaultFunctionsPath = path.storagePath("framework/defaults/functions"), functionsPath = userFunctionsPath, outputDir = path.storagePath("framework/auto-imports"), userModelsPath = path.userModelsPath(), defaultModelDirs = resolveDefaultModelDirs(), [defaultsRoot = path.storagePath("framework/defaults/app/Models"), ...enabledSubdirs] = defaultModelDirs, userJobsPath = path.userJobsPath(), userControllersPath = path.userControllersPath(), defaultControllersPath = path.storagePath("framework/defaults/app/Controllers");
97
- await Bun.write(`${outputDir}/.gitkeep`, "");
98
- const functionsIndexPath = `${outputDir}/functions.ts`;
99
- await generateRuntimeIndex([userFunctionsPath, defaultFunctionsPath], functionsIndexPath);
100
- const modelsIndexPath = `${outputDir}/models.ts`, modelScan = [
101
- userModelsPath,
102
- { dir: defaultsRoot, recursive: !1 },
103
- ...defaultModelDirs.slice(1).map((d) => ({ dir: d, recursive: !0 }))
104
- ];
105
- await generateDefineModelIndex(modelScan, modelsIndexPath);
106
- const jobsIndexPath = `${outputDir}/jobs.ts`;
107
- await generateDefineModelIndex([userJobsPath], jobsIndexPath);
108
- const controllersIndexPath = `${outputDir}/controllers.ts`;
109
- await generateDefineModelIndex([userControllersPath, defaultControllersPath], controllersIndexPath);
110
- const combinedContent = `// Generated by bun-plugin-auto-imports
1
+ import{existsSync,statSync}from"node:fs";import{dirname,relative}from"node:path";import{plugin}from"bun";import{log}from"@stacksjs/logging";import{path}from"@stacksjs/path";import{autoImports,generateRuntimeIndex,generateGlobalsScript}from"bun-plugin-auto-imports";import{globSync}from"@stacksjs/storage";import{primitiveAutoImportEntries,primitiveModules}from"./primitive-imports";const OPTIONAL_MODEL_MODULES={commerce:["config/commerce.ts"],Content:["config/cms.ts","config/blog.ts"],realtime:["config/realtime.ts"]};function configEnabled(configRelPaths){return configRelPaths.some((rel)=>existsSync(path.projectPath(rel)))}function resolveDefaultModelDirs(){const root=path.storagePath("framework/defaults/app/Models"),dirs=[root];for(const[subdir,configPaths]of Object.entries(OPTIONAL_MODEL_MODULES))if(configEnabled(configPaths))dirs.push(`${root}/${subdir}`);return dirs}function scanDirTopLevel(dir){try{return globSync(`${dir}/*.ts`,{ignore:["**/*.d.ts","**/index.ts","**/README*"]})}catch{return[]}}function scanDefineModelExports(dir,opts={}){const{recursive=!0}=opts;let files=[];try{const pattern=recursive?`${dir}/**/*.ts`:`${dir}/*.ts`;files=globSync(pattern,{ignore:["**/*.d.ts","**/index.ts","**/README*"]})}catch{return[]}const exports=[],seen=new Set;for(const file of files){const basename=file.split("/").pop()?.replace(".ts","")||"";if(basename&&!seen.has(basename)){seen.add(basename);exports.push({name:basename,file,isDefault:!0})}}return exports}const GLOBAL_SHADOW_BLOCKLIST=new Set(["Error","Request","Response","URL","Map","Set","Object","Array","Number","String","Date","Promise","Symbol"]);async function generateDefineModelIndex(entries,outputPath){const lines=["// Generated by bun-plugin-auto-imports"],seen=new Set;for(const entry of entries){const dir=typeof entry==="string"?entry:entry.dir,recursive=typeof entry==="string"?!0:entry.recursive;let files=[];try{const pattern=recursive?`${dir}/**/*.ts`:`${dir}/*.ts`;files=globSync(pattern,{ignore:["**/*.d.ts","**/index.ts","**/README*"]})}catch{continue}for(const file of files){const basename=file.split("/").pop()?.replace(".ts","")||"";if(!basename||seen.has(basename))continue;seen.add(basename);const relativePath=relative(dirname(outputPath),file).replace(/\.ts$/,"");if(GLOBAL_SHADOW_BLOCKLIST.has(basename)){lines.push(`// Skipped '${basename}' \u2014 would shadow a built-in global. Import directly if needed.`);lines.push(`// export { default as ${basename} } from '${relativePath}'`);continue}lines.push(`export { default as ${basename} } from '${relativePath}'`)}}await Bun.write(outputPath,lines.join(`
2
+ `)+`
3
+ `)}function autoImportSourceDirs(){return[path.resourcesPath("functions"),path.storagePath("framework/defaults/functions"),path.userModelsPath(),...resolveDefaultModelDirs(),path.userJobsPath(),path.userControllersPath(),path.storagePath("framework/defaults/app/Controllers")]}export function autoImportsAreStale(){const manifest=path.storagePath("framework/auto-imports/functions.ts");if(!existsSync(manifest))return!0;let manifestTime;try{manifestTime=statSync(manifest).mtimeMs}catch{return!0}for(const dir of autoImportSourceDirs()){if(!existsSync(dir))continue;try{if(statSync(dir).mtimeMs>manifestTime)return!0;for(const file of globSync(`${dir}/**/*.ts`,{ignore:["**/*.d.ts"]}))if(statSync(file).mtimeMs>manifestTime)return!0}catch{continue}}return!1}export async function generateAutoImportFiles(){await generateServerAutoImportTypes();const userFunctionsPath=path.resourcesPath("functions"),defaultFunctionsPath=path.storagePath("framework/defaults/functions"),functionsPath=userFunctionsPath,outputDir=path.storagePath("framework/auto-imports"),userModelsPath=path.userModelsPath(),defaultModelDirs=resolveDefaultModelDirs(),[defaultsRoot=path.storagePath("framework/defaults/app/Models"),...enabledSubdirs]=defaultModelDirs,userJobsPath=path.userJobsPath(),userControllersPath=path.userControllersPath(),defaultControllersPath=path.storagePath("framework/defaults/app/Controllers");await Bun.write(`${outputDir}/.gitkeep`,"");const functionsIndexPath=`${outputDir}/functions.ts`;await generateRuntimeIndex([userFunctionsPath,defaultFunctionsPath],functionsIndexPath);const modelsIndexPath=`${outputDir}/models.ts`,modelScan=[userModelsPath,{dir:defaultsRoot,recursive:!1},...defaultModelDirs.slice(1).map((d)=>({dir:d,recursive:!0}))];await generateDefineModelIndex(modelScan,modelsIndexPath);const jobsIndexPath=`${outputDir}/jobs.ts`;await generateDefineModelIndex([userJobsPath],jobsIndexPath);const controllersIndexPath=`${outputDir}/controllers.ts`;await generateDefineModelIndex([userControllersPath,defaultControllersPath],controllersIndexPath);const combinedContent=`// Generated by bun-plugin-auto-imports
111
4
  export * from './functions'
112
5
  export * from './models'
113
6
  export * from './jobs'
114
7
  export * from './controllers'
115
- `;
116
- await Bun.write(`${outputDir}/index.ts`, combinedContent);
117
- const globalsPath = `${outputDir}/globals.ts`;
118
- await generateGlobalsScript([functionsPath], globalsPath, `${outputDir}/index.ts`);
119
- log.debug("Auto-import files generated successfully");
120
- }
121
- export function initiateImports() {
122
- const functionsPath = path.resourcesPath("functions"), defaultFunctionsPath = path.storagePath("framework/defaults/functions"), userModelsPath = path.userModelsPath(), defaultModelDirs = resolveDefaultModelDirs(), [defaultsRoot = path.storagePath("framework/defaults/app/Models"), ...enabledSubdirs] = defaultModelDirs, userJobsPath = path.userJobsPath(), userControllersPath = path.userControllersPath(), defaultControllersPath = path.storagePath("framework/defaults/app/Controllers"), defineModelExports = [
123
- ...scanDefineModelExports(userModelsPath),
124
- ...scanDefineModelExports(defaultsRoot, { recursive: !1 }),
125
- ...enabledSubdirs.flatMap((d) => scanDefineModelExports(d))
126
- ], jobExports = scanDefineModelExports(userJobsPath), seen = new Set, uniqueDefineModelExports = defineModelExports.filter((exp) => {
127
- if (seen.has(exp.name))
128
- return !1;
129
- seen.add(exp.name);
130
- return !0;
131
- }), dtsDir = dirname(path.storagePath("framework/types/server-auto-imports.d.ts")), defineModelImports = uniqueDefineModelExports.map((exp) => ({
132
- from: `./${relative(dtsDir, exp.file).replace(/\\/g, "/").replace(/\.ts$/, "")}`,
133
- name: "default",
134
- as: exp.name
135
- })), jobImports = jobExports.map((exp) => ({
136
- from: `./${relative(dtsDir, exp.file).replace(/\\/g, "/").replace(/\.ts$/, "")}`,
137
- name: "default",
138
- as: exp.name
139
- })), controllerExports = [
140
- ...scanDefineModelExports(userControllersPath),
141
- ...scanDefineModelExports(defaultControllersPath)
142
- ], seenControllers = new Set, controllerImports = controllerExports.filter((exp) => {
143
- if (seenControllers.has(exp.name))
144
- return !1;
145
- seenControllers.add(exp.name);
146
- return !0;
147
- }).map((exp) => ({
148
- from: `./${relative(dtsDir, exp.file).replace(/\\/g, "/").replace(/\.ts$/, "")}`,
149
- name: "default",
150
- as: exp.name
151
- })), options = {
152
- dts: path.storagePath("framework/types/server-auto-imports.d.ts"),
153
- imports: [
154
- ...primitiveAutoImportEntries(),
155
- ...defineModelImports,
156
- ...jobImports,
157
- ...controllerImports
158
- ],
159
- dirs: [functionsPath, defaultFunctionsPath],
160
- eslint: {
161
- enabled: !0,
162
- filepath: path.storagePath("framework/server-auto-imports.json")
163
- }
164
- };
165
- plugin(autoImports(options));
166
- generateAutoImportFiles().catch((err) => {
167
- console.error("[Server] Failed to generate auto-import files:", err);
168
- });
169
- }
170
- export async function generateServerAutoImportTypes() {
171
- const userModelsPath = path.userModelsPath(), defaultModelDirs = resolveDefaultModelDirs(), [defaultsRoot = path.storagePath("framework/defaults/app/Models"), ...enabledSubdirs] = defaultModelDirs, modelExports = [
172
- ...scanDefineModelExports(userModelsPath),
173
- ...scanDefineModelExports(defaultsRoot, { recursive: !1 }),
174
- ...enabledSubdirs.flatMap((dir) => scanDefineModelExports(dir))
175
- ], jobExports = scanDefineModelExports(path.userJobsPath()), controllerExports = [
176
- ...scanDefineModelExports(path.userControllersPath()),
177
- ...scanDefineModelExports(path.storagePath("framework/defaults/app/Controllers"))
178
- ], seen = new Set, valueExports = [...modelExports, ...jobExports, ...controllerExports].filter((exp) => !GLOBAL_SHADOW_BLOCKLIST.has(exp.name)).filter((exp) => {
179
- if (seen.has(exp.name))
180
- return !1;
181
- seen.add(exp.name);
182
- return !0;
183
- }), outputPath = path.storagePath("framework/types/server-auto-imports.d.ts"), outputDir = dirname(outputPath), declaredValues = new Set(valueExports.map((exp) => exp.name)), lines = [
184
- "// Generated by Stacks server auto-imports",
185
- "// This file is regenerated automatically when the API starts.",
186
- "export {}",
187
- "declare global {"
188
- ];
189
- for (const { from, name, as } of primitiveAutoImportEntries())
190
- if (!declaredValues.has(as))
191
- lines.push(` const ${as}: typeof import('${from}')['${name}']`);
192
- for (const exp of valueExports) {
193
- const importPath = relative(outputDir, exp.file).replace(/\\/g, "/").replace(/\.ts$/, ""), relativePath = importPath.startsWith(".") ? importPath : `./${importPath}`;
194
- lines.push(` const ${exp.name}: typeof import('${relativePath}')['default']`);
195
- }
196
- lines.push("}", "");
197
- await Bun.write(outputPath, lines.join(`
198
- `));
199
- }
200
- export async function injectGlobalAutoImports() {
201
- if (globalThis.__stacksAutoImportsInjected)
202
- return;
203
- globalThis.__stacksAutoImportsInjected = !0;
204
- const errors = [], importWithTimeout = async (pkg) => {
205
- return Promise.race([
206
- import(pkg),
207
- new Promise((_, reject) => setTimeout(() => reject(Error(`auto-import timed out: ${pkg}`)), 4000))
208
- ]);
209
- };
210
- await Promise.all(primitiveModules.map(async ([pkg, names]) => {
211
- try {
212
- const mod = await importWithTimeout(pkg);
213
- for (const name of names)
214
- if (mod[name] !== void 0)
215
- globalThis[name] = mod[name];
216
- } catch (err) {
217
- errors.push(err);
218
- }
219
- }));
220
- try {
221
- const { ensureLocalesLoaded } = await import("@stacksjs/i18n");
222
- await ensureLocalesLoaded();
223
- } catch (err) {
224
- errors.push(err);
225
- }
226
- try {
227
- const autoImports = await import(path.storagePath("framework/auto-imports/index.ts"));
228
- Object.assign(globalThis, autoImports);
229
- } catch (err) {
230
- errors.push(err);
231
- }
232
- if (errors.length)
233
- for (const err of errors)
234
- console.warn("[auto-imports]", err.message);
235
- }
8
+ `;await Bun.write(`${outputDir}/index.ts`,combinedContent);const globalsPath=`${outputDir}/globals.ts`;await generateGlobalsScript([functionsPath],globalsPath,`${outputDir}/index.ts`);log.debug("Auto-import files generated successfully")}export function initiateImports(){const functionsPath=path.resourcesPath("functions"),defaultFunctionsPath=path.storagePath("framework/defaults/functions"),userModelsPath=path.userModelsPath(),defaultModelDirs=resolveDefaultModelDirs(),[defaultsRoot=path.storagePath("framework/defaults/app/Models"),...enabledSubdirs]=defaultModelDirs,userJobsPath=path.userJobsPath(),userControllersPath=path.userControllersPath(),defaultControllersPath=path.storagePath("framework/defaults/app/Controllers"),defineModelExports=[...scanDefineModelExports(userModelsPath),...scanDefineModelExports(defaultsRoot,{recursive:!1}),...enabledSubdirs.flatMap((d)=>scanDefineModelExports(d))],jobExports=scanDefineModelExports(userJobsPath),seen=new Set,uniqueDefineModelExports=defineModelExports.filter((exp)=>{if(seen.has(exp.name))return!1;seen.add(exp.name);return!0}),dtsDir=dirname(path.storagePath("framework/types/server-auto-imports.d.ts")),defineModelImports=uniqueDefineModelExports.map((exp)=>({from:`./${relative(dtsDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,"")}`,name:"default",as:exp.name})),jobImports=jobExports.map((exp)=>({from:`./${relative(dtsDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,"")}`,name:"default",as:exp.name})),controllerExports=[...scanDefineModelExports(userControllersPath),...scanDefineModelExports(defaultControllersPath)],seenControllers=new Set,controllerImports=controllerExports.filter((exp)=>{if(seenControllers.has(exp.name))return!1;seenControllers.add(exp.name);return!0}).map((exp)=>({from:`./${relative(dtsDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,"")}`,name:"default",as:exp.name})),options={dts:path.storagePath("framework/types/server-auto-imports.d.ts"),imports:[...primitiveAutoImportEntries(),...defineModelImports,...jobImports,...controllerImports],dirs:[functionsPath,defaultFunctionsPath],eslint:{enabled:!0,filepath:path.storagePath("framework/server-auto-imports.json")}};plugin(autoImports(options));generateAutoImportFiles().catch((err)=>{console.error("[Server] Failed to generate auto-import files:",err)})}export async function generateServerAutoImportTypes(){const userModelsPath=path.userModelsPath(),defaultModelDirs=resolveDefaultModelDirs(),[defaultsRoot=path.storagePath("framework/defaults/app/Models"),...enabledSubdirs]=defaultModelDirs,modelExports=[...scanDefineModelExports(userModelsPath),...scanDefineModelExports(defaultsRoot,{recursive:!1}),...enabledSubdirs.flatMap((dir)=>scanDefineModelExports(dir))],jobExports=scanDefineModelExports(path.userJobsPath()),controllerExports=[...scanDefineModelExports(path.userControllersPath()),...scanDefineModelExports(path.storagePath("framework/defaults/app/Controllers"))],seen=new Set,valueExports=[...modelExports,...jobExports,...controllerExports].filter((exp)=>!GLOBAL_SHADOW_BLOCKLIST.has(exp.name)).filter((exp)=>{if(seen.has(exp.name))return!1;seen.add(exp.name);return!0}),outputPath=path.storagePath("framework/types/server-auto-imports.d.ts"),outputDir=dirname(outputPath),declaredValues=new Set(valueExports.map((exp)=>exp.name)),lines=["// Generated by Stacks server auto-imports","// This file is regenerated automatically when the API starts.","export {}","declare global {"];for(const{from,name,as}of primitiveAutoImportEntries())if(!declaredValues.has(as))lines.push(` const ${as}: typeof import('${from}')['${name}']`);for(const exp of valueExports){const importPath=relative(outputDir,exp.file).replace(/\\/g,"/").replace(/\.ts$/,""),relativePath=importPath.startsWith(".")?importPath:`./${importPath}`;lines.push(` const ${exp.name}: typeof import('${relativePath}')['default']`)}lines.push("}","");await Bun.write(outputPath,lines.join(`
9
+ `))}export async function injectGlobalAutoImports(){if(globalThis.__stacksAutoImportsInjected)return;globalThis.__stacksAutoImportsInjected=!0;const errors=[],importWithTimeout=async(pkg)=>{return Promise.race([import(pkg),new Promise((_,reject)=>setTimeout(()=>reject(Error(`auto-import timed out: ${pkg}`)),4000))])};await Promise.all(primitiveModules.map(async([pkg,names])=>{try{const mod=await importWithTimeout(pkg);for(const name of names)if(mod[name]!==void 0)globalThis[name]=mod[name]}catch(err){errors.push(err)}}));try{const{ensureLocalesLoaded}=await import("@stacksjs/i18n");await ensureLocalesLoaded()}catch(err){errors.push(err)}try{const autoImports=await import(path.storagePath("framework/auto-imports/index.ts"));Object.assign(globalThis,autoImports)}catch(err){errors.push(err)}if(errors.length)for(const err of errors)console.warn("[auto-imports]",err.message)}
package/dist/index.js CHANGED
@@ -1,5 +1 @@
1
- export { config as server } from "./config";
2
- export * from "./controllers/base";
3
- export * from "./imports";
4
- export * from "./maintenance";
5
- export * from "./proxy";
1
+ export{config as server}from"./config";export*from"./controllers/base";export*from"./imports";export*from"./maintenance";export*from"./proxy";
@@ -1,148 +1,4 @@
1
- import { log } from "@stacksjs/logging";
2
- import * as p from "@stacksjs/path";
3
- const DEFAULT_MAINTENANCE_PAYLOAD = {
4
- mode: "maintenance",
5
- status: 503,
6
- message: "We are currently performing maintenance. Please check back soon."
7
- }, DEFAULT_COMING_SOON_PAYLOAD = {
8
- mode: "coming-soon",
9
- status: 200,
10
- message: "Stacks is setting up camp. Check back soon for the public launch.",
11
- redirect: "/coming-soon"
12
- };
13
- function defaultsForMode(mode) {
14
- return mode === "coming-soon" ? DEFAULT_COMING_SOON_PAYLOAD : DEFAULT_MAINTENANCE_PAYLOAD;
15
- }
16
- export function maintenanceFilePath() {
17
- return p.storagePath("framework/down");
18
- }
19
- export function comingSoonFilePath() {
20
- return p.storagePath("framework/coming-soon");
21
- }
22
- export function siteModeFilePath(mode) {
23
- return mode === "coming-soon" ? comingSoonFilePath() : maintenanceFilePath();
24
- }
25
- export async function isDownForMaintenance() {
26
- try {
27
- return await Bun.file(maintenanceFilePath()).exists();
28
- } catch {
29
- return !1;
30
- }
31
- }
32
- export async function isComingSoon() {
33
- try {
34
- return await Bun.file(comingSoonFilePath()).exists();
35
- } catch {
36
- return !1;
37
- }
38
- }
39
- export async function maintenancePayload() {
40
- return siteModePayload("maintenance");
41
- }
42
- export async function comingSoonPayload() {
43
- return siteModePayload("coming-soon");
44
- }
45
- export async function siteModePayload(mode) {
46
- try {
47
- const file = Bun.file(siteModeFilePath(mode));
48
- if (!await file.exists())
49
- return null;
50
- const content = await file.text();
51
- return {
52
- ...defaultsForMode(mode),
53
- ...JSON.parse(content),
54
- mode
55
- };
56
- } catch {
57
- return null;
58
- }
59
- }
60
- export async function activeSiteModePayload() {
61
- return await maintenancePayload() ?? await comingSoonPayload() ?? envSiteModePayload();
62
- }
63
- function envSiteModePayload() {
64
- if (isTruthy(process.env.APP_MAINTENANCE))
65
- return {
66
- ...DEFAULT_MAINTENANCE_PAYLOAD,
67
- mode: "maintenance",
68
- time: Date.now(),
69
- secret: process.env.APP_MAINTENANCE_SECRET || void 0
70
- };
71
- if (isTruthy(process.env.APP_COMING_SOON))
72
- return {
73
- ...DEFAULT_COMING_SOON_PAYLOAD,
74
- mode: "coming-soon",
75
- time: Date.now(),
76
- secret: process.env.APP_COMING_SOON_SECRET || void 0
77
- };
78
- return null;
79
- }
80
- function isTruthy(value) {
81
- return ["1", "true", "yes", "on"].includes(String(value || "").toLowerCase());
82
- }
83
- export async function down(options = {}) {
84
- const payload = {
85
- ...DEFAULT_MAINTENANCE_PAYLOAD,
86
- ...options,
87
- mode: "maintenance",
88
- time: Date.now()
89
- }, frameworkDir = p.storagePath("framework"), { mkdirSync, existsSync } = await import("@stacksjs/storage");
90
- if (!existsSync(frameworkDir))
91
- mkdirSync(frameworkDir, { recursive: !0 });
92
- await Bun.write(maintenanceFilePath(), JSON.stringify(payload, null, 2));
93
- log.info("Application is now in maintenance mode.");
94
- if (payload.secret)
95
- log.info("Maintenance bypass secret has been configured");
96
- }
97
- export async function comingSoon(options = {}) {
98
- const payload = {
99
- ...DEFAULT_COMING_SOON_PAYLOAD,
100
- ...options,
101
- mode: "coming-soon",
102
- time: Date.now()
103
- }, frameworkDir = p.storagePath("framework"), { mkdirSync, existsSync } = await import("@stacksjs/storage");
104
- if (!existsSync(frameworkDir))
105
- mkdirSync(frameworkDir, { recursive: !0 });
106
- await Bun.write(comingSoonFilePath(), JSON.stringify(payload, null, 2));
107
- log.info("Application is now in coming soon mode.");
108
- if (payload.secret)
109
- log.info("Coming soon bypass secret has been configured");
110
- }
111
- export async function up() {
112
- const { unlinkSync, existsSync } = await import("node:fs"), filePath = maintenanceFilePath();
113
- if (existsSync(filePath)) {
114
- unlinkSync(filePath);
115
- log.info("Application is now live.");
116
- } else
117
- log.info("Application is already live.");
118
- }
119
- export async function launch() {
120
- const { unlinkSync, existsSync } = await import("node:fs"), filePath = comingSoonFilePath();
121
- if (existsSync(filePath)) {
122
- unlinkSync(filePath);
123
- log.info("Application is out of coming soon mode.");
124
- } else
125
- log.info("Application is not in coming soon mode.");
126
- }
127
- export function isAllowedIp(ip, allowed = [], trustLocalhost = !0) {
128
- if (trustLocalhost && ["127.0.0.1", "::1", "localhost"].includes(ip))
129
- return !0;
130
- if (allowed.length === 0)
131
- return !1;
132
- return allowed.includes(ip);
133
- }
134
- export function bypassCookieName(mode = "maintenance") {
135
- return mode === "coming-soon" ? "stacks_coming_soon_bypass" : "stacks_maintenance_bypass";
136
- }
137
- export function hasValidBypassCookie(cookies, secret, mode = "maintenance") {
138
- return cookies[bypassCookieName(mode)] === secret;
139
- }
140
- export function isSecretPath(path, secret) {
141
- return path === `/${secret}` || path.startsWith(`/${secret}/`);
142
- }
143
- export function maintenanceHtml(payload) {
144
- const mode = payload.mode ?? "maintenance", defaults = defaultsForMode(mode), message = escapeHtml(payload.message || defaults.message || ""), title = escapeHtml(payload.title || (mode === "coming-soon" ? "Opening Soon" : "Trail Maintenance"));
145
- return `<!DOCTYPE html>
1
+ import{log}from"@stacksjs/logging";import*as p from"@stacksjs/path";const DEFAULT_MAINTENANCE_PAYLOAD={mode:"maintenance",status:503,message:"We are currently performing maintenance. Please check back soon."},DEFAULT_COMING_SOON_PAYLOAD={mode:"coming-soon",status:200,message:"Stacks is setting up camp. Check back soon for the public launch.",redirect:"/coming-soon"};function defaultsForMode(mode){return mode==="coming-soon"?DEFAULT_COMING_SOON_PAYLOAD:DEFAULT_MAINTENANCE_PAYLOAD}export function maintenanceFilePath(){return p.storagePath("framework/down")}export function comingSoonFilePath(){return p.storagePath("framework/coming-soon")}export function siteModeFilePath(mode){return mode==="coming-soon"?comingSoonFilePath():maintenanceFilePath()}export async function isDownForMaintenance(){try{return await Bun.file(maintenanceFilePath()).exists()}catch{return!1}}export async function isComingSoon(){try{return await Bun.file(comingSoonFilePath()).exists()}catch{return!1}}export async function maintenancePayload(){return siteModePayload("maintenance")}export async function comingSoonPayload(){return siteModePayload("coming-soon")}export async function siteModePayload(mode){try{const file=Bun.file(siteModeFilePath(mode));if(!await file.exists())return null;const content=await file.text();return{...defaultsForMode(mode),...JSON.parse(content),mode}}catch{return null}}export async function activeSiteModePayload(){return await maintenancePayload()??await comingSoonPayload()??envSiteModePayload()}function envSiteModePayload(){if(isTruthy(process.env.APP_MAINTENANCE))return{...DEFAULT_MAINTENANCE_PAYLOAD,mode:"maintenance",time:Date.now(),secret:process.env.APP_MAINTENANCE_SECRET||void 0};if(isTruthy(process.env.APP_COMING_SOON))return{...DEFAULT_COMING_SOON_PAYLOAD,mode:"coming-soon",time:Date.now(),secret:process.env.APP_COMING_SOON_SECRET||void 0};return null}function isTruthy(value){return["1","true","yes","on"].includes(String(value||"").toLowerCase())}export async function down(options={}){const payload={...DEFAULT_MAINTENANCE_PAYLOAD,...options,mode:"maintenance",time:Date.now()},frameworkDir=p.storagePath("framework"),{mkdirSync,existsSync}=await import("@stacksjs/storage");if(!existsSync(frameworkDir))mkdirSync(frameworkDir,{recursive:!0});await Bun.write(maintenanceFilePath(),JSON.stringify(payload,null,2));log.info("Application is now in maintenance mode.");if(payload.secret)log.info("Maintenance bypass secret has been configured")}export async function comingSoon(options={}){const payload={...DEFAULT_COMING_SOON_PAYLOAD,...options,mode:"coming-soon",time:Date.now()},frameworkDir=p.storagePath("framework"),{mkdirSync,existsSync}=await import("@stacksjs/storage");if(!existsSync(frameworkDir))mkdirSync(frameworkDir,{recursive:!0});await Bun.write(comingSoonFilePath(),JSON.stringify(payload,null,2));log.info("Application is now in coming soon mode.");if(payload.secret)log.info("Coming soon bypass secret has been configured")}export async function up(){const{unlinkSync,existsSync}=await import("node:fs"),filePath=maintenanceFilePath();if(existsSync(filePath)){unlinkSync(filePath);log.info("Application is now live.")}else log.info("Application is already live.")}export async function launch(){const{unlinkSync,existsSync}=await import("node:fs"),filePath=comingSoonFilePath();if(existsSync(filePath)){unlinkSync(filePath);log.info("Application is out of coming soon mode.")}else log.info("Application is not in coming soon mode.")}export function isAllowedIp(ip,allowed=[],trustLocalhost=!0){if(trustLocalhost&&["127.0.0.1","::1","localhost"].includes(ip))return!0;if(allowed.length===0)return!1;return allowed.includes(ip)}export function bypassCookieName(mode="maintenance"){return mode==="coming-soon"?"stacks_coming_soon_bypass":"stacks_maintenance_bypass"}export function hasValidBypassCookie(cookies,secret,mode="maintenance"){return cookies[bypassCookieName(mode)]===secret}export function isSecretPath(path,secret){return path===`/${secret}`||path.startsWith(`/${secret}/`)}export function maintenanceHtml(payload){const mode=payload.mode??"maintenance",defaults=defaultsForMode(mode),message=escapeHtml(payload.message||defaults.message||""),title=escapeHtml(payload.title||(mode==="coming-soon"?"Opening Soon":"Trail Maintenance"));return`<!DOCTYPE html>
146
2
  <html lang="en">
147
3
  <head>
148
4
  <meta charset="UTF-8">
@@ -266,102 +122,11 @@ export function maintenanceHtml(payload) {
266
122
  </head>
267
123
  <body>
268
124
  <div class="container">
269
- <div class="eyebrow">${mode === "coming-soon" ? "Stacks basecamp" : "Service notice"}</div>
125
+ <div class="eyebrow">${mode==="coming-soon"?"Stacks basecamp":"Service notice"}</div>
270
126
  <h1>${title}</h1>
271
- <p class="lead">${mode === "coming-soon" ? "The public trailhead is almost ready." : "The route is temporarily closed while the crew improves the path."}</p>
127
+ <p class="lead">${mode==="coming-soon"?"The public trailhead is almost ready.":"The route is temporarily closed while the crew improves the path."}</p>
272
128
  <p class="message">${message}</p>
273
- ${payload.retry ? `<p class="retry">Estimated reopening: ${Math.ceil(payload.retry / 60)} minutes.</p>` : ""}
129
+ ${payload.retry?`<p class="retry">Estimated reopening: ${Math.ceil(payload.retry/60)} minutes.</p>`:""}
274
130
  </div>
275
131
  </body>
276
- </html>`;
277
- }
278
- function escapeHtml(value) {
279
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#039;");
280
- }
281
- export function maintenanceResponse(payload) {
282
- return siteModeResponse(payload);
283
- }
284
- export function siteModeResponse(payload) {
285
- const headers = {
286
- "Content-Type": "text/html; charset=utf-8"
287
- };
288
- if (payload.retry)
289
- headers["Retry-After"] = String(payload.retry);
290
- if (payload.redirect)
291
- return new Response(null, {
292
- status: 302,
293
- headers: { Location: payload.redirect }
294
- });
295
- return new Response(maintenanceHtml(payload), {
296
- status: payload.status || (payload.mode === "coming-soon" ? 200 : 503),
297
- headers
298
- });
299
- }
300
- export function bypassCookieValue(secret, mode = "maintenance") {
301
- return `${bypassCookieName(mode)}=${secret}; Path=/; HttpOnly; SameSite=Lax`;
302
- }
303
- const ALWAYS_ALLOWED_PATHS = new Set([
304
- "/coming-soon",
305
- "/api/email/subscribe",
306
- "/favicon.ico"
307
- ]), ALWAYS_ALLOWED_PREFIXES = [
308
- "/css/",
309
- "/js/",
310
- "/images/",
311
- "/fonts/",
312
- "/assets/",
313
- "/_modules/",
314
- "/@vite/",
315
- "/@fs/",
316
- "/__deps/"
317
- ];
318
- function isAlwaysAllowed(path) {
319
- if (ALWAYS_ALLOWED_PATHS.has(path))
320
- return !0;
321
- return ALWAYS_ALLOWED_PREFIXES.some((p) => path.startsWith(p));
322
- }
323
- function parseCookieHeader(header) {
324
- const out = {};
325
- if (!header)
326
- return out;
327
- for (const part of header.split(";")) {
328
- const trimmed = part.trim(), eq = trimmed.indexOf("=");
329
- if (eq === -1)
330
- continue;
331
- const k = trimmed.slice(0, eq).trim(), v = trimmed.slice(eq + 1).trim();
332
- if (k)
333
- out[k] = v;
334
- }
335
- return out;
336
- }
337
- function clientIp(req) {
338
- const fwd = req.headers.get("x-forwarded-for");
339
- if (fwd)
340
- return fwd.split(",")[0]?.trim() ?? "127.0.0.1";
341
- const real = req.headers.get("x-real-ip");
342
- if (real)
343
- return real;
344
- return "127.0.0.1";
345
- }
346
- export async function maintenanceGate(req) {
347
- const payload = await activeSiteModePayload();
348
- if (!payload)
349
- return null;
350
- const mode = payload.mode ?? "maintenance", path = new URL(req.url).pathname;
351
- if (isAlwaysAllowed(path))
352
- return null;
353
- if (payload.secret && isSecretPath(path, payload.secret)) {
354
- const location = mode === "coming-soon" ? `/?preview=${encodeURIComponent(payload.secret)}` : "/";
355
- return new Response(null, {
356
- status: 302,
357
- headers: {
358
- Location: location,
359
- "Set-Cookie": bypassCookieValue(payload.secret, mode)
360
- }
361
- });
362
- }
363
- const cookies = parseCookieHeader(req.headers.get("cookie")), hasCookie = !!payload.secret && hasValidBypassCookie(cookies, payload.secret, mode), appEnv = (process.env.APP_ENV || "development").toLowerCase(), trustLocalhost = !["production", "staging"].includes(appEnv), ipAllowed = isAllowedIp(clientIp(req), payload.allowed, trustLocalhost);
364
- if (hasCookie || ipAllowed)
365
- return null;
366
- return siteModeResponse(payload);
367
- }
132
+ </html>`}function escapeHtml(value){return value.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#039;")}export function maintenanceResponse(payload){return siteModeResponse(payload)}export function siteModeResponse(payload){const headers={"Content-Type":"text/html; charset=utf-8"};if(payload.retry)headers["Retry-After"]=String(payload.retry);if(payload.redirect)return new Response(null,{status:302,headers:{Location:payload.redirect}});return new Response(maintenanceHtml(payload),{status:payload.status||(payload.mode==="coming-soon"?200:503),headers})}export function bypassCookieValue(secret,mode="maintenance"){return`${bypassCookieName(mode)}=${secret}; Path=/; HttpOnly; SameSite=Lax`}const ALWAYS_ALLOWED_PATHS=new Set(["/coming-soon","/api/email/subscribe","/favicon.ico"]),ALWAYS_ALLOWED_PREFIXES=["/css/","/js/","/images/","/fonts/","/assets/","/_modules/","/@vite/","/@fs/","/__deps/"];function isAlwaysAllowed(path){if(ALWAYS_ALLOWED_PATHS.has(path))return!0;return ALWAYS_ALLOWED_PREFIXES.some((p)=>path.startsWith(p))}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 k=trimmed.slice(0,eq).trim(),v=trimmed.slice(eq+1).trim();if(k)out[k]=v}return out}function clientIp(req){const fwd=req.headers.get("x-forwarded-for");if(fwd)return fwd.split(",")[0]?.trim()??"127.0.0.1";const real=req.headers.get("x-real-ip");if(real)return real;return"127.0.0.1"}export async function maintenanceGate(req){const payload=await activeSiteModePayload();if(!payload)return null;const mode=payload.mode??"maintenance",path=new URL(req.url).pathname;if(isAlwaysAllowed(path))return null;if(payload.secret&&isSecretPath(path,payload.secret)){const location=mode==="coming-soon"?`/?preview=${encodeURIComponent(payload.secret)}`:"/";return new Response(null,{status:302,headers:{Location:location,"Set-Cookie":bypassCookieValue(payload.secret,mode)}})}const cookies=parseCookieHeader(req.headers.get("cookie")),hasCookie=!!payload.secret&&hasValidBypassCookie(cookies,payload.secret,mode),appEnv=(process.env.APP_ENV||"development").toLowerCase(),trustLocalhost=!["production","staging"].includes(appEnv),ipAllowed=isAllowedIp(clientIp(req),payload.allowed,trustLocalhost);if(hasCookie||ipAllowed)return null;return siteModeResponse(payload)}
@@ -1,29 +1 @@
1
- export const primitiveModules = [
2
- ["@stacksjs/path", ["path"]],
3
- ["@stacksjs/error-handling", ["HttpError", "handleError"]],
4
- ["@stacksjs/logging", ["log"]],
5
- ["@stacksjs/config", ["config"]],
6
- ["@stacksjs/validation", ["schema"]],
7
- ["@stacksjs/router", ["response", "request", "route", "Middleware", "url"]],
8
- ["@stacksjs/storage", ["storage", "fs"]],
9
- ["@stacksjs/orm", ["defineModel", "toAttrs"]],
10
- ["@stacksjs/database", ["db", "sql"]],
11
- ["@stacksjs/email", ["mail", "template"]],
12
- ["@stacksjs/queue", ["Job"]],
13
- ["@stacksjs/scheduler", ["schedule"]],
14
- ["@stacksjs/actions", ["Action"]],
15
- ["@stacksjs/auth", ["Auth", "register", "sessionCheck"]],
16
- ["@stacksjs/events", ["dispatch", "listen", "emitter"]],
17
- ["@stacksjs/feature-flags", ["Feature"]],
18
- ["@stacksjs/security", ["makeHash", "verifyHash"]],
19
- ["@stacksjs/collections", ["collect"]],
20
- ["@stacksjs/cli", ["quotes"]],
21
- ["@stacksjs/notifications", ["notify", "useNotification", "useEmail", "useSMS", "useChat", "useDatabase"]],
22
- ["@stacksjs/realtime", ["emit", "emitToUser", "emitToUsers", "createChannel", "dispatchBroadcast"]],
23
- ["@stacksjs/i18n", ["I18n", "t", "tc", "te", "setLocale", "getLocale"]],
24
- ["@stacksjs/stx", ["state", "derived", "effect"]],
25
- ["@stacksjs/browser", ["useDark", "usePreferredDark", "useToggle", "useStorage"]]
26
- ];
27
- export function primitiveAutoImportEntries() {
28
- return primitiveModules.flatMap(([from, names]) => names.map((name) => ({ from, name, as: name })));
29
- }
1
+ export const primitiveModules=[["@stacksjs/path",["path"]],["@stacksjs/error-handling",["HttpError","handleError"]],["@stacksjs/logging",["log"]],["@stacksjs/config",["config"]],["@stacksjs/validation",["schema"]],["@stacksjs/router",["response","request","route","Middleware","url"]],["@stacksjs/storage",["storage","fs"]],["@stacksjs/orm",["defineModel","toAttrs"]],["@stacksjs/database",["db","sql"]],["@stacksjs/email",["mail","template"]],["@stacksjs/queue",["Job"]],["@stacksjs/scheduler",["schedule"]],["@stacksjs/actions",["Action"]],["@stacksjs/auth",["Auth","register","sessionCheck"]],["@stacksjs/events",["dispatch","listen","emitter"]],["@stacksjs/feature-flags",["Feature"]],["@stacksjs/security",["makeHash","verifyHash"]],["@stacksjs/collections",["collect"]],["@stacksjs/cli",["quotes"]],["@stacksjs/notifications",["notify","useNotification","useEmail","useSMS","useChat","useDatabase"]],["@stacksjs/realtime",["emit","emitToUser","emitToUsers","createChannel","dispatchBroadcast"]],["@stacksjs/i18n",["I18n","t","tc","te","setLocale","getLocale"]],["@stacksjs/stx",["state","derived","effect"]],["@stacksjs/browser",["useDark","usePreferredDark","useToggle","useStorage"]]];export function primitiveAutoImportEntries(){return primitiveModules.flatMap(([from,names])=>names.map((name)=>({from,name,as:name})))}
package/dist/proxy.js CHANGED
@@ -1,28 +1 @@
1
- const API_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
2
- export function isApiBoundRequest(req, pathname) {
3
- return pathname.startsWith("/api/") || API_METHODS.has(req.method);
4
- }
5
- export async function proxyToBackend(req, backendBase, stripPrefix) {
6
- const incoming = new URL(req.url);
7
- let pathname = incoming.pathname;
8
- if (stripPrefix && (pathname === stripPrefix || pathname.startsWith(`${stripPrefix}/`)))
9
- pathname = pathname.slice(stripPrefix.length) || "/";
10
- const target = `${backendBase}${pathname}${incoming.search}`, fwd = new Headers(req.headers);
11
- fwd.delete("host");
12
- fwd.delete("content-length");
13
- fwd.set("x-forwarded-host", incoming.host);
14
- fwd.set("x-forwarded-proto", incoming.protocol.replace(":", ""));
15
- const body = req.method === "GET" || req.method === "HEAD" ? void 0 : await req.arrayBuffer(), upstream = await fetch(target, {
16
- method: req.method,
17
- headers: fwd,
18
- body,
19
- redirect: "manual"
20
- }), out = new Headers(upstream.headers);
21
- out.delete("content-length");
22
- out.delete("content-encoding");
23
- return new Response(upstream.body, {
24
- status: upstream.status,
25
- statusText: upstream.statusText,
26
- headers: out
27
- });
28
- }
1
+ const API_METHODS=new Set(["POST","PUT","PATCH","DELETE"]);export function isApiBoundRequest(req,pathname){return pathname.startsWith("/api/")||API_METHODS.has(req.method)}export async function proxyToBackend(req,backendBase,stripPrefix){const incoming=new URL(req.url);let pathname=incoming.pathname;if(stripPrefix&&(pathname===stripPrefix||pathname.startsWith(`${stripPrefix}/`)))pathname=pathname.slice(stripPrefix.length)||"/";const target=`${backendBase}${pathname}${incoming.search}`,fwd=new Headers(req.headers);fwd.delete("host");fwd.delete("content-length");fwd.set("x-forwarded-host",incoming.host);fwd.set("x-forwarded-proto",incoming.protocol.replace(":",""));const body=req.method==="GET"||req.method==="HEAD"?void 0:await req.arrayBuffer(),upstream=await fetch(target,{method:req.method,headers:fwd,body,redirect:"manual"}),out=new Headers(upstream.headers);out.delete("content-length");out.delete("content-encoding");return new Response(upstream.body,{status:upstream.status,statusText:upstream.statusText,headers:out})}
package/dist/start.js CHANGED
@@ -1,54 +1 @@
1
- globalThis.__STACKS_BINARY_MODE__ = !0;
2
- import { assertRouteMiddlewareResolvable, loadRoutes, serve } from "@stacksjs/router";
3
- import { log, report } from "@stacksjs/logging";
4
- import config from "./config-production";
5
- import routeRegistry from "../../../../../app/Routes";
6
- process.on("unhandledRejection", (reason) => {
7
- report(reason, { label: "[server] unhandledRejection" });
8
- });
9
- process.on("uncaughtException", (error) => {
10
- report(error, { label: "[server] uncaughtException" });
11
- log.flush().finally(() => process.exit(1));
12
- });
13
- console.log("[START] Application starting...");
14
- console.log("[START] Node version:", process.version);
15
- console.log("[START] Working directory:", process.cwd());
16
- console.log("[START] Environment:", process.env.APP_ENV || "not set");
17
- process.env.SKIP_CONFIG_LOADING = "true";
18
- console.log("[START] Config loaded:", {
19
- port: config.server.port,
20
- host: config.server.host,
21
- appName: config.app.name,
22
- appUrl: config.app.url
23
- });
24
- console.log("[START] Loading routes from registry...");
25
- loadRoutes(routeRegistry).then(async () => {
26
- console.log("[START] Routes loaded successfully");
27
- try {
28
- await import("../../orm/routes");
29
- console.log("[START] ORM routes loaded successfully");
30
- } catch (ormError) {
31
- console.warn("[START] ORM routes skipped:", ormError instanceof Error ? ormError.message : String(ormError));
32
- }
33
- try {
34
- await assertRouteMiddlewareResolvable();
35
- console.log("[START] Route middleware validated");
36
- } catch (middlewareError) {
37
- console.error("[START] FATAL: unresolvable route middleware \u2014 refusing to serve unprotected routes:", middlewareError instanceof Error ? middlewareError.message : String(middlewareError));
38
- process.exit(1);
39
- }
40
- console.log("[START] Calling serve()...");
41
- try {
42
- serve({
43
- port: config.server.port,
44
- host: config.server.host
45
- });
46
- console.log("[START] serve() called successfully");
47
- } catch (error) {
48
- console.error("[START] ERROR calling serve():", error);
49
- process.exit(1);
50
- }
51
- }).catch((error) => {
52
- console.error("[START] ERROR loading routes:", error);
53
- process.exit(1);
54
- });
1
+ globalThis.__STACKS_BINARY_MODE__=!0;import{assertRouteMiddlewareResolvable,loadRoutes,serve}from"@stacksjs/router";import{log,report}from"@stacksjs/logging";import config from"./config-production";import routeRegistry from"../../../../../app/Routes";process.on("unhandledRejection",(reason)=>{report(reason,{label:"[server] unhandledRejection"})});process.on("uncaughtException",(error)=>{report(error,{label:"[server] uncaughtException"});log.flush().finally(()=>process.exit(1))});console.log("[START] Application starting...");console.log("[START] Node version:",process.version);console.log("[START] Working directory:",process.cwd());console.log("[START] Environment:",process.env.APP_ENV||"not set");process.env.SKIP_CONFIG_LOADING="true";console.log("[START] Config loaded:",{port:config.server.port,host:config.server.host,appName:config.app.name,appUrl:config.app.url});console.log("[START] Loading routes from registry...");loadRoutes(routeRegistry).then(async()=>{console.log("[START] Routes loaded successfully");try{await import("../../orm/routes");console.log("[START] ORM routes loaded successfully")}catch(ormError){console.warn("[START] ORM routes skipped:",ormError instanceof Error?ormError.message:String(ormError))}try{await assertRouteMiddlewareResolvable();console.log("[START] Route middleware validated")}catch(middlewareError){console.error("[START] FATAL: unresolvable route middleware \u2014 refusing to serve unprotected routes:",middlewareError instanceof Error?middlewareError.message:String(middlewareError));process.exit(1)}console.log("[START] Calling serve()...");try{serve({port:config.server.port,host:config.server.host});console.log("[START] serve() called successfully")}catch(error){console.error("[START] ERROR calling serve():",error);process.exit(1)}}).catch((error)=>{console.error("[START] ERROR loading routes:",error);process.exit(1)});
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/server",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.258",
5
+ "version": "0.70.260",
6
6
  "description": "Local development and production-ready.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -34,9 +34,16 @@
34
34
  "default": "./dist/index.js"
35
35
  },
36
36
  "./*": {
37
- "bun": "./dist/*",
38
- "import": "./dist/*",
39
- "default": "./dist/*"
37
+ "types": "./dist/*.d.ts",
38
+ "bun": "./dist/*.js",
39
+ "import": "./dist/*.js",
40
+ "default": "./dist/*.js"
41
+ },
42
+ "./*.js": {
43
+ "types": "./dist/*.d.ts",
44
+ "bun": "./dist/*.js",
45
+ "import": "./dist/*.js",
46
+ "default": "./dist/*.js"
40
47
  }
41
48
  },
42
49
  "module": "dist/index.js",
@@ -51,11 +58,11 @@
51
58
  "prepublishOnly": "bun run build"
52
59
  },
53
60
  "devDependencies": {
54
- "@stacksjs/config": "0.70.258",
61
+ "@stacksjs/config": "0.70.260",
55
62
  "better-dx": "^0.2.17",
56
- "@stacksjs/path": "0.70.258",
57
- "@stacksjs/router": "0.70.258",
58
- "@stacksjs/validation": "0.70.258"
63
+ "@stacksjs/path": "0.70.260",
64
+ "@stacksjs/router": "0.70.260",
65
+ "@stacksjs/validation": "0.70.260"
59
66
  },
60
67
  "dependencies": {
61
68
  "bun-plugin-auto-imports": "^0.4.0"