@stacksjs/config 0.70.87 → 0.70.90
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 +1 -0
- package/dist/config.js +109 -0
- package/dist/defaults.js +626 -0
- package/dist/features.js +53 -0
- package/dist/helpers.d.ts +2 -1
- package/dist/helpers.js +153 -0
- package/dist/index.js +4 -9
- package/dist/overrides.js +111 -0
- package/dist/validators.js +119 -0
- package/package.json +3 -3
package/dist/config.d.ts
CHANGED
|
@@ -81,6 +81,7 @@ export declare let dns: StacksOptions['dns'];
|
|
|
81
81
|
export declare let docs: StacksOptions['docs'];
|
|
82
82
|
export declare let email: StacksOptions['email'];
|
|
83
83
|
export declare let errors: StacksOptions['errors'];
|
|
84
|
+
export declare let featureFlags: StacksOptions['featureFlags'];
|
|
84
85
|
export declare let git: StacksOptions['git'];
|
|
85
86
|
export declare let hashing: StacksOptions['hashing'];
|
|
86
87
|
export declare let library: StacksOptions['library'];
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { defaults } from "./defaults";
|
|
2
|
+
import { overrides, overridesReady } from "./overrides";
|
|
3
|
+
function readMerged(prop) {
|
|
4
|
+
const o = overrides[prop];
|
|
5
|
+
if (o !== void 0 && (typeof o !== "object" || Object.keys(o).length > 0))
|
|
6
|
+
return o;
|
|
7
|
+
return defaults[prop];
|
|
8
|
+
}
|
|
9
|
+
const proxyTarget = function configProxyTarget() {};
|
|
10
|
+
export const config = new Proxy(proxyTarget, {
|
|
11
|
+
get(_t, prop) {
|
|
12
|
+
return readMerged(prop);
|
|
13
|
+
},
|
|
14
|
+
has(_t, prop) {
|
|
15
|
+
return prop in overrides || prop in defaults;
|
|
16
|
+
},
|
|
17
|
+
ownKeys() {
|
|
18
|
+
return Array.from(new Set([
|
|
19
|
+
...Object.keys(overrides),
|
|
20
|
+
...Object.keys(defaults)
|
|
21
|
+
]));
|
|
22
|
+
},
|
|
23
|
+
getOwnPropertyDescriptor(_t, prop) {
|
|
24
|
+
if (typeof prop !== "string")
|
|
25
|
+
return;
|
|
26
|
+
if (!(prop in overrides) && !(prop in defaults))
|
|
27
|
+
return;
|
|
28
|
+
return {
|
|
29
|
+
enumerable: !0,
|
|
30
|
+
configurable: !0,
|
|
31
|
+
writable: !0,
|
|
32
|
+
value: readMerged(prop)
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
isExtensible() {
|
|
36
|
+
return !0;
|
|
37
|
+
},
|
|
38
|
+
preventExtensions() {
|
|
39
|
+
return !1;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
export async function awaitConfig() {
|
|
43
|
+
await overridesReady;
|
|
44
|
+
return config;
|
|
45
|
+
}
|
|
46
|
+
const DB_READY = Symbol.for("@stacksjs/config:databaseReady"), globalScope = globalThis;
|
|
47
|
+
export async function awaitDatabaseConfig() {
|
|
48
|
+
await overridesReady;
|
|
49
|
+
const deadline = Date.now() + 5000;
|
|
50
|
+
while (!globalScope[DB_READY] && Date.now() < deadline)
|
|
51
|
+
await new Promise((r) => setTimeout(r, 25));
|
|
52
|
+
if (!globalScope[DB_READY])
|
|
53
|
+
console.warn("[config] awaitDatabaseConfig() timed out \u2014 database driver did not signal readiness within 5s");
|
|
54
|
+
return config;
|
|
55
|
+
}
|
|
56
|
+
export function markDatabaseReady() {
|
|
57
|
+
globalScope[DB_READY] = !0;
|
|
58
|
+
}
|
|
59
|
+
export function getConfig() {
|
|
60
|
+
return config;
|
|
61
|
+
}
|
|
62
|
+
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;
|
|
63
|
+
overridesReady.then(() => {
|
|
64
|
+
ai = config.ai;
|
|
65
|
+
analytics = config.analytics;
|
|
66
|
+
app = config.app;
|
|
67
|
+
auth = config.auth;
|
|
68
|
+
realtime = config.realtime;
|
|
69
|
+
cache = config.cache;
|
|
70
|
+
cloud = config.cloud;
|
|
71
|
+
cli = config.cli;
|
|
72
|
+
dashboard = config.dashboard;
|
|
73
|
+
database = config.database;
|
|
74
|
+
dns = config.dns;
|
|
75
|
+
docs = config.docs;
|
|
76
|
+
email = config.email;
|
|
77
|
+
errors = config.errors;
|
|
78
|
+
featureFlags = config.featureFlags;
|
|
79
|
+
git = config.git;
|
|
80
|
+
hashing = config.hashing;
|
|
81
|
+
library = config.library;
|
|
82
|
+
logging = config.logging;
|
|
83
|
+
notification = config.notification;
|
|
84
|
+
payment = config.payment;
|
|
85
|
+
ports = config.ports;
|
|
86
|
+
queue = config.queue;
|
|
87
|
+
security = config.security;
|
|
88
|
+
saas = config.saas;
|
|
89
|
+
searchEngine = config.searchEngine;
|
|
90
|
+
services = config.services;
|
|
91
|
+
filesystems = config.filesystems;
|
|
92
|
+
team = config.team;
|
|
93
|
+
ui = config.ui;
|
|
94
|
+
}).catch(() => {});
|
|
95
|
+
|
|
96
|
+
export * from "./helpers";
|
|
97
|
+
export { defaults, overrides, overridesReady };
|
|
98
|
+
export function determineAppEnv() {
|
|
99
|
+
const env = config.app?.env;
|
|
100
|
+
if (env === "local" || env === "development")
|
|
101
|
+
return "dev";
|
|
102
|
+
if (env === "staging")
|
|
103
|
+
return "stage";
|
|
104
|
+
if (env === "production")
|
|
105
|
+
return "prod";
|
|
106
|
+
if (!env)
|
|
107
|
+
throw Error("Couldn't determine app environment");
|
|
108
|
+
return env;
|
|
109
|
+
}
|
package/dist/defaults.js
ADDED
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
var {require}=import.meta;import { commandsPath, projectPath, userDatabasePath } from "@stacksjs/path";
|
|
2
|
+
export const FRAMEWORK_DEFAULTS = {
|
|
3
|
+
awsRegion: "us-east-1",
|
|
4
|
+
timezone: "UTC",
|
|
5
|
+
noReplyEmail: "no-reply@stacksjs.com",
|
|
6
|
+
fallbackDomain: "stacks.localhost"
|
|
7
|
+
};
|
|
8
|
+
function deriveAppDefaults() {
|
|
9
|
+
try {
|
|
10
|
+
const pkgPath = projectPath("package.json"), raw = (require(pkgPath).name ?? "").trim();
|
|
11
|
+
if (!raw)
|
|
12
|
+
return { name: "Stacks", url: "stacks.localhost" };
|
|
13
|
+
const slug = raw.replace(/^@[^/]+\//, "").toLowerCase();
|
|
14
|
+
return { name: slug.replace(/[-_]+/g, " ").replace(/(^|\s)\w/g, (c) => c.toUpperCase()), url: `${slug}.localhost` };
|
|
15
|
+
} catch {
|
|
16
|
+
return { name: "Stacks", url: "stacks.localhost" };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const appDefaults = deriveAppDefaults();
|
|
20
|
+
export const defaults = {
|
|
21
|
+
cms: { enabled: !1 },
|
|
22
|
+
commerce: { enabled: !1 },
|
|
23
|
+
marketing: { enabled: !1 },
|
|
24
|
+
monitoring: { enabled: !1 },
|
|
25
|
+
ai: {
|
|
26
|
+
deploy: !1,
|
|
27
|
+
models: [
|
|
28
|
+
"anthropic.claude-sonnet-4-20250514-v1:0",
|
|
29
|
+
"anthropic.claude-haiku-4-20250514-v1:0",
|
|
30
|
+
"anthropic.claude-3-5-sonnet-20241022-v2:0",
|
|
31
|
+
"amazon.titan-embed-text-v2:0",
|
|
32
|
+
"amazon.titan-text-premier-v1:0",
|
|
33
|
+
"amazon.titan-image-generator-v2:0",
|
|
34
|
+
"meta.llama3-1-70b-instruct-v1:0",
|
|
35
|
+
"meta.llama3-1-8b-instruct-v1:0"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
auth: {
|
|
39
|
+
username: "email",
|
|
40
|
+
password: "password",
|
|
41
|
+
defaultTokenName: "auth-token",
|
|
42
|
+
tokenExpiry: 3600000,
|
|
43
|
+
refreshTokenExpiry: 2592000000,
|
|
44
|
+
defaultAbilities: ["*"]
|
|
45
|
+
},
|
|
46
|
+
realtime: {
|
|
47
|
+
driver: "pusher"
|
|
48
|
+
},
|
|
49
|
+
analytics: {
|
|
50
|
+
driver: void 0
|
|
51
|
+
},
|
|
52
|
+
app: {
|
|
53
|
+
name: appDefaults.name,
|
|
54
|
+
description: "A Stacks application.",
|
|
55
|
+
env: "local",
|
|
56
|
+
url: appDefaults.url,
|
|
57
|
+
debug: !0,
|
|
58
|
+
key: "",
|
|
59
|
+
timezone: FRAMEWORK_DEFAULTS.timezone,
|
|
60
|
+
locale: "en",
|
|
61
|
+
fallbackLocale: "en",
|
|
62
|
+
cipher: "AES-256-CBC",
|
|
63
|
+
docMode: !1,
|
|
64
|
+
redirectUrls: [],
|
|
65
|
+
maintenanceMode: !1,
|
|
66
|
+
comingSoonMode: !1,
|
|
67
|
+
comingSoonSecret: ""
|
|
68
|
+
},
|
|
69
|
+
cli: {
|
|
70
|
+
name: "My Custom CLI",
|
|
71
|
+
command: "my-custom-cli",
|
|
72
|
+
description: "Stacks is a full-stack framework for TypeScript.",
|
|
73
|
+
source: commandsPath(),
|
|
74
|
+
deploy: !1
|
|
75
|
+
},
|
|
76
|
+
cache: {
|
|
77
|
+
driver: "memory",
|
|
78
|
+
prefix: "stx",
|
|
79
|
+
ttl: 3600,
|
|
80
|
+
maxKeys: -1,
|
|
81
|
+
useClones: !0,
|
|
82
|
+
drivers: {
|
|
83
|
+
redis: {
|
|
84
|
+
host: "localhost",
|
|
85
|
+
port: 6379,
|
|
86
|
+
username: "",
|
|
87
|
+
password: "",
|
|
88
|
+
database: 0,
|
|
89
|
+
tls: !1
|
|
90
|
+
},
|
|
91
|
+
memory: {
|
|
92
|
+
maxKeys: -1,
|
|
93
|
+
checkPeriod: 600,
|
|
94
|
+
deleteOnExpire: !0
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
featureFlags: {
|
|
99
|
+
default: "memory",
|
|
100
|
+
missing: "false",
|
|
101
|
+
drivers: {
|
|
102
|
+
memory: { cloneValues: !0 },
|
|
103
|
+
database: { table: "feature_flags", autoCreate: !1 }
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
cloud: {
|
|
107
|
+
infrastructure: {
|
|
108
|
+
type: "serverless",
|
|
109
|
+
driver: "aws",
|
|
110
|
+
environments: ["production", "staging", "development"],
|
|
111
|
+
firewall: {
|
|
112
|
+
enabled: !0,
|
|
113
|
+
countryCodes: [],
|
|
114
|
+
ipAddresses: [],
|
|
115
|
+
queryString: [],
|
|
116
|
+
httpHeaders: [],
|
|
117
|
+
rateLimitPerMinute: 1000,
|
|
118
|
+
useIpReputationLists: !0,
|
|
119
|
+
useKnownBadInputsRuleSet: !0
|
|
120
|
+
},
|
|
121
|
+
cdn: {
|
|
122
|
+
allowedMethods: "GET_HEAD",
|
|
123
|
+
cachedMethods: "GET_HEAD",
|
|
124
|
+
minTtl: 0,
|
|
125
|
+
defaultTtl: 86400,
|
|
126
|
+
maxTtl: 31536000,
|
|
127
|
+
compress: !0,
|
|
128
|
+
priceClass: "PriceClass_All",
|
|
129
|
+
originShieldRegion: FRAMEWORK_DEFAULTS.awsRegion,
|
|
130
|
+
cookieBehavior: "none",
|
|
131
|
+
allowList: {
|
|
132
|
+
cookies: [],
|
|
133
|
+
headers: [],
|
|
134
|
+
queryStrings: []
|
|
135
|
+
},
|
|
136
|
+
realtimeLogs: {
|
|
137
|
+
enabled: !0,
|
|
138
|
+
samplingRate: 2
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
fileSystem: !1,
|
|
142
|
+
storage: {}
|
|
143
|
+
},
|
|
144
|
+
sites: {
|
|
145
|
+
root: "",
|
|
146
|
+
path: ""
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
dashboard: {
|
|
150
|
+
sections: {
|
|
151
|
+
library: { enabled: !0 },
|
|
152
|
+
content: { enabled: !0 },
|
|
153
|
+
commerce: { enabled: !0 },
|
|
154
|
+
marketing: { enabled: !0 },
|
|
155
|
+
analytics: { enabled: !0 },
|
|
156
|
+
management: { enabled: !0 },
|
|
157
|
+
utilities: { enabled: !0 }
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
database: {
|
|
161
|
+
default: "sqlite",
|
|
162
|
+
logging: !1,
|
|
163
|
+
connections: {
|
|
164
|
+
sqlite: {
|
|
165
|
+
database: userDatabasePath("stacks.sqlite"),
|
|
166
|
+
prefix: ""
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
migrations: "migrations",
|
|
170
|
+
migrationLocks: "migration_locks"
|
|
171
|
+
},
|
|
172
|
+
dns: {
|
|
173
|
+
driver: "aws",
|
|
174
|
+
a: [],
|
|
175
|
+
aaaa: [],
|
|
176
|
+
cname: [],
|
|
177
|
+
mx: [],
|
|
178
|
+
txt: []
|
|
179
|
+
},
|
|
180
|
+
docs: {
|
|
181
|
+
lang: "en-US",
|
|
182
|
+
title: "Stacks",
|
|
183
|
+
description: "Rapid application, cloud & library framework.",
|
|
184
|
+
lastUpdated: !0,
|
|
185
|
+
deploy: !1,
|
|
186
|
+
themeConfig: {
|
|
187
|
+
editLink: {
|
|
188
|
+
pattern: "https://github.com/stacksjs/stacks/edit/main/docs/docs/:path",
|
|
189
|
+
text: "Edit this page on GitHub"
|
|
190
|
+
},
|
|
191
|
+
footer: {
|
|
192
|
+
message: "Released under the MIT License.",
|
|
193
|
+
copyright: "Copyright \xA9 2024-present Stacks.js, Inc."
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
email: {
|
|
198
|
+
from: {
|
|
199
|
+
name: "Stacks",
|
|
200
|
+
address: FRAMEWORK_DEFAULTS.noReplyEmail
|
|
201
|
+
},
|
|
202
|
+
mailboxes: [],
|
|
203
|
+
server: {
|
|
204
|
+
enabled: !0,
|
|
205
|
+
scan: !0
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
errors: {
|
|
209
|
+
messages: {
|
|
210
|
+
string: "The {{ field }} field must be a string",
|
|
211
|
+
email: "The {{ field }} field must be a valid email address",
|
|
212
|
+
regex: "The {{ field }} field format is invalid",
|
|
213
|
+
url: "The {{ field }} field must be a valid URL",
|
|
214
|
+
activeUrl: "The {{ field }} field must be a valid URL",
|
|
215
|
+
alpha: "The {{ field }} field must contain only letters",
|
|
216
|
+
alphaNumeric: "The {{ field }} field must contain only letters and numbers",
|
|
217
|
+
"min(": "The {{ field }} field must have at least {{ min }} characters",
|
|
218
|
+
maxLength: "The {{ field }} field must not be greater than {{ max }} characters",
|
|
219
|
+
fixedLength: "The {{ field }} field must be {{ size }} characters long",
|
|
220
|
+
confirmed: "The {{ field }} field and {{ otherField }} field must be the same",
|
|
221
|
+
endsWith: "The {{ field }} field must end with {{ substring }}",
|
|
222
|
+
startsWith: "The {{ field }} field must start with {{ substring }}",
|
|
223
|
+
sameAs: "The {{ field }} field and {{ otherField }} field must be the same",
|
|
224
|
+
notSameAs: "The {{ field }} field and {{ otherField }} field must be different",
|
|
225
|
+
in: "The selected {{ field }} is invalid",
|
|
226
|
+
notIn: "The selected {{ field }} is invalid",
|
|
227
|
+
ipAddress: "The {{ field }} field must be a valid IP address",
|
|
228
|
+
uuid: "The {{ field }} field must be a valid UUID",
|
|
229
|
+
ascii: "The {{ field }} field must only contain ASCII characters",
|
|
230
|
+
creditCard: "The {{ field }} field must be a valid {{ providersList }} card number",
|
|
231
|
+
hexCode: "The {{ field }} field must be a valid hex color code",
|
|
232
|
+
iban: "The {{ field }} field must be a valid IBAN number",
|
|
233
|
+
jwt: "The {{ field }} field must be a valid JWT token",
|
|
234
|
+
coordinates: "The {{ field }} field must contain latitude and longitude coordinates",
|
|
235
|
+
mobile: "The {{ field }} field must be a valid mobile phone number",
|
|
236
|
+
passport: "The {{ field }} field must be a valid passport number",
|
|
237
|
+
postalCode: "The {{ field }} field must be a valid postal code",
|
|
238
|
+
boolean: "The value must be a boolean",
|
|
239
|
+
number: "The {{ field }} field must be a number",
|
|
240
|
+
min: "The {{ field }} field must be at least {{ min }}",
|
|
241
|
+
max: "The {{ field }} field must not be greater than {{ max }}",
|
|
242
|
+
range: "The {{ field }} field must be between {{ min }} and {{ max }}",
|
|
243
|
+
positive: "The {{ field }} field must be positive",
|
|
244
|
+
negative: "The {{ field }} field must be negative",
|
|
245
|
+
decimal: "The {{ field }} field must have {{ digits }} decimal places",
|
|
246
|
+
withoutDecimals: "The {{ field }} field must not have decimal places",
|
|
247
|
+
date: "The {{ field }} field must be a datetime value",
|
|
248
|
+
"date.equals": "The {{ field }} field must be a date equal to {{ expectedValue }}",
|
|
249
|
+
"date.after": "The {{ field }} field must be a date after {{ expectedValue }}",
|
|
250
|
+
"date.before": "The {{ field }} field must be a date before {{ expectedValue }}",
|
|
251
|
+
"date.afterOrEqual": "The {{ field }} field must be a date after or equal to {{ expectedValue }}",
|
|
252
|
+
"date.beforeOrEqual": "The {{ field }} field must be a date before or equal to {{ expectedValue }}",
|
|
253
|
+
"date.sameAs": "The {{ field }} field and {{ otherField }} field must be the same",
|
|
254
|
+
"date.notSameAs": "The {{ field }} field and {{ otherField }} field must be different",
|
|
255
|
+
"date.afterField": "The {{ field }} field must be a date after {{ otherField }}",
|
|
256
|
+
accepted: "The {{ field }} field must be accepted",
|
|
257
|
+
enum: "The selected {{ field }} is invalid",
|
|
258
|
+
literal: "The {{ field }} field must be {{ expectedValue }}",
|
|
259
|
+
object: "The {{ field }} field must be an object",
|
|
260
|
+
record: "The {{ field }} field must be an object",
|
|
261
|
+
"record.min(": "The {{ field }} field must have at least {{ min }} items",
|
|
262
|
+
"record.maxLength": "The {{ field }} field must not have more than {{ max }} items",
|
|
263
|
+
"record.fixedLength": "The {{ field }} field must contain {{ size }} items",
|
|
264
|
+
array: "The {{ field }} field must be an array",
|
|
265
|
+
"array.min(": "The {{ field }} field must have at least {{ min }} items",
|
|
266
|
+
"array.maxLength": "The {{ field }} field must not have more than {{ max }} items",
|
|
267
|
+
"array.fixedLength": "The {{ field }} field must contain {{ size }} items",
|
|
268
|
+
notEmpty: "The {{ field }} field must not be empty",
|
|
269
|
+
distinct: "The {{ field }} field has duplicate values",
|
|
270
|
+
tuple: "The {{ field }} field must be an array",
|
|
271
|
+
union: "Invalid value provided for {{ field }} field",
|
|
272
|
+
unionGroup: "Invalid value provided for {{ field }} field",
|
|
273
|
+
unionOfTypes: "Invalid value provided for {{ field }} field"
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
git: {
|
|
277
|
+
hooks: {
|
|
278
|
+
"pre-commit": "lint-staged"
|
|
279
|
+
},
|
|
280
|
+
scopes: [
|
|
281
|
+
"",
|
|
282
|
+
"ci",
|
|
283
|
+
"deps",
|
|
284
|
+
"dx",
|
|
285
|
+
"release",
|
|
286
|
+
"docs",
|
|
287
|
+
"test",
|
|
288
|
+
"core",
|
|
289
|
+
"actions",
|
|
290
|
+
"arrays",
|
|
291
|
+
"auth",
|
|
292
|
+
"build",
|
|
293
|
+
"cache",
|
|
294
|
+
"cli",
|
|
295
|
+
"cloud",
|
|
296
|
+
"collections",
|
|
297
|
+
"config",
|
|
298
|
+
"database",
|
|
299
|
+
"datetime",
|
|
300
|
+
"docs",
|
|
301
|
+
"errors",
|
|
302
|
+
"git",
|
|
303
|
+
"lint",
|
|
304
|
+
"x-ray",
|
|
305
|
+
"modules",
|
|
306
|
+
"notifications",
|
|
307
|
+
"objects",
|
|
308
|
+
"path",
|
|
309
|
+
"realtime",
|
|
310
|
+
"router",
|
|
311
|
+
"buddy",
|
|
312
|
+
"security",
|
|
313
|
+
"server",
|
|
314
|
+
"storage",
|
|
315
|
+
"strings",
|
|
316
|
+
"tests",
|
|
317
|
+
"types",
|
|
318
|
+
"ui",
|
|
319
|
+
"utils"
|
|
320
|
+
],
|
|
321
|
+
messages: {
|
|
322
|
+
type: "Select the type of change that you're committing:",
|
|
323
|
+
scope: "Select the SCOPE of this change (optional):",
|
|
324
|
+
customScope: "Select the SCOPE of this change:",
|
|
325
|
+
subject: `Write a SHORT, IMPERATIVE tense description of the change:
|
|
326
|
+
`,
|
|
327
|
+
body: `Provide a LONGER description of the change (optional). Use "|" to break new line:
|
|
328
|
+
`,
|
|
329
|
+
breaking: `List any BREAKING CHANGES (optional). Use "|" to break new line:
|
|
330
|
+
`,
|
|
331
|
+
footerPrefixesSelect: "Select the ISSUES type of the change list by this change (optional):",
|
|
332
|
+
customFooterPrefixes: "Input ISSUES prefix:",
|
|
333
|
+
footer: `List any ISSUES by this change. E.g.: #31, #34:
|
|
334
|
+
`,
|
|
335
|
+
confirmCommit: "Are you sure you want to proceed with the commit above?"
|
|
336
|
+
},
|
|
337
|
+
types: [
|
|
338
|
+
{
|
|
339
|
+
value: "feat",
|
|
340
|
+
name: "feat: \u2728 A new feature",
|
|
341
|
+
emoji: ":sparkles:"
|
|
342
|
+
},
|
|
343
|
+
{ value: "fix", name: "fix: \uD83D\uDC1B A bug fix", emoji: ":bug:" },
|
|
344
|
+
{
|
|
345
|
+
value: "docs",
|
|
346
|
+
name: "docs: \uD83D\uDCDD Documentation only changes",
|
|
347
|
+
emoji: ":memo:"
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
value: "style",
|
|
351
|
+
name: "style: \uD83D\uDC84 Changes that do not affect the meaning of the code",
|
|
352
|
+
emoji: ":lipstick:"
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
value: "refactor",
|
|
356
|
+
name: "refactor: \u267B\uFE0F A code change that neither fixes a bug nor adds a feature",
|
|
357
|
+
emoji: ":recycle:"
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
value: "perf",
|
|
361
|
+
name: "perf: \u26A1\uFE0F A code change that improves performance",
|
|
362
|
+
emoji: ":zap:"
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
value: "test",
|
|
366
|
+
name: "test: \u2705 Adding missing tests or adjusting existing tests",
|
|
367
|
+
emoji: ":white_check_mark:"
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
value: "build",
|
|
371
|
+
name: "build: \uD83D\uDCE6\uFE0F Changes that affect the build system or external dependencies",
|
|
372
|
+
emoji: ":package:"
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
value: "ci",
|
|
376
|
+
name: "ci: \uD83C\uDFA1 Changes to our CI configuration files and scripts",
|
|
377
|
+
emoji: ":ferris_wheel:"
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
value: "chore",
|
|
381
|
+
name: "chore: \uD83D\uDD28 Other changes that don't modify src or test files",
|
|
382
|
+
emoji: ":hammer:"
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
value: "revert",
|
|
386
|
+
name: "revert: \u23EA\uFE0F Reverts a previous commit",
|
|
387
|
+
emoji: ":rewind:"
|
|
388
|
+
}
|
|
389
|
+
]
|
|
390
|
+
},
|
|
391
|
+
hashing: {
|
|
392
|
+
driver: "bcrypt",
|
|
393
|
+
bcrypt: {
|
|
394
|
+
rounds: 12
|
|
395
|
+
},
|
|
396
|
+
argon2: {
|
|
397
|
+
memory: 65536,
|
|
398
|
+
time: 2
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
library: {
|
|
402
|
+
name: "hello-world",
|
|
403
|
+
owner: "@stacksjs",
|
|
404
|
+
repository: "stacksjs/stacks",
|
|
405
|
+
license: "MIT",
|
|
406
|
+
author: "",
|
|
407
|
+
contributors: [],
|
|
408
|
+
defaultLanguage: "en",
|
|
409
|
+
webComponents: {
|
|
410
|
+
name: "hello-world-elements",
|
|
411
|
+
description: "Your framework agnostic web component library description.",
|
|
412
|
+
keywords: ["custom-elements", "web-components", "library", "framework-agnostic", "typescript", "javascript"],
|
|
413
|
+
tags: [
|
|
414
|
+
{
|
|
415
|
+
name: ["HelloWorld", "AppHelloWorld"],
|
|
416
|
+
description: "The Hello World custom element, built via this framework.",
|
|
417
|
+
attributes: [
|
|
418
|
+
{
|
|
419
|
+
name: "greeting",
|
|
420
|
+
description: "The greeting."
|
|
421
|
+
}
|
|
422
|
+
]
|
|
423
|
+
}
|
|
424
|
+
]
|
|
425
|
+
},
|
|
426
|
+
functions: {
|
|
427
|
+
name: "hello-world-fx",
|
|
428
|
+
description: "Your function library description.",
|
|
429
|
+
keywords: ["functions", "composables", "library", "typescript", "javascript"],
|
|
430
|
+
shouldGenerateSourcemap: !1,
|
|
431
|
+
files: ["counter", "dark"]
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
logging: {
|
|
435
|
+
logsPath: "storage/logs/stacks.log",
|
|
436
|
+
deploymentsPath: "storage/logs/deployments.log"
|
|
437
|
+
},
|
|
438
|
+
notification: {
|
|
439
|
+
default: "email"
|
|
440
|
+
},
|
|
441
|
+
payment: {
|
|
442
|
+
driver: "stripe"
|
|
443
|
+
},
|
|
444
|
+
ports: {
|
|
445
|
+
frontend: 3000,
|
|
446
|
+
backend: 3001,
|
|
447
|
+
admin: 3002,
|
|
448
|
+
library: 3003,
|
|
449
|
+
desktop: 3004,
|
|
450
|
+
email: 3005,
|
|
451
|
+
docs: 3006,
|
|
452
|
+
inspect: 3007,
|
|
453
|
+
api: 3008,
|
|
454
|
+
systemTray: 3009,
|
|
455
|
+
database: 3010
|
|
456
|
+
},
|
|
457
|
+
queue: {
|
|
458
|
+
default: "sync",
|
|
459
|
+
connections: {
|
|
460
|
+
sync: {
|
|
461
|
+
driver: "sync"
|
|
462
|
+
},
|
|
463
|
+
database: {
|
|
464
|
+
driver: "database",
|
|
465
|
+
table: "jobs",
|
|
466
|
+
queue: "default",
|
|
467
|
+
retryAfter: 90
|
|
468
|
+
},
|
|
469
|
+
redis: {
|
|
470
|
+
driver: "redis",
|
|
471
|
+
queue: "default",
|
|
472
|
+
retryAfter: 90
|
|
473
|
+
},
|
|
474
|
+
sqs: {
|
|
475
|
+
driver: "sqs",
|
|
476
|
+
key: "",
|
|
477
|
+
secret: "",
|
|
478
|
+
prefix: "",
|
|
479
|
+
suffix: "",
|
|
480
|
+
queue: "default",
|
|
481
|
+
region: FRAMEWORK_DEFAULTS.awsRegion
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
saas: {
|
|
486
|
+
plans: [
|
|
487
|
+
{
|
|
488
|
+
productName: "Stacks Hobby",
|
|
489
|
+
description: "All the Stacks features.",
|
|
490
|
+
pricing: [
|
|
491
|
+
{
|
|
492
|
+
key: "stacks_hobby_monthly",
|
|
493
|
+
price: 3900,
|
|
494
|
+
interval: "month",
|
|
495
|
+
currency: "usd"
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
key: "stacks_hobby_yearly",
|
|
499
|
+
price: 37900,
|
|
500
|
+
interval: "year",
|
|
501
|
+
currency: "usd"
|
|
502
|
+
}
|
|
503
|
+
],
|
|
504
|
+
metadata: {
|
|
505
|
+
createdBy: "admin",
|
|
506
|
+
version: "1.0.0"
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
productName: "Stacks Pro",
|
|
511
|
+
description: "All the Stacks features, including being able to invite team members.",
|
|
512
|
+
pricing: [
|
|
513
|
+
{
|
|
514
|
+
key: "stacks_pro_monthly",
|
|
515
|
+
price: 5900,
|
|
516
|
+
interval: "month",
|
|
517
|
+
currency: "usd"
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
key: "stacks_pro_yearly",
|
|
521
|
+
price: 57900,
|
|
522
|
+
interval: "year",
|
|
523
|
+
currency: "usd"
|
|
524
|
+
}
|
|
525
|
+
],
|
|
526
|
+
metadata: {
|
|
527
|
+
createdBy: "admin",
|
|
528
|
+
version: "1.0.0"
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
],
|
|
532
|
+
webhook: {
|
|
533
|
+
endpoint: "/webhooks/stripe",
|
|
534
|
+
secret: ""
|
|
535
|
+
},
|
|
536
|
+
currencies: ["usd"],
|
|
537
|
+
coupons: [
|
|
538
|
+
{
|
|
539
|
+
code: "SUMMER2024",
|
|
540
|
+
amountOff: 500,
|
|
541
|
+
duration: "once"
|
|
542
|
+
}
|
|
543
|
+
],
|
|
544
|
+
products: [
|
|
545
|
+
{
|
|
546
|
+
name: "Stacks Pro",
|
|
547
|
+
description: "All the Stacks features.",
|
|
548
|
+
images: ["url_to_image"]
|
|
549
|
+
}
|
|
550
|
+
]
|
|
551
|
+
},
|
|
552
|
+
searchEngine: {
|
|
553
|
+
driver: "opensearch"
|
|
554
|
+
},
|
|
555
|
+
security: {
|
|
556
|
+
firewall: {
|
|
557
|
+
enabled: !0,
|
|
558
|
+
countryCodes: [],
|
|
559
|
+
ipAddresses: [],
|
|
560
|
+
queryString: [],
|
|
561
|
+
httpHeaders: [],
|
|
562
|
+
rateLimitPerMinute: 1000,
|
|
563
|
+
useIpReputationLists: !0,
|
|
564
|
+
useKnownBadInputsRuleSet: !0
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
services: {
|
|
568
|
+
aws: {
|
|
569
|
+
accountId: "",
|
|
570
|
+
appId: "",
|
|
571
|
+
apiKey: "",
|
|
572
|
+
region: FRAMEWORK_DEFAULTS.awsRegion
|
|
573
|
+
},
|
|
574
|
+
algolia: {
|
|
575
|
+
appId: "",
|
|
576
|
+
apiKey: ""
|
|
577
|
+
},
|
|
578
|
+
meilisearch: {
|
|
579
|
+
appId: "",
|
|
580
|
+
apiKey: ""
|
|
581
|
+
},
|
|
582
|
+
stripe: {
|
|
583
|
+
appId: "",
|
|
584
|
+
apiKey: ""
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
filesystems: {
|
|
588
|
+
driver: "s3"
|
|
589
|
+
},
|
|
590
|
+
team: {
|
|
591
|
+
name: "",
|
|
592
|
+
members: {}
|
|
593
|
+
},
|
|
594
|
+
ui: {
|
|
595
|
+
shortcuts: [
|
|
596
|
+
[
|
|
597
|
+
"btn",
|
|
598
|
+
"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"
|
|
599
|
+
]
|
|
600
|
+
],
|
|
601
|
+
safelist: "prose prose-sm m-auto text-left",
|
|
602
|
+
trigger: ":stx:",
|
|
603
|
+
classPrefix: "stx-",
|
|
604
|
+
reset: "tailwind",
|
|
605
|
+
icons: ["hugeicons"],
|
|
606
|
+
fonts: {
|
|
607
|
+
email: {
|
|
608
|
+
title: "Mona",
|
|
609
|
+
text: "Hubot"
|
|
610
|
+
},
|
|
611
|
+
desktop: {
|
|
612
|
+
title: "Mona",
|
|
613
|
+
text: "Hubot"
|
|
614
|
+
},
|
|
615
|
+
mobile: {
|
|
616
|
+
title: "Mona",
|
|
617
|
+
text: "Hubot"
|
|
618
|
+
},
|
|
619
|
+
web: {
|
|
620
|
+
title: "Mona",
|
|
621
|
+
text: "Hubot"
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
export default defaults;
|
package/dist/features.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { config } from "./config";
|
|
2
|
+
const FEATURE_NAMES = [
|
|
3
|
+
"auth",
|
|
4
|
+
"marketing",
|
|
5
|
+
"cms",
|
|
6
|
+
"commerce",
|
|
7
|
+
"dashboard",
|
|
8
|
+
"monitoring",
|
|
9
|
+
"realtime",
|
|
10
|
+
"queue"
|
|
11
|
+
], FEATURE_DEFAULTS = {
|
|
12
|
+
dashboard: !0
|
|
13
|
+
}, overrides = new Map;
|
|
14
|
+
function configFor(name) {
|
|
15
|
+
const raw = config[name];
|
|
16
|
+
return raw && typeof raw === "object" ? raw : void 0;
|
|
17
|
+
}
|
|
18
|
+
export function feature(name) {
|
|
19
|
+
if (overrides.has(name))
|
|
20
|
+
return overrides.get(name);
|
|
21
|
+
const cfg = configFor(name);
|
|
22
|
+
if (cfg) {
|
|
23
|
+
const enabledField = cfg.enabled;
|
|
24
|
+
if (enabledField === !1)
|
|
25
|
+
return !1;
|
|
26
|
+
if (Array.isArray(cfg.env) && cfg.env.length > 0) {
|
|
27
|
+
const currentEnv = (config.app?.env ?? "").toString();
|
|
28
|
+
if (!cfg.env.includes(currentEnv))
|
|
29
|
+
return !1;
|
|
30
|
+
}
|
|
31
|
+
if (enabledField !== void 0)
|
|
32
|
+
return !!enabledField;
|
|
33
|
+
return !0;
|
|
34
|
+
}
|
|
35
|
+
return FEATURE_DEFAULTS[name] ?? !1;
|
|
36
|
+
}
|
|
37
|
+
export function enableFeature(name) {
|
|
38
|
+
overrides.set(name, !0);
|
|
39
|
+
}
|
|
40
|
+
export function disableFeature(name) {
|
|
41
|
+
overrides.set(name, !1);
|
|
42
|
+
}
|
|
43
|
+
export function resetFeature(name) {
|
|
44
|
+
overrides.delete(name);
|
|
45
|
+
}
|
|
46
|
+
export function listFeatures() {
|
|
47
|
+
const out = {};
|
|
48
|
+
for (const name of FEATURE_NAMES)
|
|
49
|
+
out[name] = feature(name);
|
|
50
|
+
for (const name of overrides.keys())
|
|
51
|
+
out[name] = feature(name);
|
|
52
|
+
return out;
|
|
53
|
+
}
|
package/dist/helpers.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { config } from '.';
|
|
2
|
-
import type { AppConfig, CacheConfig, CdnConfig, ChatConfig, CliConfig, DatabaseConfig, DependenciesConfig, DnsConfig, EmailConfig, Events, FilesystemsConfig, GitConfig, HashingConfig, LibraryConfig, Model, NotificationConfig, PaymentConfig, QueueConfig, SearchEngineConfig, SecurityConfig, ServicesConfig, StacksConfig, StorageConfig, UiConfig } from '@stacksjs/types';
|
|
2
|
+
import type { AppConfig, CacheConfig, CdnConfig, ChatConfig, CliConfig, DatabaseConfig, DependenciesConfig, DnsConfig, EmailConfig, Events, FilesystemsConfig, FeatureFlagsConfig, GitConfig, HashingConfig, LibraryConfig, Model, NotificationConfig, PaymentConfig, QueueConfig, SearchEngineConfig, SecurityConfig, ServicesConfig, StacksConfig, StorageConfig, UiConfig } from '@stacksjs/types';
|
|
3
3
|
export declare function localUrl(options?: {
|
|
4
4
|
domain?: string
|
|
5
5
|
type?: LocalUrlType
|
|
@@ -30,6 +30,7 @@ export declare function defineServices(config: ServicesConfig): ServicesConfig;
|
|
|
30
30
|
export declare function defineSms(config: any): any;
|
|
31
31
|
export declare function defineStorage(config: StorageConfig): StorageConfig;
|
|
32
32
|
export declare function defineFilesystems(config: FilesystemsConfig): FilesystemsConfig;
|
|
33
|
+
export declare function defineFeatureFlags(config: FeatureFlagsConfig): FeatureFlagsConfig;
|
|
33
34
|
export declare function defineUi(config: UiConfig): UiConfig;
|
|
34
35
|
export declare function defineModel(config: Model): Model;
|
|
35
36
|
export declare function defineEvents(config: Events): Events;
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { config } from ".";
|
|
2
|
+
export async function localUrl(options = {}) {
|
|
3
|
+
const domain = options.domain ?? config.app.url ?? "stacks", type = options.type ?? "frontend", localhost = options.localhost ?? !1, https = options.https, network = options.network;
|
|
4
|
+
let url = domain.replace(/\.[^.]+$/, ".localhost");
|
|
5
|
+
async function tunnel(port) {
|
|
6
|
+
const { createLocalTunnel } = await import("@stacksjs/tunnel");
|
|
7
|
+
return createLocalTunnel(port);
|
|
8
|
+
}
|
|
9
|
+
switch (type) {
|
|
10
|
+
case "frontend":
|
|
11
|
+
if (network)
|
|
12
|
+
return await tunnel(config.ports?.frontend || 3000);
|
|
13
|
+
if (localhost)
|
|
14
|
+
return `http://localhost:${config.ports?.frontend}`;
|
|
15
|
+
break;
|
|
16
|
+
case "backend":
|
|
17
|
+
if (network)
|
|
18
|
+
return await tunnel(config.ports?.backend || 3001);
|
|
19
|
+
if (localhost)
|
|
20
|
+
return `http://localhost:${config.ports?.backend}`;
|
|
21
|
+
url = `api.${url}`;
|
|
22
|
+
break;
|
|
23
|
+
case "admin":
|
|
24
|
+
if (network)
|
|
25
|
+
return await tunnel(config.ports?.admin || 3002);
|
|
26
|
+
if (localhost)
|
|
27
|
+
return `http://localhost:${config.ports?.admin}`;
|
|
28
|
+
url = `admin.${url}`;
|
|
29
|
+
break;
|
|
30
|
+
case "library":
|
|
31
|
+
if (network)
|
|
32
|
+
return await tunnel(config.ports?.library || 3003);
|
|
33
|
+
if (localhost)
|
|
34
|
+
return `http://localhost:${config.ports?.library}`;
|
|
35
|
+
url = `libs.${url}`;
|
|
36
|
+
break;
|
|
37
|
+
case "email":
|
|
38
|
+
if (network)
|
|
39
|
+
return await tunnel(config.ports?.email || 3005);
|
|
40
|
+
if (localhost)
|
|
41
|
+
return `http://localhost:${config.ports?.email}`;
|
|
42
|
+
url = `email.${url}`;
|
|
43
|
+
break;
|
|
44
|
+
case "desktop":
|
|
45
|
+
if (network)
|
|
46
|
+
return await tunnel(config.ports?.desktop || 3004);
|
|
47
|
+
if (localhost)
|
|
48
|
+
return `http://localhost:${config.ports?.desktop}`;
|
|
49
|
+
url = `desktop.${url}`;
|
|
50
|
+
break;
|
|
51
|
+
case "docs":
|
|
52
|
+
if (network)
|
|
53
|
+
return await tunnel(config.ports?.docs || 3006);
|
|
54
|
+
if (localhost)
|
|
55
|
+
return `http://localhost:${config.ports?.docs}`;
|
|
56
|
+
url = `docs.${url}`;
|
|
57
|
+
break;
|
|
58
|
+
case "inspect":
|
|
59
|
+
if (network)
|
|
60
|
+
return await tunnel(config.ports?.inspect || 3007);
|
|
61
|
+
if (localhost)
|
|
62
|
+
return `http://localhost:${config.ports?.inspect}`;
|
|
63
|
+
url = `inspect.${url}`;
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
if (localhost)
|
|
67
|
+
return `http://localhost:${config.ports?.frontend}`;
|
|
68
|
+
}
|
|
69
|
+
if (https)
|
|
70
|
+
return `https://${url}`;
|
|
71
|
+
return `http://${url}`;
|
|
72
|
+
}
|
|
73
|
+
export function defineStacksConfig(config) {
|
|
74
|
+
return config;
|
|
75
|
+
}
|
|
76
|
+
export function defineApp(config) {
|
|
77
|
+
return config;
|
|
78
|
+
}
|
|
79
|
+
export function defineCache(config) {
|
|
80
|
+
return config;
|
|
81
|
+
}
|
|
82
|
+
export function defineCdn(config) {
|
|
83
|
+
return config;
|
|
84
|
+
}
|
|
85
|
+
export function defineChat(config) {
|
|
86
|
+
return config;
|
|
87
|
+
}
|
|
88
|
+
export function defineCli(config) {
|
|
89
|
+
return config;
|
|
90
|
+
}
|
|
91
|
+
export function defineDatabase(config) {
|
|
92
|
+
return config;
|
|
93
|
+
}
|
|
94
|
+
export function defineDependencies(config) {
|
|
95
|
+
return config;
|
|
96
|
+
}
|
|
97
|
+
export function defineDns(config) {
|
|
98
|
+
return config;
|
|
99
|
+
}
|
|
100
|
+
export function defineEmailConfig(config) {
|
|
101
|
+
return config;
|
|
102
|
+
}
|
|
103
|
+
export function defineEmail(config) {
|
|
104
|
+
return config;
|
|
105
|
+
}
|
|
106
|
+
export function defineGit(config) {
|
|
107
|
+
return config;
|
|
108
|
+
}
|
|
109
|
+
export function defineHashing(config) {
|
|
110
|
+
return config;
|
|
111
|
+
}
|
|
112
|
+
export function defineLibrary(config) {
|
|
113
|
+
return config;
|
|
114
|
+
}
|
|
115
|
+
export function defineNotification(config) {
|
|
116
|
+
return config;
|
|
117
|
+
}
|
|
118
|
+
export function definePayment(config) {
|
|
119
|
+
return config;
|
|
120
|
+
}
|
|
121
|
+
export function defineQueue(config) {
|
|
122
|
+
return config;
|
|
123
|
+
}
|
|
124
|
+
export function defineSearchEngine(config) {
|
|
125
|
+
return config;
|
|
126
|
+
}
|
|
127
|
+
export function defineSecurity(config) {
|
|
128
|
+
return config;
|
|
129
|
+
}
|
|
130
|
+
export function defineServices(config) {
|
|
131
|
+
return config;
|
|
132
|
+
}
|
|
133
|
+
export function defineSms(config) {
|
|
134
|
+
return config;
|
|
135
|
+
}
|
|
136
|
+
export function defineStorage(config) {
|
|
137
|
+
return config;
|
|
138
|
+
}
|
|
139
|
+
export function defineFilesystems(config) {
|
|
140
|
+
return config;
|
|
141
|
+
}
|
|
142
|
+
export function defineFeatureFlags(config) {
|
|
143
|
+
return config;
|
|
144
|
+
}
|
|
145
|
+
export function defineUi(config) {
|
|
146
|
+
return config;
|
|
147
|
+
}
|
|
148
|
+
export function defineModel(config) {
|
|
149
|
+
return config;
|
|
150
|
+
}
|
|
151
|
+
export function defineEvents(config) {
|
|
152
|
+
return config;
|
|
153
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
`,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:
|
|
6
|
-
`,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}},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:B.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:B.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"}}}};function m(x){return typeof x==="object"&&x!==null&&!Array.isArray(x)}function _(x,X){return(G,z)=>{if(G==null)return[];let J=null;if(typeof G==="number"&&Number.isInteger(G))J=G;else if(typeof G==="string"&&/^-?\d+$/.test(G))J=Number.parseInt(G,10);if(J===null)return[{path:z,message:`expected integer, got ${typeof G} (${JSON.stringify(G)})`}];if(J<x||J>X)return[{path:z,message:`expected integer in [${x}, ${X}], got ${J}`}];return[]}}function j(x){return(X,G)=>{if(X==null)return[];if(typeof X!=="string"||!x.includes(X))return[{path:G,message:`expected one of [${x.join(", ")}], got ${JSON.stringify(X)}`}];return[]}}function T(){return(x,X)=>{if(x==null)return[];return typeof x==="string"?[]:[{path:X,message:`expected string, got ${typeof x}`}]}}function O(){return(x,X)=>{if(x==null)return[];return typeof x==="boolean"?[]:[{path:X,message:`expected boolean, got ${typeof x}`}]}}var q=_(1,65535),R={app:{rules:{name:T(),env:j(["local","development","staging","production","test"]),debug:O(),url:T()}},ports:{rules:{frontend:q,api:q,admin:q,docs:q,systemTray:q,desktop:q}},database:{rules:{default:j(["sqlite","mysql","singlestore","postgres","dynamodb"])}},cache:{rules:{driver:j(["memory","redis","singlestore"])}},queue:{rules:{default:j(["sync","database","redis"])}},logging:{rules:{level:j(["trace","debug","info","warn","error","fatal"])}},email:{rules:{default:j(["ses","sendgrid","mailgun","mailtrap","smtp","log","capture"])}}};function w(x){let X=[];for(let[G,z]of Object.entries(R)){let J=x[G];if(J==null)continue;if(!m(J)){X.push({path:G,message:`expected object, got ${typeof J}`});continue}for(let[Q,I]of Object.entries(z.rules)){let Z=J[Q];X.push(...I(Z,`${G}.${Q}`))}}return X}var k=process.env.SKIP_CONFIG_LOADING==="true",E=process.env.SKIP_CONFIG_VALIDATION==="true",Y=Symbol.for("@stacksjs/config:overrides"),b=Symbol.for("@stacksjs/config:overridesReady");function h(){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:{},git:{},hashing:{},library:{},logging:{},marketing:{},monitoring:{},notification:{},queue:{},payment:{},ports:{},saas:{},searchEngine:{},security:{},services:{},filesystems:{},team:{},ui:{}}}var W=globalThis,d=W[Y],$=d??(()=>{let x=h();return W[Y]=x,x})(),p=[["ai","~/config/ai"],["analytics","~/config/analytics"],["app","~/config/app"],["auth","~/config/auth"],["cache","~/config/cache"],["cli","~/config/cli"],["cloud","~/config/cloud"],["cms","~/config/cms"],["commerce","~/config/commerce"],["dashboard","~/config/dashboard"],["database","~/config/database"],["dns","~/config/dns"],["email","~/config/email"],["errors","~/config/errors"],["git","~/config/git"],["hashing","~/config/hashing"],["library","~/config/library"],["logging","~/config/logging"],["marketing","~/config/marketing"],["monitoring","~/config/monitoring"],["notification","~/config/notification"],["payment","~/config/payment"],["ports","~/config/ports"],["queue","~/config/queue"],["realtime","~/config/realtime"],["saas","~/config/saas"],["searchEngine","~/config/search-engine"],["security","~/config/security"],["services","~/config/services"],["filesystems","~/config/filesystems"],["team","~/config/team"],["ui","~/config/ui"]],t=W[b],F=t??(()=>{let x=k?Promise.resolve($):Promise.all(p.map(async([X,G])=>{try{let z=await import(G);if(z?.default!==void 0)$[X]=z.default}catch(z){let J=z?.code,Q=z?.message??String(z);if(!(J==="ERR_MODULE_NOT_FOUND"||J==="MODULE_NOT_FOUND"||/Cannot find module/i.test(Q)))console.warn(`[config] Failed to load ${String(X)} config from ${G}: ${Q}`)}})).then(()=>{if(!E){let X=w($);if(X.length>0){console.error("[config] Configuration issues detected:");for(let z of X)console.error(` \u2022 ${z.path}: ${z.message}`);let G=X.map((z)=>` \u2022 ${z.path}: ${z.message}`).join(`
|
|
7
|
-
`);throw Error(`[config] ${X.length} configuration issue(s) detected at boot:
|
|
8
|
-
${G}
|
|
9
|
-
Set SKIP_CONFIG_VALIDATION=true to bypass (e.g. when running migrations against partial config).`)}}return $});return W[b]=x,x})();async function Ax(x={}){let X=x.domain??N.app.url??"stacks",G=x.type??"frontend",z=x.localhost??!1,J=x.https,Q=x.network,I=X.replace(/\.[^.]+$/,".localhost");async function Z(A){let{createLocalTunnel:K}=await import("@stacksjs/tunnel");return K(A)}switch(G){case"frontend":if(Q)return await Z(N.ports?.frontend||3000);if(z)return`http://localhost:${N.ports?.frontend}`;break;case"backend":if(Q)return await Z(N.ports?.backend||3001);if(z)return`http://localhost:${N.ports?.backend}`;I=`api.${I}`;break;case"admin":if(Q)return await Z(N.ports?.admin||3002);if(z)return`http://localhost:${N.ports?.admin}`;I=`admin.${I}`;break;case"library":if(Q)return await Z(N.ports?.library||3003);if(z)return`http://localhost:${N.ports?.library}`;I=`libs.${I}`;break;case"email":if(Q)return await Z(N.ports?.email||3005);if(z)return`http://localhost:${N.ports?.email}`;I=`email.${I}`;break;case"desktop":if(Q)return await Z(N.ports?.desktop||3004);if(z)return`http://localhost:${N.ports?.desktop}`;I=`desktop.${I}`;break;case"docs":if(Q)return await Z(N.ports?.docs||3006);if(z)return`http://localhost:${N.ports?.docs}`;I=`docs.${I}`;break;case"inspect":if(Q)return await Z(N.ports?.inspect||3007);if(z)return`http://localhost:${N.ports?.inspect}`;I=`inspect.${I}`;break;default:if(z)return`http://localhost:${N.ports?.frontend}`}if(J)return`https://${I}`;return`http://${I}`}function Kx(x){return x}function Px(x){return x}function Cx(x){return x}function Sx(x){return x}function Dx(x){return x}function mx(x){return x}function _x(x){return x}function Ox(x){return x}function Rx(x){return x}function kx(x){return x}function Ex(x){return x}function hx(x){return x}function dx(x){return x}function px(x){return x}function tx(x){return x}function vx(x){return x}function rx(x){return x}function ux(x){return x}function sx(x){return x}function ax(x){return x}function lx(x){return x}function fx(x){return x}function gx(x){return x}function ex(x){return x}function cx(x){return x}function nx(x){return x}function y(x){let X=$[x];if(X!==void 0&&(typeof X!=="object"||Object.keys(X).length>0))return X;return U[x]}var v=function(){},N=new Proxy(v,{get(x,X){return y(X)},has(x,X){return X in $||X in U},ownKeys(){return Array.from(new Set([...Object.keys($),...Object.keys(U)]))},getOwnPropertyDescriptor(x,X){if(typeof X!=="string")return;if(!(X in $)&&!(X in U))return;return{enumerable:!0,configurable:!0,writable:!0,value:y(X)}},isExtensible(){return!0},preventExtensions(){return!1}});async function NN(){return await F,N}var L=Symbol.for("@stacksjs/config:databaseReady"),V=globalThis;async function XN(){await F;let x=Date.now()+5000;while(!V[L]&&Date.now()<x)await new Promise((X)=>setTimeout(X,25));if(!V[L])console.warn("[config] awaitDatabaseConfig() timed out \u2014 database driver did not signal readiness within 5s");return N}function zN(){V[L]=!0}function GN(){return N}var{ai:r,analytics:u,app:s,auth:a,realtime:l,cache:f,cloud:g,cli:e,dashboard:c,database:n,dns:i,docs:o,email:xx,errors:Nx,git:Xx,hashing:zx,library:Gx,logging:Ix,notification:Jx,payment:Qx,ports:Zx,queue:$x,security:jx,saas:qx,searchEngine:Bx,services:Ux,filesystems:Wx,team:Fx,ui:Mx}=N;F.then(()=>{r=N.ai,u=N.analytics,s=N.app,a=N.auth,l=N.realtime,f=N.cache,g=N.cloud,e=N.cli,c=N.dashboard,n=N.database,i=N.dns,o=N.docs,xx=N.email,Nx=N.errors,Xx=N.git,zx=N.hashing,Gx=N.library,Ix=N.logging,Jx=N.notification,Qx=N.payment,Zx=N.ports,$x=N.queue,jx=N.security,qx=N.saas,Bx=N.searchEngine,Ux=N.services,Wx=N.filesystems,Fx=N.team,Mx=N.ui}).catch(()=>{});function IN(){let x=N.app?.env;if(x==="local"||x==="development")return"dev";if(x==="staging")return"stage";if(x==="production")return"prod";if(!x)throw Error("Couldn't determine app environment");return x}export{UN as validateConfig,Mx as ui,Fx as team,Ux as services,jx as security,Bx as searchEngine,qx as saas,HN as resetFeature,WN as reportConfigIssues,l as realtime,$x as queue,Zx as ports,Qx as payment,F as overridesReady,$ as overrides,Jx as notification,zN as markDatabaseReady,Ix as logging,Ax as localUrl,TN as listFeatures,Gx as library,zx as hashing,Xx as git,GN as getConfig,Wx as filesystems,MN as feature,Nx as errors,LN as enableFeature,xx as email,o as docs,i as dns,VN as disableFeature,IN as determineAppEnv,ex as defineUi,fx as defineStorage,Kx as defineStacksConfig,lx as defineSms,ax as defineServices,sx as defineSecurity,ux as defineSearchEngine,rx as defineQueue,vx as definePayment,tx as defineNotification,cx as defineModel,px as defineLibrary,dx as defineHashing,hx as defineGit,gx as defineFilesystems,nx as defineEvents,kx as defineEmailConfig,Ex as defineEmail,Rx as defineDns,Ox as defineDependencies,_x as defineDatabase,mx as defineCli,Dx as defineChat,Sx as defineCdn,Cx as defineCache,Px as defineApp,U as defaults,n as database,c as dashboard,N as config,g as cloud,e as cli,f as cache,XN as awaitDatabaseConfig,NN as awaitConfig,a as auth,s as app,u as analytics,r as ai,qN as FRAMEWORK_DEFAULTS};
|
|
1
|
+
export * from "./config";
|
|
2
|
+
export { FRAMEWORK_DEFAULTS } from "./defaults";
|
|
3
|
+
export { validateConfig, reportConfigIssues } from "./validators";
|
|
4
|
+
export { feature, enableFeature, disableFeature, resetFeature, listFeatures } from "./features";
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { validateConfig } from "./validators";
|
|
2
|
+
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");
|
|
3
|
+
function defaultsForOverrides() {
|
|
4
|
+
return {
|
|
5
|
+
ai: {},
|
|
6
|
+
analytics: {},
|
|
7
|
+
app: { name: process.env.APP_NAME || "Stacks", env: process.env.APP_ENV || "production" },
|
|
8
|
+
auth: {},
|
|
9
|
+
cache: {},
|
|
10
|
+
cli: {},
|
|
11
|
+
cloud: {},
|
|
12
|
+
cms: {},
|
|
13
|
+
commerce: {},
|
|
14
|
+
dashboard: {},
|
|
15
|
+
database: {},
|
|
16
|
+
dns: {},
|
|
17
|
+
realtime: {},
|
|
18
|
+
email: {},
|
|
19
|
+
errors: {},
|
|
20
|
+
featureFlags: {},
|
|
21
|
+
git: {},
|
|
22
|
+
hashing: {},
|
|
23
|
+
library: {},
|
|
24
|
+
logging: {},
|
|
25
|
+
marketing: {},
|
|
26
|
+
monitoring: {},
|
|
27
|
+
notification: {},
|
|
28
|
+
queue: {},
|
|
29
|
+
payment: {},
|
|
30
|
+
ports: {},
|
|
31
|
+
saas: {},
|
|
32
|
+
searchEngine: {},
|
|
33
|
+
security: {},
|
|
34
|
+
services: {},
|
|
35
|
+
filesystems: {},
|
|
36
|
+
team: {},
|
|
37
|
+
ui: {}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const globalScope = globalThis, sharedOverrides = globalScope[OVERRIDES_KEY];
|
|
41
|
+
export const overrides = sharedOverrides ?? (() => {
|
|
42
|
+
const created = defaultsForOverrides();
|
|
43
|
+
globalScope[OVERRIDES_KEY] = created;
|
|
44
|
+
return created;
|
|
45
|
+
})();
|
|
46
|
+
const userConfigs = [
|
|
47
|
+
["ai", "~/config/ai"],
|
|
48
|
+
["analytics", "~/config/analytics"],
|
|
49
|
+
["app", "~/config/app"],
|
|
50
|
+
["auth", "~/config/auth"],
|
|
51
|
+
["cache", "~/config/cache"],
|
|
52
|
+
["cli", "~/config/cli"],
|
|
53
|
+
["cloud", "~/config/cloud"],
|
|
54
|
+
["cms", "~/config/cms"],
|
|
55
|
+
["commerce", "~/config/commerce"],
|
|
56
|
+
["dashboard", "~/config/dashboard"],
|
|
57
|
+
["database", "~/config/database"],
|
|
58
|
+
["dns", "~/config/dns"],
|
|
59
|
+
["email", "~/config/email"],
|
|
60
|
+
["errors", "~/config/errors"],
|
|
61
|
+
["featureFlags", "~/config/feature-flags"],
|
|
62
|
+
["git", "~/config/git"],
|
|
63
|
+
["hashing", "~/config/hashing"],
|
|
64
|
+
["library", "~/config/library"],
|
|
65
|
+
["logging", "~/config/logging"],
|
|
66
|
+
["marketing", "~/config/marketing"],
|
|
67
|
+
["monitoring", "~/config/monitoring"],
|
|
68
|
+
["notification", "~/config/notification"],
|
|
69
|
+
["payment", "~/config/payment"],
|
|
70
|
+
["ports", "~/config/ports"],
|
|
71
|
+
["queue", "~/config/queue"],
|
|
72
|
+
["realtime", "~/config/realtime"],
|
|
73
|
+
["saas", "~/config/saas"],
|
|
74
|
+
["searchEngine", "~/config/search-engine"],
|
|
75
|
+
["security", "~/config/security"],
|
|
76
|
+
["services", "~/config/services"],
|
|
77
|
+
["filesystems", "~/config/filesystems"],
|
|
78
|
+
["team", "~/config/team"],
|
|
79
|
+
["ui", "~/config/ui"]
|
|
80
|
+
], sharedReady = globalScope[READY_KEY];
|
|
81
|
+
export const overridesReady = sharedReady ?? (() => {
|
|
82
|
+
const promise = skipConfigLoading ? Promise.resolve(overrides) : Promise.all(userConfigs.map(async ([key, modulePath]) => {
|
|
83
|
+
try {
|
|
84
|
+
const mod = await import(modulePath);
|
|
85
|
+
if (mod?.default !== void 0)
|
|
86
|
+
overrides[key] = mod.default;
|
|
87
|
+
} catch (err) {
|
|
88
|
+
const code = err?.code, msg = err?.message ?? String(err);
|
|
89
|
+
if (!(code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND" || /Cannot find module/i.test(msg)))
|
|
90
|
+
console.warn(`[config] Failed to load ${String(key)} config from ${modulePath}: ${msg}`);
|
|
91
|
+
}
|
|
92
|
+
})).then(() => {
|
|
93
|
+
if (!skipConfigValidation) {
|
|
94
|
+
const issues = validateConfig(overrides);
|
|
95
|
+
if (issues.length > 0) {
|
|
96
|
+
console.error("[config] Configuration issues detected:");
|
|
97
|
+
for (const issue of issues)
|
|
98
|
+
console.error(` \u2022 ${issue.path}: ${issue.message}`);
|
|
99
|
+
const summary = issues.map((i) => ` \u2022 ${i.path}: ${i.message}`).join(`
|
|
100
|
+
`);
|
|
101
|
+
throw Error(`[config] ${issues.length} configuration issue(s) detected at boot:
|
|
102
|
+
${summary}
|
|
103
|
+
Set SKIP_CONFIG_VALIDATION=true to bypass (e.g. when running migrations against partial config).`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return overrides;
|
|
107
|
+
});
|
|
108
|
+
globalScope[READY_KEY] = promise;
|
|
109
|
+
return promise;
|
|
110
|
+
})();
|
|
111
|
+
export default overrides;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
function isPlainObject(v) {
|
|
2
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3
|
+
}
|
|
4
|
+
function checkInteger(min, max) {
|
|
5
|
+
return (value, path) => {
|
|
6
|
+
if (value == null)
|
|
7
|
+
return [];
|
|
8
|
+
let num = null;
|
|
9
|
+
if (typeof value === "number" && Number.isInteger(value))
|
|
10
|
+
num = value;
|
|
11
|
+
else if (typeof value === "string" && /^-?\d+$/.test(value))
|
|
12
|
+
num = Number.parseInt(value, 10);
|
|
13
|
+
if (num === null)
|
|
14
|
+
return [{ path, message: `expected integer, got ${typeof value} (${JSON.stringify(value)})` }];
|
|
15
|
+
if (num < min || num > max)
|
|
16
|
+
return [{ path, message: `expected integer in [${min}, ${max}], got ${num}` }];
|
|
17
|
+
return [];
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function checkOneOf(values) {
|
|
21
|
+
return (value, path) => {
|
|
22
|
+
if (value == null)
|
|
23
|
+
return [];
|
|
24
|
+
if (typeof value !== "string" || !values.includes(value))
|
|
25
|
+
return [{ path, message: `expected one of [${values.join(", ")}], got ${JSON.stringify(value)}` }];
|
|
26
|
+
return [];
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function checkString() {
|
|
30
|
+
return (value, path) => {
|
|
31
|
+
if (value == null)
|
|
32
|
+
return [];
|
|
33
|
+
return typeof value === "string" ? [] : [{ path, message: `expected string, got ${typeof value}` }];
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function checkBoolean() {
|
|
37
|
+
return (value, path) => {
|
|
38
|
+
if (value == null)
|
|
39
|
+
return [];
|
|
40
|
+
return typeof value === "boolean" ? [] : [{ path, message: `expected boolean, got ${typeof value}` }];
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const PORT_CHECK = checkInteger(1, 65535), SCHEMA = {
|
|
44
|
+
app: {
|
|
45
|
+
rules: {
|
|
46
|
+
name: checkString(),
|
|
47
|
+
env: checkOneOf(["local", "development", "staging", "production", "test"]),
|
|
48
|
+
debug: checkBoolean(),
|
|
49
|
+
url: checkString()
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
ports: {
|
|
53
|
+
rules: {
|
|
54
|
+
frontend: PORT_CHECK,
|
|
55
|
+
api: PORT_CHECK,
|
|
56
|
+
admin: PORT_CHECK,
|
|
57
|
+
docs: PORT_CHECK,
|
|
58
|
+
systemTray: PORT_CHECK,
|
|
59
|
+
desktop: PORT_CHECK
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
database: {
|
|
63
|
+
rules: {
|
|
64
|
+
default: checkOneOf(["sqlite", "mysql", "singlestore", "postgres", "dynamodb"])
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
cache: {
|
|
68
|
+
rules: {
|
|
69
|
+
driver: checkOneOf(["memory", "redis", "singlestore"])
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
featureFlags: {
|
|
73
|
+
rules: {
|
|
74
|
+
default: checkOneOf(["memory", "database"]),
|
|
75
|
+
missing: checkOneOf(["false", "throw"])
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
queue: {
|
|
79
|
+
rules: {
|
|
80
|
+
default: checkOneOf(["sync", "database", "redis"])
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
logging: {
|
|
84
|
+
rules: {
|
|
85
|
+
level: checkOneOf(["trace", "debug", "info", "warn", "error", "fatal"])
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
email: {
|
|
89
|
+
rules: {
|
|
90
|
+
default: checkOneOf(["ses", "sendgrid", "mailgun", "mailtrap", "smtp", "log", "capture"])
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
export function validateConfig(config) {
|
|
95
|
+
const issues = [];
|
|
96
|
+
for (const [section, schema] of Object.entries(SCHEMA)) {
|
|
97
|
+
const sectionValue = config[section];
|
|
98
|
+
if (sectionValue == null)
|
|
99
|
+
continue;
|
|
100
|
+
if (!isPlainObject(sectionValue)) {
|
|
101
|
+
issues.push({ path: section, message: `expected object, got ${typeof sectionValue}` });
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
for (const [field, check] of Object.entries(schema.rules)) {
|
|
105
|
+
const v = sectionValue[field];
|
|
106
|
+
issues.push(...check(v, `${section}.${field}`));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return issues;
|
|
110
|
+
}
|
|
111
|
+
export function reportConfigIssues(config) {
|
|
112
|
+
const issues = validateConfig(config);
|
|
113
|
+
if (issues.length === 0)
|
|
114
|
+
return !0;
|
|
115
|
+
console.warn("[config] Configuration issues detected:");
|
|
116
|
+
for (const issue of issues)
|
|
117
|
+
console.warn(` \u2022 ${issue.path}: ${issue.message}`);
|
|
118
|
+
return !1;
|
|
119
|
+
}
|
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.
|
|
5
|
+
"version": "0.70.90",
|
|
6
6
|
"description": "The Stacks config helper methods.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"ts-pantry": "^0.10.11"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@stacksjs/alias": "0.70.
|
|
56
|
+
"@stacksjs/alias": "0.70.90",
|
|
57
57
|
"better-dx": "^0.2.16",
|
|
58
|
-
"@stacksjs/types": "0.70.
|
|
58
|
+
"@stacksjs/types": "0.70.90",
|
|
59
59
|
"bunfig": "^0.15.11"
|
|
60
60
|
}
|
|
61
61
|
}
|