Skip to content

Commit 15f559b

Browse files
committed
Add config helper, typings, example config, and README
Expose a typed config API and improve docs/workflow. Adds defineConfig runtime helper (src/config-public.js) and TypeScript declarations (src/config.d.ts), an example jsondb.config.example.mjs, and updates package exports to expose jsondb/config. Update default mock.delay in src/config.js to [30,100]. Rework README (renamed to jsondb) to document defaults, CLI usage, REST-first workflow, and config details. Update tests and helpers to support the new "jsondb" package alias, add tests for mock delay and config usage, and fix internal imports to use the jsondb entrypoints. This change centralizes configuration ergonomics and clarifies defaults and developer UX.
1 parent d5371c8 commit 15f559b

10 files changed

Lines changed: 650 additions & 253 deletions

File tree

README.md

Lines changed: 478 additions & 251 deletions
Large diffs are not rendered by default.

jsondb.config.example.mjs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// @ts-check
2+
import { defineConfig } from 'jsondb/config';
3+
4+
export default defineConfig({
5+
// Fixture source folder. Defaults to './db'.
6+
dbDir: './db',
7+
8+
// Runtime output folder. Defaults to './.jsondb'.
9+
stateDir: './.jsondb',
10+
11+
// mirror: keep source fixtures unchanged and write app edits to .jsondb/state.
12+
// source: write generated ids back to plain .json fixtures when needed.
13+
mode: 'mirror',
14+
15+
// Generated TypeScript types. The default outFile is gitignored; commitOutFile
16+
// is useful when app code imports generated types in CI or fresh checkouts.
17+
types: {
18+
enabled: true,
19+
outFile: './.jsondb/types/index.ts',
20+
commitOutFile: null,
21+
useReadonly: false,
22+
emitComments: true,
23+
},
24+
25+
// Default local development behavior is permissive: unknown schema-backed
26+
// fields warn. Use 'error' when you want schema drift to fail sync/writes.
27+
schema: {
28+
unknownFields: 'warn',
29+
},
30+
31+
// Optional schema-only mock records. Leave off when real fixture data exists.
32+
seed: {
33+
generateFromSchema: false,
34+
generatedCount: 5,
35+
},
36+
37+
// Local server settings.
38+
server: {
39+
host: '127.0.0.1',
40+
port: 7331,
41+
maxBodyBytes: 1048576,
42+
},
43+
44+
// Local latency is on by default so loading states are visible. Use 0 to
45+
// disable delay, 50 for a fixed 50ms delay, or [50, 300] for a range.
46+
// Random errors are off by default.
47+
mock: {
48+
delay: [30, 100],
49+
errors: null,
50+
},
51+
});

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
"types": "./src/schema.d.ts",
1616
"default": "./src/schema-builders.js"
1717
},
18+
"./config": {
19+
"types": "./src/config.d.ts",
20+
"default": "./src/config-public.js"
21+
},
1822
"./client": {
1923
"types": "./src/index.d.ts",
2024
"default": "./src/client.js"
@@ -37,6 +41,7 @@
3741
"examples/*/db/**",
3842
"examples/*/jsondb.config.mjs",
3943
"examples/*/src/generated/**",
44+
"jsondb.config.example.mjs",
4045
"README.md",
4146
"SPEC.md"
4247
],

src/config-public.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function defineConfig(config) {
2+
return config;
3+
}

src/config.d.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { JsonDbOptions } from './index.d.ts';
2+
3+
/**
4+
* jsondb project configuration.
5+
*
6+
* Use with `// @ts-check` in `jsondb.config.mjs` for editor autocomplete:
7+
*
8+
* ```js
9+
* import { defineConfig } from 'jsondb/config';
10+
*
11+
* export default defineConfig({
12+
* dbDir: './db',
13+
* });
14+
* ```
15+
*/
16+
export type JsonDbConfig = JsonDbOptions;
17+
18+
/**
19+
* Type-only helper for authoring `jsondb.config.mjs`.
20+
*
21+
* It returns the config unchanged at runtime and exists so JavaScript config
22+
* files get autocomplete, literal value checking, and inline JSDoc.
23+
*/
24+
export function defineConfig<Config extends JsonDbConfig>(config: Config): Config;

