@molecule/api-mock-server 1.0.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.
Files changed (67) hide show
  1. package/LICENSE +115 -0
  2. package/README.md +853 -0
  3. package/dist/browser-guard.d.ts +2 -0
  4. package/dist/browser-guard.d.ts.map +1 -0
  5. package/dist/browser-guard.js +19 -0
  6. package/dist/browser-guard.js.map +1 -0
  7. package/dist/cli.d.ts +11 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +152 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/fixtures/app-fixtures.d.ts +54 -0
  12. package/dist/fixtures/app-fixtures.d.ts.map +1 -0
  13. package/dist/fixtures/app-fixtures.js +601 -0
  14. package/dist/fixtures/app-fixtures.js.map +1 -0
  15. package/dist/fixtures/index.d.ts +9 -0
  16. package/dist/fixtures/index.d.ts.map +1 -0
  17. package/dist/fixtures/index.js +9 -0
  18. package/dist/fixtures/index.js.map +1 -0
  19. package/dist/fixtures/seed.d.ts +74 -0
  20. package/dist/fixtures/seed.d.ts.map +1 -0
  21. package/dist/fixtures/seed.js +112 -0
  22. package/dist/fixtures/seed.js.map +1 -0
  23. package/dist/fixtures/semantic-generator.d.ts +20 -0
  24. package/dist/fixtures/semantic-generator.d.ts.map +1 -0
  25. package/dist/fixtures/semantic-generator.js +539 -0
  26. package/dist/fixtures/semantic-generator.js.map +1 -0
  27. package/dist/fixtures/zod-walker.d.ts +34 -0
  28. package/dist/fixtures/zod-walker.d.ts.map +1 -0
  29. package/dist/fixtures/zod-walker.js +183 -0
  30. package/dist/fixtures/zod-walker.js.map +1 -0
  31. package/dist/index.d.ts +78 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +78 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/scanner/index.d.ts +6 -0
  36. package/dist/scanner/index.d.ts.map +1 -0
  37. package/dist/scanner/index.js +6 -0
  38. package/dist/scanner/index.js.map +1 -0
  39. package/dist/scanner/scanner.d.ts +21 -0
  40. package/dist/scanner/scanner.d.ts.map +1 -0
  41. package/dist/scanner/scanner.js +463 -0
  42. package/dist/scanner/scanner.js.map +1 -0
  43. package/dist/server/index.d.ts +7 -0
  44. package/dist/server/index.d.ts.map +1 -0
  45. package/dist/server/index.js +7 -0
  46. package/dist/server/index.js.map +1 -0
  47. package/dist/server/middleware.d.ts +51 -0
  48. package/dist/server/middleware.d.ts.map +1 -0
  49. package/dist/server/middleware.js +124 -0
  50. package/dist/server/middleware.js.map +1 -0
  51. package/dist/server/server.d.ts +29 -0
  52. package/dist/server/server.d.ts.map +1 -0
  53. package/dist/server/server.js +314 -0
  54. package/dist/server/server.js.map +1 -0
  55. package/dist/states/index.d.ts +6 -0
  56. package/dist/states/index.d.ts.map +1 -0
  57. package/dist/states/index.js +6 -0
  58. package/dist/states/index.js.map +1 -0
  59. package/dist/states/states.d.ts +57 -0
  60. package/dist/states/states.d.ts.map +1 -0
  61. package/dist/states/states.js +89 -0
  62. package/dist/states/states.js.map +1 -0
  63. package/dist/types.d.ts +214 -0
  64. package/dist/types.d.ts.map +1 -0
  65. package/dist/types.js +6 -0
  66. package/dist/types.js.map +1 -0
  67. package/package.json +66 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=browser-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-guard.d.ts","sourceRoot":"","sources":["../src/browser-guard.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,CAAA"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Browser guard — `@molecule/api-mock-server` is SERVER-ONLY.
