@nymbalhq/config 1.0.0 → 1.2.0
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/index.d.ts +1051 -48
- package/dist/index.js +193 -44
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
package/dist/index.js
CHANGED
|
@@ -49,6 +49,15 @@ var KNOWN_PROVIDERS = {
|
|
|
49
49
|
ai: ["none", "anthropic", "custom"]
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
// src/known-infrastructure.ts
|
|
53
|
+
var KNOWN_INFRASTRUCTURE = {
|
|
54
|
+
commandStore: ["sqlite", "postgres"],
|
|
55
|
+
documentStore: ["in-memory", "redis", "postgres-jsonb"],
|
|
56
|
+
eventBus: ["in-process", "redis-streams"],
|
|
57
|
+
media: ["local-fs", "s3"]
|
|
58
|
+
};
|
|
59
|
+
var REMOVED_INFRASTRUCTURE_KEYS = ["cloud", "compute"];
|
|
60
|
+
|
|
52
61
|
// src/load.ts
|
|
53
62
|
import { existsSync } from "fs";
|
|
54
63
|
import { dirname, isAbsolute, resolve } from "path";
|
|
@@ -72,14 +81,101 @@ var storeSchema = z.object({
|
|
|
72
81
|
locale: z.string().min(2),
|
|
73
82
|
timezone: z.string().min(1)
|
|
74
83
|
});
|
|
75
|
-
var
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
var quotedList = (values) => values.map((v) => `'${v}'`).join(", ");
|
|
85
|
+
function infrastructureValue(slot, values) {
|
|
86
|
+
return z.enum(values, {
|
|
87
|
+
errorMap: (issue, ctx) => issue.code === z.ZodIssueCode.invalid_enum_value ? {
|
|
88
|
+
message: `unknown ${slot} '${String(issue.received)}'; the ${slot} values are ${quotedList(values)}`
|
|
89
|
+
} : { message: ctx.defaultError }
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
var INFRASTRUCTURE_KEYS = [...Object.keys(KNOWN_INFRASTRUCTURE), "redis", "s3"];
|
|
93
|
+
function unrecognizedInfrastructureKeys(keys) {
|
|
94
|
+
return keys.map(
|
|
95
|
+
(key) => REMOVED_INFRASTRUCTURE_KEYS.includes(key) ? `infrastructure.${key} was removed: it drives nothing, so delete it from the config` : `unknown infrastructure key '${key}'; the infrastructure keys are ${quotedList(INFRASTRUCTURE_KEYS)}`
|
|
96
|
+
).join("; ");
|
|
97
|
+
}
|
|
98
|
+
var redisSchema = z.object({
|
|
99
|
+
/** Defaults to `REDIS_URL`. */
|
|
100
|
+
url: z.string().min(1).optional(),
|
|
101
|
+
/** Namespaces every key and stream; defaults to `NYMBAL_REDIS_PREFIX`, then `'nymbal'`. */
|
|
102
|
+
prefix: z.string().min(1).optional(),
|
|
103
|
+
/** How long a publish waits for the groups it delivers to (default 15 000). */
|
|
104
|
+
ackTimeoutMs: z.number().int().positive().optional(),
|
|
105
|
+
/** How long an entry may stay pending on a consumer before a live one takes it over (default 5 000). */
|
|
106
|
+
claimIdleMs: z.number().int().positive().optional(),
|
|
107
|
+
/** The approximate length each stream is trimmed to (default 10 000). */
|
|
108
|
+
streamMaxLen: z.number().int().positive().optional()
|
|
109
|
+
}).strict();
|
|
110
|
+
var S3_KEYS = ["bucket", "region", "endpoint", "prefix", "publicUrl", "forcePathStyle"];
|
|
111
|
+
var s3Schema = z.object(
|
|
112
|
+
{
|
|
113
|
+
/** Defaults to `S3_BUCKET`; one of the two is required. */
|
|
114
|
+
bucket: z.string().min(1).optional(),
|
|
115
|
+
/** Defaults to `AWS_REGION`, then `'us-east-1'`. */
|
|
116
|
+
region: z.string().min(1).optional(),
|
|
117
|
+
/** An S3-compatible API (MinIO, R2); defaults to `S3_ENDPOINT`, then AWS. */
|
|
118
|
+
endpoint: z.string().min(1).optional(),
|
|
119
|
+
/** Where every object key starts; defaults to `NYMBAL_S3_PREFIX`, then none. */
|
|
120
|
+
prefix: z.string().optional(),
|
|
121
|
+
/** Where the bucket's objects are served from (a CDN); defaults to `S3_PUBLIC_URL`, then the bucket's own URL. */
|
|
122
|
+
publicUrl: z.string().min(1).optional(),
|
|
123
|
+
/** Path-style requests; true by default when an endpoint is set. */
|
|
124
|
+
forcePathStyle: z.boolean().optional()
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
errorMap: (issue, ctx) => issue.code === z.ZodIssueCode.unrecognized_keys ? {
|
|
128
|
+
message: `unknown infrastructure.s3 key${issue.keys.length > 1 ? "s" : ""} ${quotedList(issue.keys)}; the s3 keys are ${quotedList(S3_KEYS)}, and credentials come from the AWS SDK (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, a profile or a role), never the config`
|
|
129
|
+
} : { message: ctx.defaultError }
|
|
130
|
+
}
|
|
131
|
+
).strict();
|
|
132
|
+
var infrastructureSchema = z.object(
|
|
133
|
+
{
|
|
134
|
+
commandStore: infrastructureValue("commandStore", KNOWN_INFRASTRUCTURE.commandStore),
|
|
135
|
+
documentStore: infrastructureValue("documentStore", KNOWN_INFRASTRUCTURE.documentStore),
|
|
136
|
+
eventBus: infrastructureValue("eventBus", KNOWN_INFRASTRUCTURE.eventBus),
|
|
137
|
+
media: infrastructureValue("media", KNOWN_INFRASTRUCTURE.media).default("local-fs"),
|
|
138
|
+
redis: redisSchema.optional(),
|
|
139
|
+
s3: s3Schema.optional()
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
errorMap: (issue, ctx) => issue.code === z.ZodIssueCode.unrecognized_keys ? { message: unrecognizedInfrastructureKeys(issue.keys) } : { message: ctx.defaultError }
|
|
143
|
+
}
|
|
144
|
+
).strict().superRefine((infra, ctx) => {
|
|
145
|
+
if (infra.documentStore === "postgres-jsonb" && infra.commandStore !== "postgres") {
|
|
146
|
+
ctx.addIssue({
|
|
147
|
+
code: z.ZodIssueCode.custom,
|
|
148
|
+
path: ["documentStore"],
|
|
149
|
+
message: `documentStore 'postgres-jsonb' shares the command store's Postgres connection, so it needs commandStore 'postgres' (not '${infra.commandStore}')`
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
if (infra.eventBus === "redis-streams" && infra.documentStore === "in-memory") {
|
|
153
|
+
ctx.addIssue({
|
|
154
|
+
code: z.ZodIssueCode.custom,
|
|
155
|
+
path: ["eventBus"],
|
|
156
|
+
message: `eventBus 'redis-streams' needs a shared documentStore ('redis' or 'postgres-jsonb'), not 'in-memory': a named group hands each event to one instance, so a per-process read model would miss the rest`
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (infra.s3 !== void 0 && infra.media !== "s3") {
|
|
160
|
+
ctx.addIssue({
|
|
161
|
+
code: z.ZodIssueCode.custom,
|
|
162
|
+
path: ["s3"],
|
|
163
|
+
message: `infrastructure.s3 configures media 's3', but media is '${infra.media}': set media to 's3' or delete the s3 block`
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
var cloudflareSchema = z.object({
|
|
168
|
+
zoneId: z.string().optional(),
|
|
169
|
+
apiToken: z.string().optional(),
|
|
170
|
+
/** The Cloudflare v4 API; the adapter defaults it to https://api.cloudflare.com/client/v4. */
|
|
171
|
+
apiBase: z.string().url().optional()
|
|
172
|
+
});
|
|
173
|
+
var customRuleSchema = z.object({
|
|
174
|
+
name: z.string().min(1),
|
|
175
|
+
expression: z.string().min(1),
|
|
176
|
+
action: z.enum(["block", "managed_challenge", "js_challenge", "log"])
|
|
81
177
|
});
|
|
82
|
-
var
|
|
178
|
+
var securityFields = z.object({
|
|
83
179
|
adapter: z.enum(["middleware", "cloudflare", "aws-waf", "akamai"]),
|
|
84
180
|
rateLimit: z.record(
|
|
85
181
|
z.string().regex(rateLimitPathPattern, {
|
|
@@ -102,8 +198,39 @@ var securitySchema = z.object({
|
|
|
102
198
|
jwtSecret: z.string().min(16).default(DEFAULT_JWT_SECRET),
|
|
103
199
|
accessTtl: z.string().regex(/^\d+(ms|s|m|h|d)$/, 'TTL must look like "15m"').default("15m"),
|
|
104
200
|
refreshTtl: z.string().regex(/^\d+(ms|s|m|h|d)$/, 'TTL must look like "7d"').default("7d")
|
|
105
|
-
}).default({})
|
|
201
|
+
}).default({}),
|
|
202
|
+
cloudflare: cloudflareSchema.optional(),
|
|
203
|
+
geo: z.object({
|
|
204
|
+
block: z.array(z.string().regex(/^[A-Z]{2}$/, 'geo.block codes are ISO 3166 alpha-2, like "RU"')).default([])
|
|
205
|
+
}).default({ block: [] }),
|
|
206
|
+
customRules: z.array(customRuleSchema).default([]),
|
|
207
|
+
managedRulesets: z.array(z.enum(["cloudflare", "owasp"])).default([])
|
|
106
208
|
});
|
|
209
|
+
var securitySchema = securityFields.superRefine((security, ctx) => {
|
|
210
|
+
if (security.adapter === "cloudflare") {
|
|
211
|
+
for (const field of ["zoneId", "apiToken"]) {
|
|
212
|
+
if (!security.cloudflare?.[field]) {
|
|
213
|
+
ctx.addIssue({
|
|
214
|
+
code: z.ZodIssueCode.custom,
|
|
215
|
+
path: ["cloudflare", field],
|
|
216
|
+
message: `security.adapter 'cloudflare' needs security.cloudflare.${field}`
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const seen = /* @__PURE__ */ new Set();
|
|
222
|
+
security.customRules.forEach((rule, i) => {
|
|
223
|
+
if (seen.has(rule.name)) {
|
|
224
|
+
ctx.addIssue({
|
|
225
|
+
code: z.ZodIssueCode.custom,
|
|
226
|
+
path: ["customRules", i, "name"],
|
|
227
|
+
message: `customRules has two rules named '${rule.name}'; names must be unique`
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
seen.add(rule.name);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
var NPM_PACKAGE_NAME = /^(?:@[a-z0-9~-][a-z0-9._~-]*\/)?[a-z0-9~-][a-z0-9._~-]*$/;
|
|
107
234
|
function adapterBlock(slot, providers) {
|
|
108
235
|
const known = providers.map((p) => `'${p}'`).join(", ");
|
|
109
236
|
return z.object({
|
|
@@ -112,7 +239,9 @@ function adapterBlock(slot, providers) {
|
|
|
112
239
|
message: `unknown ${slot} provider '${String(issue.received)}'; the ${slot} providers are ${known}`
|
|
113
240
|
} : { message: ctx.defaultError }
|
|
114
241
|
}),
|
|
115
|
-
config: z.record(z.string(), z.unknown()).optional()
|
|
242
|
+
config: z.record(z.string(), z.unknown()).optional(),
|
|
243
|
+
/** The npm package a `custom` slot's adapter comes from, for tooling (`nymbal test:contracts`); the kernel never reads it. */
|
|
244
|
+
package: z.string().max(214, "an npm package name is at most 214 characters").regex(NPM_PACKAGE_NAME, "must be an npm package name, such as `@acme/nymbal-search`").optional()
|
|
116
245
|
});
|
|
117
246
|
}
|
|
118
247
|
var commerceSchema = z.object({
|
|
@@ -148,6 +277,23 @@ var featuresSchema = z.object({
|
|
|
148
277
|
heartbeat: z.boolean().default(false),
|
|
149
278
|
autoUpdates: z.boolean().default(false)
|
|
150
279
|
});
|
|
280
|
+
var eventArchiveSchema = z.object({
|
|
281
|
+
adapter: z.literal("s3"),
|
|
282
|
+
bucket: z.string().min(1),
|
|
283
|
+
/** Where every archive key starts; none when not given. */
|
|
284
|
+
prefix: z.string().optional(),
|
|
285
|
+
/** `'us-east-1'` when not given. */
|
|
286
|
+
region: z.string().min(1).optional(),
|
|
287
|
+
/** An S3-compatible API (MinIO, R2). */
|
|
288
|
+
endpoint: z.string().min(1).optional(),
|
|
289
|
+
/** Path-style requests; true by default when an endpoint is set. */
|
|
290
|
+
forcePathStyle: z.boolean().optional()
|
|
291
|
+
}).strict();
|
|
292
|
+
var eventsSchema = z.object({
|
|
293
|
+
/** Days a delivered event stays in the log. */
|
|
294
|
+
retentionDays: z.number().int().min(1).default(30),
|
|
295
|
+
archive: eventArchiveSchema.optional()
|
|
296
|
+
}).strict();
|
|
151
297
|
var nymbalConfigSchema = z.object({
|
|
152
298
|
store: storeSchema,
|
|
153
299
|
template: z.enum(["astro", "nextjs"]),
|
|
@@ -160,30 +306,16 @@ var nymbalConfigSchema = z.object({
|
|
|
160
306
|
staging: false,
|
|
161
307
|
heartbeat: false,
|
|
162
308
|
autoUpdates: false
|
|
163
|
-
})
|
|
309
|
+
}),
|
|
310
|
+
events: eventsSchema.default({})
|
|
164
311
|
}).superRefine((cfg, ctx) => {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
if (!["in-process", "redis-streams"].includes(cfg.infrastructure.eventBus)) {
|
|
174
|
-
ctx.addIssue({
|
|
175
|
-
code: z.ZodIssueCode.custom,
|
|
176
|
-
path: ["infrastructure", "eventBus"],
|
|
177
|
-
message: `cloud=local only supports 'in-process' or 'redis-streams' for eventBus`
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
if (!["in-process", "worker-threads"].includes(cfg.infrastructure.compute)) {
|
|
181
|
-
ctx.addIssue({
|
|
182
|
-
code: z.ZodIssueCode.custom,
|
|
183
|
-
path: ["infrastructure", "compute"],
|
|
184
|
-
message: `cloud=local only supports 'in-process' or 'worker-threads' for compute`
|
|
185
|
-
});
|
|
186
|
-
}
|
|
312
|
+
const archiveBucket = cfg.events.archive?.bucket;
|
|
313
|
+
if (archiveBucket !== void 0 && cfg.infrastructure.media === "s3" && archiveBucket === cfg.infrastructure.s3?.bucket) {
|
|
314
|
+
ctx.addIssue({
|
|
315
|
+
code: z.ZodIssueCode.custom,
|
|
316
|
+
path: ["events", "archive", "bucket"],
|
|
317
|
+
message: `events.archive.bucket is infrastructure.s3.bucket ('${archiveBucket}'), the media bucket, which serves its objects publicly; archive events to a private bucket of their own`
|
|
318
|
+
});
|
|
187
319
|
}
|
|
188
320
|
const email = cfg.commerce.email;
|
|
189
321
|
if (email.provider === "native" && email.config?.["transport"] === "smtp") {
|
|
@@ -193,15 +325,6 @@ var nymbalConfigSchema = z.object({
|
|
|
193
325
|
message: `the native email provider only prints to the console; for SMTP mail set email.provider to 'smtp' (@nymbalhq/adapter-smtp)`
|
|
194
326
|
});
|
|
195
327
|
}
|
|
196
|
-
if (cfg.security.adapter === "middleware") {
|
|
197
|
-
if (["aws", "gcp", "azure"].includes(cfg.infrastructure.cloud)) {
|
|
198
|
-
ctx.addIssue({
|
|
199
|
-
code: z.ZodIssueCode.custom,
|
|
200
|
-
path: ["security", "adapter"],
|
|
201
|
-
message: `security.adapter='middleware' is intended for local/docker development. Use a WAF adapter ('cloudflare', 'aws-waf', 'akamai') for cloud=${cfg.infrastructure.cloud}.`
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
328
|
});
|
|
206
329
|
|
|
207
330
|
// src/load.ts
|
|
@@ -225,18 +348,20 @@ async function loadConfig(startDir = process.cwd()) {
|
|
|
225
348
|
);
|
|
226
349
|
}
|
|
227
350
|
const jiti = createJiti(pathToFileURL(path).href, { interopDefault: true });
|
|
228
|
-
let
|
|
351
|
+
let mod;
|
|
229
352
|
try {
|
|
230
|
-
|
|
353
|
+
mod = await jiti.import(path);
|
|
231
354
|
} catch (err) {
|
|
232
355
|
throw new ConfigError2(`Failed to load ${path}: ${err.message}`, {
|
|
233
356
|
cause: err,
|
|
234
357
|
context: { path }
|
|
235
358
|
});
|
|
236
359
|
}
|
|
360
|
+
const raw = mod["default"] ?? mod;
|
|
361
|
+
const adapters = adaptersExport(mod["adapters"], path);
|
|
237
362
|
try {
|
|
238
363
|
const config = nymbalConfigSchema.parse(raw);
|
|
239
|
-
return { config, path, projectRoot: dirname(path) };
|
|
364
|
+
return { config, path, projectRoot: dirname(path), ...adapters !== void 0 && { adapters } };
|
|
240
365
|
} catch (err) {
|
|
241
366
|
if (err instanceof z2.ZodError) {
|
|
242
367
|
throw new ConfigError2(formatZodError(err, path), {
|
|
@@ -247,6 +372,24 @@ async function loadConfig(startDir = process.cwd()) {
|
|
|
247
372
|
throw err;
|
|
248
373
|
}
|
|
249
374
|
}
|
|
375
|
+
function adaptersExport(value, path) {
|
|
376
|
+
if (value === void 0) return void 0;
|
|
377
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
378
|
+
throw new ConfigError2(`${path}: the adapters export must be an object keyed by commerce slot`, {
|
|
379
|
+
code: "config.adapters_invalid",
|
|
380
|
+
context: { path }
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
const slots = Object.keys(KNOWN_PROVIDERS);
|
|
384
|
+
const unknown = Object.keys(value).filter((key) => !slots.includes(key));
|
|
385
|
+
if (unknown.length > 0) {
|
|
386
|
+
throw new ConfigError2(
|
|
387
|
+
`${path}: the adapters export names ${unknown.join(", ")}, which is no commerce slot (${slots.join(", ")})`,
|
|
388
|
+
{ code: "config.adapters_invalid", context: { path, unknown } }
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
return value;
|
|
392
|
+
}
|
|
250
393
|
function formatZodError(err, path) {
|
|
251
394
|
const lines = err.issues.map((issue) => {
|
|
252
395
|
const at = issue.path.length > 0 ? issue.path.join(".") : "<root>";
|
|
@@ -257,7 +400,9 @@ ${lines.join("\n")}`;
|
|
|
257
400
|
}
|
|
258
401
|
export {
|
|
259
402
|
DEFAULT_JWT_SECRET,
|
|
403
|
+
KNOWN_INFRASTRUCTURE,
|
|
260
404
|
KNOWN_PROVIDERS,
|
|
405
|
+
REMOVED_INFRASTRUCTURE_KEYS,
|
|
261
406
|
commerceSchema,
|
|
262
407
|
defineConfig,
|
|
263
408
|
deploymentSchema,
|
|
@@ -265,12 +410,16 @@ export {
|
|
|
265
410
|
envBool,
|
|
266
411
|
envNumber,
|
|
267
412
|
envOptional,
|
|
413
|
+
eventArchiveSchema,
|
|
414
|
+
eventsSchema,
|
|
268
415
|
featuresSchema,
|
|
269
416
|
findConfigFile,
|
|
270
417
|
httpSchema,
|
|
271
418
|
infrastructureSchema,
|
|
272
419
|
loadConfig,
|
|
273
420
|
nymbalConfigSchema,
|
|
421
|
+
redisSchema,
|
|
422
|
+
s3Schema,
|
|
274
423
|
securitySchema,
|
|
275
424
|
storeSchema
|
|
276
425
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/define-config.ts","../src/env.ts","../src/known-providers.ts","../src/load.ts","../src/schema.ts"],"sourcesContent":["import type { NymbalConfigInput } from './schema.js'\n\nexport function defineConfig<T extends NymbalConfigInput>(config: T): T {\n return config\n}\n","import { ConfigError } from '@nymbalhq/types'\n\nexport function env(key: string, defaultValue?: string): string {\n const value = process.env[key]\n if (value !== undefined && value !== '') return value\n if (defaultValue !== undefined) return defaultValue\n throw new ConfigError(`Missing required environment variable: ${key}`, {\n context: { key },\n })\n}\n\nexport function envOptional(key: string): string | undefined {\n const value = process.env[key]\n return value !== undefined && value !== '' ? value : undefined\n}\n\nexport function envNumber(key: string, defaultValue?: number): number {\n const raw = envOptional(key)\n if (raw === undefined) {\n if (defaultValue !== undefined) return defaultValue\n throw new ConfigError(`Missing required environment variable: ${key}`, { context: { key } })\n }\n const parsed = Number(raw)\n if (!Number.isFinite(parsed)) {\n throw new ConfigError(`Environment variable ${key} is not a valid number: ${raw}`, {\n context: { key, raw },\n })\n }\n return parsed\n}\n\nexport function envBool(key: string, defaultValue = false): boolean {\n const raw = envOptional(key)?.toLowerCase()\n if (raw === undefined) return defaultValue\n return raw === 'true' || raw === '1' || raw === 'yes' || raw === 'on'\n}\n","import type { CommerceSlot } from '@nymbalhq/types'\n\nexport type { CommerceSlot }\n\n/**\n * The providers each commerce slot accepts. A provider that needs an SDK lives in an `@nymbalhq/adapter-*` package the\n * kernel loads only when the config names it; `custom` takes the adapter a project passes to `createApp`.\n */\nexport const KNOWN_PROVIDERS = {\n payments: ['native', 'stripe', 'custom'],\n email: ['native', 'smtp', 'custom'],\n reviews: ['native', 'custom'],\n search: ['native', 'custom'],\n analytics: ['native', 'custom'],\n shipping: ['native', 'custom'],\n tax: ['native', 'custom'],\n ai: ['none', 'anthropic', 'custom'],\n} as const satisfies Readonly<Record<CommerceSlot, readonly [string, ...string[]]>>\n","import { existsSync } from 'node:fs'\nimport { dirname, isAbsolute, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { createJiti } from 'jiti'\nimport { z } from 'zod'\nimport { ConfigError } from '@nymbalhq/types'\nimport { nymbalConfigSchema, type NymbalConfig } from './schema.js'\n\nconst CONFIG_FILE = 'nymbal.config.ts'\n\nexport interface LoadedConfig {\n config: NymbalConfig\n path: string\n projectRoot: string\n}\n\nexport function findConfigFile(startDir: string): string | null {\n let current = isAbsolute(startDir) ? startDir : resolve(startDir)\n while (true) {\n const candidate = resolve(current, CONFIG_FILE)\n if (existsSync(candidate)) return candidate\n const parent = dirname(current)\n if (parent === current) return null\n current = parent\n }\n}\n\nexport async function loadConfig(startDir: string = process.cwd()): Promise<LoadedConfig> {\n const path = findConfigFile(startDir)\n if (!path) {\n throw new ConfigError(\n `Could not find ${CONFIG_FILE} in ${startDir} or any parent directory.`,\n { context: { startDir } },\n )\n }\n\n const jiti = createJiti(pathToFileURL(path).href, { interopDefault: true })\n let raw: unknown\n try {\n raw = await jiti.import(path, { default: true })\n } catch (err) {\n throw new ConfigError(`Failed to load ${path}: ${(err as Error).message}`, {\n cause: err,\n context: { path },\n })\n }\n\n try {\n const config = nymbalConfigSchema.parse(raw)\n return { config, path, projectRoot: dirname(path) }\n } catch (err) {\n if (err instanceof z.ZodError) {\n throw new ConfigError(formatZodError(err, path), {\n cause: err,\n context: { path, issues: err.issues },\n })\n }\n throw err\n }\n}\n\nfunction formatZodError(err: z.ZodError, path: string): string {\n const lines = err.issues.map((issue) => {\n const at = issue.path.length > 0 ? issue.path.join('.') : '<root>'\n return ` • ${at}: ${issue.message}`\n })\n return `Invalid configuration in ${path}:\\n${lines.join('\\n')}`\n}\n","import { z } from 'zod'\nimport { KNOWN_PROVIDERS, type CommerceSlot } from './known-providers.js'\n\nconst rateLimitRuleSchema = z.object({\n requests: z.number().int().positive(),\n window: z.string().regex(/^\\d+(ms|s|m|h)$/, 'window must look like \"60s\", \"5m\", \"1h\"'),\n action: z.enum(['block', 'challenge', 'throttle']),\n})\n\nconst rateLimitPathPattern = /^\\/[\\w\\-/*:]*$/\n\n/** The schema's JWT secret when none is configured: fine for development, refused in production. */\nexport const DEFAULT_JWT_SECRET = 'dev-secret-please-override-me-1234567890'\n\nexport const storeSchema = z.object({\n name: z.string().min(1),\n currency: z.string().length(3),\n locale: z.string().min(2),\n timezone: z.string().min(1),\n})\n\nexport const infrastructureSchema = z.object({\n cloud: z.enum(['local', 'aws', 'gcp', 'azure', 'docker']),\n commandStore: z.enum(['sqlite', 'postgres']),\n documentStore: z.enum(['in-memory', 'dynamodb', 'firestore', 'cosmosdb', 'postgres-jsonb']),\n eventBus: z.enum(['in-process', 'eventbridge', 'pubsub', 'service-bus', 'redis-streams']),\n compute: z.enum(['in-process', 'lambda', 'cloud-functions', 'azure-functions', 'worker-threads']),\n})\n\nexport const securitySchema = z.object({\n adapter: z.enum(['middleware', 'cloudflare', 'aws-waf', 'akamai']),\n rateLimit: z\n .record(\n z.string().regex(rateLimitPathPattern, {\n message: 'rate limit keys must start with \"/\" and use only letters, numbers, -, _, /, *, :',\n }),\n rateLimitRuleSchema,\n )\n .default({}),\n botProtection: z\n .object({\n mode: z.enum(['off', 'managed', 'strict']).default('off'),\n allowList: z.array(z.string()).default([]),\n })\n .default({ mode: 'off', allowList: [] }),\n headers: z\n .object({\n hsts: z.boolean().default(true),\n contentSecurityPolicy: z\n .union([z.enum(['strict', 'relaxed', 'off']), z.string()])\n .default('strict'),\n referrerPolicy: z.string().default('strict-origin-when-cross-origin'),\n xFrameOptions: z.enum(['deny', 'sameorigin']).default('deny'),\n })\n .default({}),\n csrf: z.boolean().default(true),\n auth: z\n .object({\n jwtSecret: z.string().min(16).default(DEFAULT_JWT_SECRET),\n accessTtl: z\n .string()\n .regex(/^\\d+(ms|s|m|h|d)$/, 'TTL must look like \"15m\"')\n .default('15m'),\n refreshTtl: z\n .string()\n .regex(/^\\d+(ms|s|m|h|d)$/, 'TTL must look like \"7d\"')\n .default('7d'),\n })\n .default({}),\n})\n\n/** A slot's block: its provider must be one the slot knows, and an unknown one is named with the slot's list. */\nfunction adapterBlock<const P extends readonly [string, ...string[]]>(\n slot: CommerceSlot,\n providers: P,\n) {\n const known = providers.map((p) => `'${p}'`).join(', ')\n return z.object({\n provider: z.enum(providers, {\n errorMap: (issue, ctx) =>\n issue.code === z.ZodIssueCode.invalid_enum_value\n ? {\n message: `unknown ${slot} provider '${String(issue.received)}'; the ${slot} providers are ${known}`,\n }\n : { message: ctx.defaultError },\n }),\n config: z.record(z.string(), z.unknown()).optional(),\n })\n}\n\nexport const commerceSchema = z.object({\n payments: adapterBlock('payments', KNOWN_PROVIDERS.payments),\n email: adapterBlock('email', KNOWN_PROVIDERS.email),\n reviews: adapterBlock('reviews', KNOWN_PROVIDERS.reviews),\n search: adapterBlock('search', KNOWN_PROVIDERS.search),\n analytics: adapterBlock('analytics', KNOWN_PROVIDERS.analytics),\n shipping: adapterBlock('shipping', KNOWN_PROVIDERS.shipping),\n tax: adapterBlock('tax', KNOWN_PROVIDERS.tax),\n ai: adapterBlock('ai', KNOWN_PROVIDERS.ai),\n orders: z\n .object({\n numberPrefix: z.string().min(1).default('NYM'),\n numberStart: z.number().int().nonnegative().default(1000),\n })\n .default({}),\n})\n\nexport const httpSchema = z.object({\n adapter: z.enum(['fastify', 'hono']).default('fastify'),\n port: z.number().int().positive().default(3001),\n host: z.string().default('0.0.0.0'),\n /** Whether `X-Forwarded-For` sets the client IP the rate limiter keys on; only behind a proxy you run. */\n trustProxy: z.boolean().default(false),\n cors: z\n .object({\n allowedOrigins: z\n .array(z.string())\n .default(['http://localhost:3000', 'http://localhost:4321']),\n credentials: z.boolean().default(true),\n })\n .default({}),\n})\n\nexport const deploymentSchema = z.object({\n strategy: z.enum(['standard', 'blue-green']).default('standard'),\n})\n\nexport const featuresSchema = z.object({\n staging: z.boolean().default(false),\n heartbeat: z.boolean().default(false),\n autoUpdates: z.boolean().default(false),\n})\n\nexport const nymbalConfigSchema = z\n .object({\n store: storeSchema,\n template: z.enum(['astro', 'nextjs']),\n infrastructure: infrastructureSchema,\n security: securitySchema,\n commerce: commerceSchema,\n http: httpSchema,\n deployment: deploymentSchema,\n features: featuresSchema.default({\n staging: false,\n heartbeat: false,\n autoUpdates: false,\n }),\n })\n .superRefine((cfg, ctx) => {\n // Local infrastructure restricts which document-store / event-bus options make sense.\n if (cfg.infrastructure.cloud === 'local') {\n if (!['in-memory', 'postgres-jsonb'].includes(cfg.infrastructure.documentStore)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['infrastructure', 'documentStore'],\n message: `cloud=local only supports 'in-memory' or 'postgres-jsonb' for documentStore`,\n })\n }\n if (!['in-process', 'redis-streams'].includes(cfg.infrastructure.eventBus)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['infrastructure', 'eventBus'],\n message: `cloud=local only supports 'in-process' or 'redis-streams' for eventBus`,\n })\n }\n if (!['in-process', 'worker-threads'].includes(cfg.infrastructure.compute)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['infrastructure', 'compute'],\n message: `cloud=local only supports 'in-process' or 'worker-threads' for compute`,\n })\n }\n }\n\n // SMTP left the kernel for @nymbalhq/adapter-smtp; a native block still asking for it would print to the console.\n const email = cfg.commerce.email\n if (email.provider === 'native' && email.config?.['transport'] === 'smtp') {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['commerce', 'email', 'config', 'transport'],\n message: `the native email provider only prints to the console; for SMTP mail set email.provider to 'smtp' (@nymbalhq/adapter-smtp)`,\n })\n }\n\n // middleware security adapter is v0.1 and not intended for managed-cloud production deployments.\n if (cfg.security.adapter === 'middleware') {\n if (['aws', 'gcp', 'azure'].includes(cfg.infrastructure.cloud)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['security', 'adapter'],\n message: `security.adapter='middleware' is intended for local/docker development. Use a WAF adapter ('cloudflare', 'aws-waf', 'akamai') for cloud=${cfg.infrastructure.cloud}.`,\n })\n }\n }\n })\n\nexport type NymbalConfigInput = z.input<typeof nymbalConfigSchema>\nexport type NymbalConfig = z.output<typeof nymbalConfigSchema>\n"],"mappings":"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","names":["z","ConfigError","ConfigError","z"]}
|
|
1
|
+
{"version":3,"sources":["../src/define-config.ts","../src/env.ts","../src/known-providers.ts","../src/known-infrastructure.ts","../src/load.ts","../src/schema.ts"],"sourcesContent":["import type { NymbalConfigInput } from './schema.js'\n\nexport function defineConfig<T extends NymbalConfigInput>(config: T): T {\n return config\n}\n","import { ConfigError } from '@nymbalhq/types'\n\nexport function env(key: string, defaultValue?: string): string {\n const value = process.env[key]\n if (value !== undefined && value !== '') return value\n if (defaultValue !== undefined) return defaultValue\n throw new ConfigError(`Missing required environment variable: ${key}`, {\n context: { key },\n })\n}\n\nexport function envOptional(key: string): string | undefined {\n const value = process.env[key]\n return value !== undefined && value !== '' ? value : undefined\n}\n\nexport function envNumber(key: string, defaultValue?: number): number {\n const raw = envOptional(key)\n if (raw === undefined) {\n if (defaultValue !== undefined) return defaultValue\n throw new ConfigError(`Missing required environment variable: ${key}`, { context: { key } })\n }\n const parsed = Number(raw)\n if (!Number.isFinite(parsed)) {\n throw new ConfigError(`Environment variable ${key} is not a valid number: ${raw}`, {\n context: { key, raw },\n })\n }\n return parsed\n}\n\nexport function envBool(key: string, defaultValue = false): boolean {\n const raw = envOptional(key)?.toLowerCase()\n if (raw === undefined) return defaultValue\n return raw === 'true' || raw === '1' || raw === 'yes' || raw === 'on'\n}\n","import type { CommerceSlot } from '@nymbalhq/types'\n\nexport type { CommerceSlot }\n\n/**\n * The providers each commerce slot accepts. A provider that needs an SDK lives in an `@nymbalhq/adapter-*` package the\n * kernel loads only when the config names it; `custom` takes the adapter a project passes to `createApp`.\n */\nexport const KNOWN_PROVIDERS = {\n payments: ['native', 'stripe', 'custom'],\n email: ['native', 'smtp', 'custom'],\n reviews: ['native', 'custom'],\n search: ['native', 'custom'],\n analytics: ['native', 'custom'],\n shipping: ['native', 'custom'],\n tax: ['native', 'custom'],\n ai: ['none', 'anthropic', 'custom'],\n} as const satisfies Readonly<Record<CommerceSlot, readonly [string, ...string[]]>>\n","/**\n * The values each infrastructure slot accepts: only what is built. `in-memory`, `in-process` and `local-fs` are the\n * kernel's own; `redis`, `postgres-jsonb`, `redis-streams` and `s3` live in `@nymbalhq/*` packages the kernel loads\n * only when the config names them.\n */\nexport const KNOWN_INFRASTRUCTURE = {\n commandStore: ['sqlite', 'postgres'],\n documentStore: ['in-memory', 'redis', 'postgres-jsonb'],\n eventBus: ['in-process', 'redis-streams'],\n media: ['local-fs', 's3'],\n} as const satisfies Readonly<Record<string, readonly [string, ...string[]]>>\n\nexport type InfrastructureSlot = keyof typeof KNOWN_INFRASTRUCTURE\n\n/** Keys that drove nothing and were removed; a config that still sets one is told to delete it. */\nexport const REMOVED_INFRASTRUCTURE_KEYS = ['cloud', 'compute'] as const\n","import { existsSync } from 'node:fs'\nimport { dirname, isAbsolute, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { createJiti } from 'jiti'\nimport { z } from 'zod'\nimport { ConfigError, type CommerceSlotAdapters } from '@nymbalhq/types'\nimport { KNOWN_PROVIDERS } from './known-providers.js'\nimport { nymbalConfigSchema, type NymbalConfig } from './schema.js'\n\nconst CONFIG_FILE = 'nymbal.config.ts'\n\nexport interface LoadedConfig {\n config: NymbalConfig\n path: string\n projectRoot: string\n /** The module's named `adapters` export: one adapter per slot whose provider is `custom`, for createApp. */\n adapters?: Partial<CommerceSlotAdapters>\n}\n\nexport function findConfigFile(startDir: string): string | null {\n let current = isAbsolute(startDir) ? startDir : resolve(startDir)\n while (true) {\n const candidate = resolve(current, CONFIG_FILE)\n if (existsSync(candidate)) return candidate\n const parent = dirname(current)\n if (parent === current) return null\n current = parent\n }\n}\n\nexport async function loadConfig(startDir: string = process.cwd()): Promise<LoadedConfig> {\n const path = findConfigFile(startDir)\n if (!path) {\n throw new ConfigError(\n `Could not find ${CONFIG_FILE} in ${startDir} or any parent directory.`,\n { context: { startDir } },\n )\n }\n\n const jiti = createJiti(pathToFileURL(path).href, { interopDefault: true })\n let mod: Record<string, unknown>\n try {\n mod = await jiti.import<Record<string, unknown>>(path)\n } catch (err) {\n throw new ConfigError(`Failed to load ${path}: ${(err as Error).message}`, {\n cause: err,\n context: { path },\n })\n }\n\n const raw = mod['default'] ?? mod\n const adapters = adaptersExport(mod['adapters'], path)\n try {\n const config = nymbalConfigSchema.parse(raw)\n return { config, path, projectRoot: dirname(path), ...(adapters !== undefined && { adapters }) }\n } catch (err) {\n if (err instanceof z.ZodError) {\n throw new ConfigError(formatZodError(err, path), {\n cause: err,\n context: { path, issues: err.issues },\n })\n }\n throw err\n }\n}\n\n/** The `adapters` export, keyed by commerce slot; anything else is a mistake worth naming before createApp runs. */\nfunction adaptersExport(value: unknown, path: string): Partial<CommerceSlotAdapters> | undefined {\n if (value === undefined) return undefined\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new ConfigError(`${path}: the adapters export must be an object keyed by commerce slot`, {\n code: 'config.adapters_invalid',\n context: { path },\n })\n }\n const slots = Object.keys(KNOWN_PROVIDERS)\n const unknown = Object.keys(value).filter((key) => !slots.includes(key))\n if (unknown.length > 0) {\n throw new ConfigError(\n `${path}: the adapters export names ${unknown.join(', ')}, which is no commerce slot (${slots.join(', ')})`,\n { code: 'config.adapters_invalid', context: { path, unknown } },\n )\n }\n return value as Partial<CommerceSlotAdapters>\n}\n\nfunction formatZodError(err: z.ZodError, path: string): string {\n const lines = err.issues.map((issue) => {\n const at = issue.path.length > 0 ? issue.path.join('.') : '<root>'\n return ` • ${at}: ${issue.message}`\n })\n return `Invalid configuration in ${path}:\\n${lines.join('\\n')}`\n}\n","import { z } from 'zod'\nimport {\n KNOWN_INFRASTRUCTURE,\n REMOVED_INFRASTRUCTURE_KEYS,\n type InfrastructureSlot,\n} from './known-infrastructure.js'\nimport { KNOWN_PROVIDERS, type CommerceSlot } from './known-providers.js'\n\nconst rateLimitRuleSchema = z.object({\n requests: z.number().int().positive(),\n window: z.string().regex(/^\\d+(ms|s|m|h)$/, 'window must look like \"60s\", \"5m\", \"1h\"'),\n action: z.enum(['block', 'challenge', 'throttle']),\n})\n\nconst rateLimitPathPattern = /^\\/[\\w\\-/*:]*$/\n\n/** The schema's JWT secret when none is configured: fine for development, refused in production. */\nexport const DEFAULT_JWT_SECRET = 'dev-secret-please-override-me-1234567890'\n\nexport const storeSchema = z.object({\n name: z.string().min(1),\n currency: z.string().length(3),\n locale: z.string().min(2),\n timezone: z.string().min(1),\n})\n\nconst quotedList = (values: readonly string[]): string => values.map((v) => `'${v}'`).join(', ')\n\n/** A slot's value must be one the slot lists; an unknown one is named with the list. */\nfunction infrastructureValue<const V extends readonly [string, ...string[]]>(\n slot: InfrastructureSlot,\n values: V,\n) {\n return z.enum(values, {\n errorMap: (issue, ctx) =>\n issue.code === z.ZodIssueCode.invalid_enum_value\n ? {\n message: `unknown ${slot} '${String(issue.received)}'; the ${slot} values are ${quotedList(values)}`,\n }\n : { message: ctx.defaultError },\n })\n}\n\nconst INFRASTRUCTURE_KEYS = [...Object.keys(KNOWN_INFRASTRUCTURE), 'redis', 's3']\n\nfunction unrecognizedInfrastructureKeys(keys: string[]): string {\n return keys\n .map((key) =>\n (REMOVED_INFRASTRUCTURE_KEYS as readonly string[]).includes(key)\n ? `infrastructure.${key} was removed: it drives nothing, so delete it from the config`\n : `unknown infrastructure key '${key}'; the infrastructure keys are ${quotedList(INFRASTRUCTURE_KEYS)}`,\n )\n .join('; ')\n}\n\n/** The shared Redis connection of the `redis` document store and the `redis-streams` bus. */\nexport const redisSchema = z\n .object({\n /** Defaults to `REDIS_URL`. */\n url: z.string().min(1).optional(),\n /** Namespaces every key and stream; defaults to `NYMBAL_REDIS_PREFIX`, then `'nymbal'`. */\n prefix: z.string().min(1).optional(),\n /** How long a publish waits for the groups it delivers to (default 15 000). */\n ackTimeoutMs: z.number().int().positive().optional(),\n /** How long an entry may stay pending on a consumer before a live one takes it over (default 5 000). */\n claimIdleMs: z.number().int().positive().optional(),\n /** The approximate length each stream is trimmed to (default 10 000). */\n streamMaxLen: z.number().int().positive().optional(),\n })\n .strict()\n\nconst S3_KEYS = ['bucket', 'region', 'endpoint', 'prefix', 'publicUrl', 'forcePathStyle']\n\n/**\n * The bucket `media: 's3'` stores in. Each field falls back to the environment in the platform; credentials are never\n * config keys: the AWS SDK's default chain provides them.\n */\nexport const s3Schema = z\n .object(\n {\n /** Defaults to `S3_BUCKET`; one of the two is required. */\n bucket: z.string().min(1).optional(),\n /** Defaults to `AWS_REGION`, then `'us-east-1'`. */\n region: z.string().min(1).optional(),\n /** An S3-compatible API (MinIO, R2); defaults to `S3_ENDPOINT`, then AWS. */\n endpoint: z.string().min(1).optional(),\n /** Where every object key starts; defaults to `NYMBAL_S3_PREFIX`, then none. */\n prefix: z.string().optional(),\n /** Where the bucket's objects are served from (a CDN); defaults to `S3_PUBLIC_URL`, then the bucket's own URL. */\n publicUrl: z.string().min(1).optional(),\n /** Path-style requests; true by default when an endpoint is set. */\n forcePathStyle: z.boolean().optional(),\n },\n {\n errorMap: (issue, ctx) =>\n issue.code === z.ZodIssueCode.unrecognized_keys\n ? {\n message: `unknown infrastructure.s3 key${issue.keys.length > 1 ? 's' : ''} ${quotedList(issue.keys)}; the s3 keys are ${quotedList(S3_KEYS)}, and credentials come from the AWS SDK (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, a profile or a role), never the config`,\n }\n : { message: ctx.defaultError },\n },\n )\n .strict()\n\nexport const infrastructureSchema = z\n .object(\n {\n commandStore: infrastructureValue('commandStore', KNOWN_INFRASTRUCTURE.commandStore),\n documentStore: infrastructureValue('documentStore', KNOWN_INFRASTRUCTURE.documentStore),\n eventBus: infrastructureValue('eventBus', KNOWN_INFRASTRUCTURE.eventBus),\n media: infrastructureValue('media', KNOWN_INFRASTRUCTURE.media).default('local-fs'),\n redis: redisSchema.optional(),\n s3: s3Schema.optional(),\n },\n {\n errorMap: (issue, ctx) =>\n issue.code === z.ZodIssueCode.unrecognized_keys\n ? { message: unrecognizedInfrastructureKeys(issue.keys) }\n : { message: ctx.defaultError },\n },\n )\n .strict()\n .superRefine((infra, ctx) => {\n if (infra.documentStore === 'postgres-jsonb' && infra.commandStore !== 'postgres') {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['documentStore'],\n message: `documentStore 'postgres-jsonb' shares the command store's Postgres connection, so it needs commandStore 'postgres' (not '${infra.commandStore}')`,\n })\n }\n if (infra.eventBus === 'redis-streams' && infra.documentStore === 'in-memory') {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['eventBus'],\n message: `eventBus 'redis-streams' needs a shared documentStore ('redis' or 'postgres-jsonb'), not 'in-memory': a named group hands each event to one instance, so a per-process read model would miss the rest`,\n })\n }\n if (infra.s3 !== undefined && infra.media !== 's3') {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['s3'],\n message: `infrastructure.s3 configures media 's3', but media is '${infra.media}': set media to 's3' or delete the s3 block`,\n })\n }\n })\n\n/** Where a `cloudflare` store's rules go: required when `security.adapter` is `cloudflare`, read with `env()`. */\nconst cloudflareSchema = z.object({\n zoneId: z.string().optional(),\n apiToken: z.string().optional(),\n /** The Cloudflare v4 API; the adapter defaults it to https://api.cloudflare.com/client/v4. */\n apiBase: z.string().url().optional(),\n})\n\nconst customRuleSchema = z.object({\n name: z.string().min(1),\n expression: z.string().min(1),\n action: z.enum(['block', 'managed_challenge', 'js_challenge', 'log']),\n})\n\nconst securityFields = z.object({\n adapter: z.enum(['middleware', 'cloudflare', 'aws-waf', 'akamai']),\n rateLimit: z\n .record(\n z.string().regex(rateLimitPathPattern, {\n message: 'rate limit keys must start with \"/\" and use only letters, numbers, -, _, /, *, :',\n }),\n rateLimitRuleSchema,\n )\n .default({}),\n botProtection: z\n .object({\n mode: z.enum(['off', 'managed', 'strict']).default('off'),\n allowList: z.array(z.string()).default([]),\n })\n .default({ mode: 'off', allowList: [] }),\n headers: z\n .object({\n hsts: z.boolean().default(true),\n contentSecurityPolicy: z\n .union([z.enum(['strict', 'relaxed', 'off']), z.string()])\n .default('strict'),\n referrerPolicy: z.string().default('strict-origin-when-cross-origin'),\n xFrameOptions: z.enum(['deny', 'sameorigin']).default('deny'),\n })\n .default({}),\n csrf: z.boolean().default(true),\n auth: z\n .object({\n jwtSecret: z.string().min(16).default(DEFAULT_JWT_SECRET),\n accessTtl: z\n .string()\n .regex(/^\\d+(ms|s|m|h|d)$/, 'TTL must look like \"15m\"')\n .default('15m'),\n refreshTtl: z\n .string()\n .regex(/^\\d+(ms|s|m|h|d)$/, 'TTL must look like \"7d\"')\n .default('7d'),\n })\n .default({}),\n cloudflare: cloudflareSchema.optional(),\n geo: z\n .object({\n block: z\n .array(z.string().regex(/^[A-Z]{2}$/, 'geo.block codes are ISO 3166 alpha-2, like \"RU\"'))\n .default([]),\n })\n .default({ block: [] }),\n customRules: z.array(customRuleSchema).default([]),\n managedRulesets: z.array(z.enum(['cloudflare', 'owasp'])).default([]),\n})\n\nexport const securitySchema = securityFields.superRefine((security, ctx) => {\n if (security.adapter === 'cloudflare') {\n for (const field of ['zoneId', 'apiToken'] as const) {\n if (!security.cloudflare?.[field]) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['cloudflare', field],\n message: `security.adapter 'cloudflare' needs security.cloudflare.${field}`,\n })\n }\n }\n }\n const seen = new Set<string>()\n security.customRules.forEach((rule, i) => {\n if (seen.has(rule.name)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['customRules', i, 'name'],\n message: `customRules has two rules named '${rule.name}'; names must be unique`,\n })\n }\n seen.add(rule.name)\n })\n})\n\n/**\n * npm's rules for a new package name: lower case and URL-safe, optionally `@scope/`, never starting with `.` or `_`.\n * The 214-character limit is checked beside it.\n */\nconst NPM_PACKAGE_NAME = /^(?:@[a-z0-9~-][a-z0-9._~-]*\\/)?[a-z0-9~-][a-z0-9._~-]*$/\n\n/** A slot's block: its provider must be one the slot knows, and an unknown one is named with the slot's list. */\nfunction adapterBlock<const P extends readonly [string, ...string[]]>(\n slot: CommerceSlot,\n providers: P,\n) {\n const known = providers.map((p) => `'${p}'`).join(', ')\n return z.object({\n provider: z.enum(providers, {\n errorMap: (issue, ctx) =>\n issue.code === z.ZodIssueCode.invalid_enum_value\n ? {\n message: `unknown ${slot} provider '${String(issue.received)}'; the ${slot} providers are ${known}`,\n }\n : { message: ctx.defaultError },\n }),\n config: z.record(z.string(), z.unknown()).optional(),\n /** The npm package a `custom` slot's adapter comes from, for tooling (`nymbal test:contracts`); the kernel never reads it. */\n package: z\n .string()\n .max(214, 'an npm package name is at most 214 characters')\n .regex(NPM_PACKAGE_NAME, 'must be an npm package name, such as `@acme/nymbal-search`')\n .optional(),\n })\n}\n\nexport const commerceSchema = z.object({\n payments: adapterBlock('payments', KNOWN_PROVIDERS.payments),\n email: adapterBlock('email', KNOWN_PROVIDERS.email),\n reviews: adapterBlock('reviews', KNOWN_PROVIDERS.reviews),\n search: adapterBlock('search', KNOWN_PROVIDERS.search),\n analytics: adapterBlock('analytics', KNOWN_PROVIDERS.analytics),\n shipping: adapterBlock('shipping', KNOWN_PROVIDERS.shipping),\n tax: adapterBlock('tax', KNOWN_PROVIDERS.tax),\n ai: adapterBlock('ai', KNOWN_PROVIDERS.ai),\n orders: z\n .object({\n numberPrefix: z.string().min(1).default('NYM'),\n numberStart: z.number().int().nonnegative().default(1000),\n })\n .default({}),\n})\n\nexport const httpSchema = z.object({\n adapter: z.enum(['fastify', 'hono']).default('fastify'),\n port: z.number().int().positive().default(3001),\n host: z.string().default('0.0.0.0'),\n /** Whether `X-Forwarded-For` sets the client IP the rate limiter keys on; only behind a proxy you run. */\n trustProxy: z.boolean().default(false),\n cors: z\n .object({\n allowedOrigins: z\n .array(z.string())\n .default(['http://localhost:3000', 'http://localhost:4321']),\n credentials: z.boolean().default(true),\n })\n .default({}),\n})\n\nexport const deploymentSchema = z.object({\n strategy: z.enum(['standard', 'blue-green']).default('standard'),\n})\n\nexport const featuresSchema = z.object({\n staging: z.boolean().default(false),\n heartbeat: z.boolean().default(false),\n autoUpdates: z.boolean().default(false),\n})\n\n/**\n * The bucket delivered events past retention are archived to before they are deleted. Its objects hold customer\n * data, so it must be private: never the media bucket, which serves its objects publicly. Credentials come from the\n * AWS SDK's default chain, as `infrastructure.s3`'s do.\n */\nexport const eventArchiveSchema = z\n .object({\n adapter: z.literal('s3'),\n bucket: z.string().min(1),\n /** Where every archive key starts; none when not given. */\n prefix: z.string().optional(),\n /** `'us-east-1'` when not given. */\n region: z.string().min(1).optional(),\n /** An S3-compatible API (MinIO, R2). */\n endpoint: z.string().min(1).optional(),\n /** Path-style requests; true by default when an endpoint is set. */\n forcePathStyle: z.boolean().optional(),\n })\n .strict()\n\nexport const eventsSchema = z\n .object({\n /** Days a delivered event stays in the log. */\n retentionDays: z.number().int().min(1).default(30),\n archive: eventArchiveSchema.optional(),\n })\n .strict()\n\nexport const nymbalConfigSchema = z\n .object({\n store: storeSchema,\n template: z.enum(['astro', 'nextjs']),\n infrastructure: infrastructureSchema,\n security: securitySchema,\n commerce: commerceSchema,\n http: httpSchema,\n deployment: deploymentSchema,\n features: featuresSchema.default({\n staging: false,\n heartbeat: false,\n autoUpdates: false,\n }),\n events: eventsSchema.default({}),\n })\n .superRefine((cfg, ctx) => {\n const archiveBucket = cfg.events.archive?.bucket\n if (\n archiveBucket !== undefined &&\n cfg.infrastructure.media === 's3' &&\n archiveBucket === cfg.infrastructure.s3?.bucket\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['events', 'archive', 'bucket'],\n message: `events.archive.bucket is infrastructure.s3.bucket ('${archiveBucket}'), the media bucket, which serves its objects publicly; archive events to a private bucket of their own`,\n })\n }\n // SMTP left the kernel for @nymbalhq/adapter-smtp; a native block still asking for it would print to the console.\n const email = cfg.commerce.email\n if (email.provider === 'native' && email.config?.['transport'] === 'smtp') {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['commerce', 'email', 'config', 'transport'],\n message: `the native email provider only prints to the console; for SMTP mail set email.provider to 'smtp' (@nymbalhq/adapter-smtp)`,\n })\n }\n })\n\nexport type NymbalConfigInput = z.input<typeof nymbalConfigSchema>\nexport type NymbalConfig = z.output<typeof nymbalConfigSchema>\n"],"mappings":"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","names":["z","ConfigError","ConfigError","z"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nymbalhq/config",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Typed configuration surface for Nymbal",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -27,17 +27,18 @@
|
|
|
27
27
|
"dist"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
+
"@nymbalhq/types": "1.2.0",
|
|
30
31
|
"jiti": "^2.4.0",
|
|
31
|
-
"zod": "^3.23.8"
|
|
32
|
-
"@nymbalhq/types": "1.0.0"
|
|
32
|
+
"zod": "^3.23.8"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"
|
|
36
|
-
"
|
|
35
|
+
"@typescript/native": "npm:typescript@^7.0.2",
|
|
36
|
+
"tsup": "^9.0.0",
|
|
37
|
+
"typescript": "npm:@typescript/typescript6@^6.0.2"
|
|
37
38
|
},
|
|
38
39
|
"scripts": {
|
|
39
40
|
"build": "tsup",
|
|
40
41
|
"dev": "tsup --watch",
|
|
41
|
-
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
42
|
+
"typecheck": "tsc -p tsconfig.json --noEmit --rootDir ../.."
|
|
42
43
|
}
|
|
43
44
|
}
|