src/config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const DEFAULT_CONFIG = {
4646
path: '/graphql',
4747
},
4848
mock: {
49-
delay: null,
49+
delay: [30, 100],
5050
errors: null,
5151
},
5252
generate: {

src/index.d.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,58 +4,91 @@ export type JsonDbTypeMap = {
44
};
55

66
export type JsonDbOptions = {
7+
/** Project root used to resolve relative config paths. Defaults to process.cwd(). */
78
cwd?: string;
9+
/** Explicit config file path. Defaults to jsondb.config.mjs/js lookup from cwd. */
810
configPath?: string;
11+
/** Fixture source folder. Defaults to "./db". */
912
dbDir?: string;
13+
/** Backwards-compatible fixture source folder alias. If set, it wins over dbDir. */
1014
sourceDir?: string;
15+
/** Generated runtime output folder. Defaults to "./.jsondb". */
1116
stateDir?: string;
17+
/** "mirror" keeps source fixtures unchanged; "source" may write generated ids back to plain .json fixtures. */
1218
mode?: 'mirror' | 'source';
19+
/** Run sync automatically when opening the package API. */
1320
syncOnOpen?: boolean;
21+
/** Keep valid resources available when one source file has diagnostics. */
1422
allowSourceErrors?: boolean;
1523
types?: {
24+
/** Generate TypeScript types during sync. */
1625
enabled?: boolean;
26+
/** Gitignored generated type output. Defaults to "./.jsondb/types/index.ts". */
1727
outFile?: string;
28+
/** Optional committed copy for app/CI imports. */
1829
commitOutFile?: string | null;
30+
/** Emit readonly object properties in generated types. */
1931
useReadonly?: boolean;
32+
/** Emit JSDoc from schema field descriptions. */
2033
emitComments?: boolean;
34+
/** Export JsonDbCollections, JsonDbDocuments, and JsonDbTypes helpers. */
2135
exportRuntimeHelpers?: boolean;
2236
};
2337
schema?: {
38+
/** Which inputs define schemas. "auto" uses schema files when present and otherwise infers from data. */
2439
source?: 'auto' | 'data' | 'schema';
40+
/** Allow JSONC source files. */
2541
allowJsonc?: boolean;
42+
/** How schema-backed resources handle fields not declared by schema. */
2643
unknownFields?: 'allow' | 'warn' | 'error';
44+
/** Future migration policy for safe additive changes. */
2745
additiveChanges?: 'auto' | 'manual';
46+
/** Future migration policy for destructive changes. */
2847
destructiveChanges?: 'manual';
48+
/** Future migration policy for field type changes. */
2949
typeChanges?: 'manual';
3050
};
3151
defaults?: {
52+
/** Apply schema defaults on create through package, REST, and GraphQL writes. */
3253
applyOnCreate?: boolean;
54+
/** Apply defaults during safe additive mirror sync. */
3355
applyOnSafeMigration?: boolean;
3456
};
3557
seed?: {
58+
/** Generate mock runtime rows for schema-only resources with empty seed data. */
3659
generateFromSchema?: boolean;
60+
/** Number of mock rows to generate when generateFromSchema is true. */
3761
generatedCount?: number;
3862
};
63+
/** Per-collection overrides such as custom id field names. */
3964
collections?: Record<string, { idField?: string }>;
4065
server?: {
66+
/** Local HTTP host. Defaults to "127.0.0.1". */
4167
host?: string;
68+
/** Local HTTP port. Defaults to 7331. */
4269
port?: number;
70+
/** Maximum JSON request body size in bytes. Defaults to 1048576. */
4371
maxBodyBytes?: number;
4472
};
4573
rest?: {
74+
/** Enable generated REST routes. */
4675
enabled?: boolean;
4776
};
4877
graphql?: {
78+
/** Enable the focused dependency-free GraphQL endpoint. */
4979
enabled?: boolean;
80+
/** GraphQL HTTP path. Defaults to "/graphql". */
5081
path?: string;
5182
};
5283
mock?: {
84+
/** Local response delay in ms, [minMs, maxMs], or an object range. Defaults to [30, 100]. Use 0 to disable. */
5385
delay?: number | [number, number] | {
5486
minMs?: number;
5587
maxMs?: number;
5688
min?: number;
5789
max?: number;
5890
} | null;
91+
/** Random local error rate or detailed error settings. Defaults to no random errors. */
5992
errors?: number | {
6093
rate?: number;
6194
probability?: number;
@@ -65,11 +98,14 @@ export type JsonDbOptions = {
6598
};
6699
generate?: {
67100
hono?: {
101+
/** Output folder for generated starter code. */
68102
outDir?: string;
103+
/** API modules to generate. */
69104
api?: Array<'rest' | 'graphql'> | 'rest' | 'graphql' | 'rest,graphql' | 'none';
70105
db?: 'sqlite';
71106
app?: 'standalone' | 'module';
72107
runtime?: 'node-sqlite';
108+
/** Include fixture seed support in generated starter code. */
73109
seed?: false | 'fixtures';
74110
};
75111
};

src/mock.test.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ test('mock delay supports range arrays', () => {
1313
assert.equal(pickDelayMs(delay, () => 1), 300);
1414
});
1515

16+
test('mock delay supports disabled and fixed values', () => {
17+
assert.deepEqual(normalizeMockDelay(0), {
18+
minMs: 0,
19+
maxMs: 0,
20+
});
21+
assert.deepEqual(normalizeMockDelay(50), {
22+
minMs: 50,
23+
maxMs: 50,
24+
});
25+
});
26+
1627
test('mock errors can force chaos responses', async () => {
1728
const result = await runMockBehavior({
1829
mock: {

test/helpers.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export async function makeProject() {
77
await mkdir(path.join(cwd, 'db'), { recursive: true });
88
await mkdir(path.join(cwd, 'node_modules'), { recursive: true });
99
await symlink(path.resolve('.'), path.join(cwd, 'node_modules', 'json-fixture-db'), 'dir');
10+
await symlink(path.resolve('.'), path.join(cwd, 'node_modules', 'jsondb'), 'dir');
1011
return cwd;
1112
}
1213

test/jsondb.test.js

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ test('data-first fixtures generate schema, types, and runtime state', async () =
2828
assert.deepEqual(JSON.parse(await readFile(path.join(cwd, '.jsondb/state/users.json'), 'utf8'))[0].id, 'u_1');
2929
});
3030

31+
test('default config adds a small local mock delay range', async () => {
32+
const cwd = await makeProject();
33+
const config = await loadConfig({ cwd });
34+
35+
assert.deepEqual(config.mock.delay, [30, 100]);
36+
});
37+
3138
test('dbDir config changes the fixture source folder', async () => {
3239
const cwd = await makeProject();
3340
await writeConfig(cwd, `export default {
@@ -57,6 +64,38 @@ test('dbDir config changes the fixture source folder', async () => {
5764
assert.equal(metadata.resources.users.path, 'jsondb/users.json');
5865
});
5966

67+
test('config files can use the typed defineConfig helper', async () => {
68+
const cwd = await makeProject();
69+
await writeConfig(cwd, `import { defineConfig } from 'jsondb/config';
70+
71+
export default defineConfig({
72+
mode: 'mirror',
73+
mock: {
74+
delay: [75, 250],
75+
},
76+
});
77+
`);
78+
79+
const config = await loadConfig({ cwd });
80+
81+
assert.equal(config.mode, 'mirror');
82+
assert.deepEqual(config.mock.delay, [75, 250]);
83+
});
84+
85+
test('consumer projects can import package APIs through the jsondb alias', async () => {
86+
const cwd = await makeProject();
87+
await writeFile(path.join(cwd, 'check-alias.mjs'), `import { openJsonFixtureDb } from 'jsondb';
88+
import { createJsonDbClient } from 'jsondb/client';
89+
import { defineConfig } from 'jsondb/config';
90+
91+
if (typeof openJsonFixtureDb !== 'function') throw new Error('missing package API');
92+
if (typeof createJsonDbClient !== 'function') throw new Error('missing client API');
93+
if (typeof defineConfig !== 'function') throw new Error('missing config API');
94+
`);
95+
96+
await execFileAsync(process.execPath, ['check-alias.mjs'], { cwd });
97+
});
98+
6099
test('schema-only fixtures generate types and initialize empty state', async () => {
61100
const cwd = await makeProject();
62101
await writeFixture(cwd, 'auditEvents.schema.jsonc', `{
@@ -220,7 +259,7 @@ test('package API duplicate ids produce actionable errors', async () => {
220259

221260
test('.schema.mjs files can use schema helpers', async () => {
222261
const cwd = await makeProject();
223-
await writeFixture(cwd, 'users.schema.mjs', `import { collection, field } from 'json-fixture-db/schema';
262+
await writeFixture(cwd, 'users.schema.mjs', `import { collection, field } from 'jsondb/schema';
224263
225264
export default collection({
226265
idField: 'id',

0 commit comments

Comments
 (0)