3
+ *
4
+ * Generated by scripts/gen-browser-guards.mjs (workspace root) — edit THAT, not this.
5
+ * Evaluating a server package in a browser bundle is always an import-graph mistake
6
+ * (node APIs, secrets); without this guard it surfaces as a cryptic downstream crash
7
+ * ("Buffer is not defined") far from the culprit. Throwing here names the package and
8
+ * the fix at the exact moment the client bundle evaluates it. jsdom tests and SSR are
9
+ * unaffected: the throw requires browser globals AND the absence of a node runtime.
10
+ */
11
+ const g = globalThis;
12
+ if (g.window !== undefined && g.document !== undefined && !g.process?.versions?.node) {
13
+ throw new Error('@molecule/api-mock-server is SERVER-ONLY: it was bundled into browser/client code. Import it only ' +
14
+ 'from server code (a server route/function or your API), or dynamic-import it inside ' +
15
+ 'the server handler — never from components or shared client modules, and never ' +
16
+ 'polyfill Buffer/process to silence this.');
17
+ }
18
+ export {};
19
+ //# sourceMappingURL=browser-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-guard.js","sourceRoot":"","sources":["../src/browser-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,GAAG,UAIT,CAAA;AACD,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACrF,MAAM,IAAI,KAAK,CACb,oGAAoG;QAClG,sFAAsF;QACtF,iFAAiF;QACjF,0CAA0C,CAC7C,CAAA;AACH,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI entrypoint for the mock API server.
4
+ *
5
+ * Usage:
6
+ * npx \@molecule/api-mock-server --app personal-finance --port 4000
7
+ * npx \@molecule/api-mock-server --fixtures-path ./fixtures --port 4000
8
+ * npx \@molecule/api-mock-server --app online-store --port 4015 --state success
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG"}
package/dist/cli.js ADDED
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI entrypoint for the mock API server.
4
+ *
5
+ * Usage:
6
+ * npx \@molecule/api-mock-server --app personal-finance --port 4000
7
+ * npx \@molecule/api-mock-server --fixtures-path ./fixtures --port 4000
8
+ * npx \@molecule/api-mock-server --app online-store --port 4015 --state success
9
+ */
10
+ import { createMockServer } from './server/server.js';
11
+ /**
12
+ *
13
+ * @param argv
14
+ */
15
+ function parseArgs(argv) {
16
+ const args = {
17
+ app: '',
18
+ port: 4000,
19
+ state: 'success',
20
+ delay: 0,
21
+ help: false,
22
+ };
23
+ for (let i = 2; i < argv.length; i++) {
24
+ const arg = argv[i];
25
+ const next = argv[i + 1];
26
+ switch (arg) {
27
+ case '--app':
28
+ case '-a':
29
+ args.app = next ?? '';
30
+ i++;
31
+ break;
32
+ case '--fixtures-path':
33
+ case '--fixtures':
34
+ args.fixturesPath = next;
35
+ i++;
36
+ break;
37
+ case '--port':
38
+ case '-p': {
39
+ // Number(next) || 4000 would coerce a valid `--port 0` (ephemeral
40
+ // port) to 4000 — only fall back when the value isn't a port at all.
41
+ const port = Number(next);
42
+ if (Number.isInteger(port) && port >= 0 && port <= 65535) {
43
+ args.port = port;
44
+ }
45
+ else {
46
+ // Same disambiguation as --state: a silent fallback reads as
47
+ // "the flag was applied" while the server listens elsewhere.
48
+ console.warn(`Warning: invalid --port "${next ?? ''}" (expected 0-65535) — using 4000.`);
49
+ }
50
+ i++;
51
+ break;
52
+ }
53
+ case '--state':
54
+ case '-s':
55
+ if (next && ['success', 'empty', 'error', 'unauthorized'].includes(next)) {
56
+ args.state = next;
57
+ }
58
+ else {
59
+ // A typo'd state silently serving 'success' is a debugging trap.
60
+ console.warn(`Warning: invalid --state "${next ?? ''}" (expected success|empty|error|unauthorized) — using "success".`);
61
+ }
62
+ i++;
63
+ break;
64
+ case '--delay':
65
+ case '-d': {
66
+ const delay = Number(next);
67
+ if (Number.isFinite(delay) && delay >= 0) {
68
+ args.delay = delay;
69
+ }
70
+ else {
71
+ console.warn(`Warning: invalid --delay "${next ?? ''}" (expected milliseconds >= 0) — using 0.`);
72
+ }
73
+ i++;
74
+ break;
75
+ }
76
+ case '--handlers-path':
77
+ args.handlersPath = next;
78
+ i++;
79
+ break;
80
+ case '--help':
81
+ case '-h':
82
+ args.help = true;
83
+ break;
84
+ }
85
+ }
86
+ return args;
87
+ }
88
+ /**
89
+ *
90
+ */
91
+ function printHelp() {
92
+ console.log(`
93
+ @molecule/api-mock-server - Mock API server with fixture data from JSON files
94
+
95
+ Usage:
96
+ npx @molecule/api-mock-server --app <app-type> [options]
97
+ npx @molecule/api-mock-server --fixtures-path <path> [options]
98
+
99
+ Options:
100
+ --app, -a <type> App type to serve (resolves fixtures from mlcl/templates/apps/{type}/api/fixtures/)
101
+ --fixtures-path <path> Explicit path to a directory of JSON fixture files
102
+ --port, -p <port> Port to listen on (default: 4000)
103
+ --state, -s <state> Default response state: success|empty|error|unauthorized (default: success)
104
+ --delay, -d <ms> Default response delay in milliseconds (default: 0)
105
+ --handlers-path <path> Custom path to handler template files
106
+ --help, -h Show this help message
107
+
108
+ Examples:
109
+ npx @molecule/api-mock-server --app personal-finance --port 4000
110
+ npx @molecule/api-mock-server --fixtures-path ./my-app/api/fixtures --port 4000
111
+ npx @molecule/api-mock-server --app online-store --state empty
112
+ npx @molecule/api-mock-server --app personal-finance --delay 500
113
+ `);
114
+ }
115
+ /**
116
+ *
117
+ */
118
+ async function main() {
119
+ const args = parseArgs(process.argv);
120
+ if (args.help) {
121
+ printHelp();
122
+ process.exit(0);
123
+ }
124
+ if (!args.app && !args.fixturesPath) {
125
+ console.error('Error: --app or --fixtures-path is required. Use --help for usage.');
126
+ process.exit(1);
127
+ }
128
+ try {
129
+ const server = await createMockServer({
130
+ appType: args.app || 'custom',
131
+ fixturesPath: args.fixturesPath,
132
+ port: args.port,
133
+ defaultState: args.state,
134
+ defaultDelay: args.delay,
135
+ handlersPath: args.handlersPath,
136
+ });
137
+ // Handle graceful shutdown
138
+ const shutdown = async () => {
139
+ console.log('\nShutting down mock server...');
140
+ await server.close();
141
+ process.exit(0);
142
+ };
143
+ process.on('SIGINT', shutdown);
144
+ process.on('SIGTERM', shutdown);
145
+ }
146
+ catch (error) {
147
+ console.error('Failed to start mock server:', error.message);
148
+ process.exit(1);
149
+ }
150
+ }
151
+ main();
152
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Fixture loading from JSON files in a directory.
3
+ * Each JSON file becomes a resource or endpoint group.
4
+ * No hardcoded app-specific data — all data lives in template fixture directories.
5
+ */
6
+ import type { AppDataPool, AppFixtureSet, EndpointDefinition } from '../types.js';
7
+ /**
8
+ * Load an AppDataPool from a directory of JSON fixture files.
9
+ *
10
+ * File naming conventions:
11
+ * - Array files (e.g. `products.json` containing `[...]`) become CRUD resources
12
+ * - Object files (e.g. `reports.json` containing `{key: ...}`) become sub-endpoint groups
13
+ * where each key maps to a GET endpoint
14
+ *
15
+ * Special filenames are treated as report/sub-endpoint groups (object shape expected):
16
+ * `reports.json`, `storefront.json`, `admin.json`
17
+ *
18
+ * All other files are treated as array resources by default.
19
+ *
20
+ * @param fixturesDir - Absolute path to the fixtures directory
21
+ * @param appType - App type label (for the returned pool metadata)
22
+ * @returns An AppDataPool, or undefined if the directory doesn't exist or is empty
23
+ */
24
+ export declare function loadFixturesFromDirectory(fixturesDir: string, appType: string): AppDataPool | undefined;
25
+ /**
26
+ * Get an AppDataPool for a fixtures directory, with fingerprint-validated
27
+ * caching: editing/adding/removing a `*.json` fixture file (mtime or size
28
+ * change) invalidates the cached pool, so a mock server re-created in the
29
+ * same process serves the fresh data instead of the first load.
30
+ * @param fixturesDir - Absolute path to the fixtures directory
31
+ * @param appType - App type label
32
+ * @returns The loaded pool, or undefined if directory missing/empty
33
+ */
34
+ export declare function getAppDataPool(fixturesDir: string, appType: string): AppDataPool | undefined;
35
+ /**
36
+ * Build a complete fixture set for an app type by combining
37
+ * data pool records with endpoint definitions.
38
+ * @param appType - The app type
39
+ * @param endpoints - The discovered endpoints from scanning
40
+ * @param fixturesDir - Path to the fixtures directory
41
+ * @returns A complete fixture set, or undefined if no data available
42
+ */
43
+ export declare function buildFixtureSet(appType: string, endpoints: EndpointDefinition[], fixturesDir?: string): AppFixtureSet | undefined;
44
+ /**
45
+ * Generate fixtures from a directory of JSON files without scanning handlers.
46
+ * Builds standard CRUD endpoints for each resource file and custom endpoints
47
+ * for each sub-endpoint group.
48
+ *
49
+ * @param fixturesDir - Absolute path to the fixtures directory
50
+ * @param appType - App type label (default: derived from directory name)
51
+ * @returns A fixture set with standard CRUD endpoints, or undefined if no data
52
+ */
53
+ export declare function generateFixtures(fixturesDir: string, appType?: string): AppFixtureSet | undefined;
54
+ //# sourceMappingURL=app-fixtures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-fixtures.d.ts","sourceRoot":"","sources":["../../src/fixtures/app-fixtures.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACb,kBAAkB,EAGnB,MAAM,aAAa,CAAA;AAsIpB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,WAAW,GAAG,SAAS,CAyDzB;AAkCD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAU5F;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,kBAAkB,EAAE,EAC/B,WAAW,CAAC,EAAE,MAAM,GACnB,aAAa,GAAG,SAAS,CAc3B;AAoID;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CA0NjG"}