@aggiovato/yrest 0.1.0 → 0.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.mts CHANGED
@@ -2,37 +2,158 @@ import * as fastify from 'fastify';
2
2
  import * as http from 'http';
3
3
  import { z } from 'zod';
4
4
 
5
+ /** A single REST resource item. Field names and value types are user-defined in the YAML file. */
5
6
  type Resource = Record<string, unknown>;
6
- type DbData = Record<string, Resource[]>;
7
+ /**
8
+ * The full in-memory database.
9
+ * Keys are collection names (e.g. `"users"`); values are arrays of {@link Resource} items.
10
+ */
11
+ type Data = Record<string, Resource[]>;
12
+ /**
13
+ * Relational mappings declared under `_rel` in the YAML file.
14
+ *
15
+ * - Outer key: child collection name.
16
+ * - Inner key: foreign key field on the child.
17
+ * - Inner value: parent collection name.
18
+ *
19
+ * @example
20
+ * // Given: _rel: { posts: { userId: users } }
21
+ * // GET /users/1/posts → returns posts where userId === "1"
22
+ */
7
23
  type Relations = Record<string, Record<string, string>>;
8
24
 
25
+ /**
26
+ * In-memory store backed by a YAML file.
27
+ *
28
+ * All reads operate on a live in-memory snapshot. Writes must be explicitly
29
+ * flushed to disk by calling {@link persist}. Use {@link reload} to pull in
30
+ * changes made to the file externally (e.g. in watch mode).
31
+ */
9
32
  interface YamlStorage {
10
- getData(): DbData;
33
+ /** Returns the full in-memory dataset (all collections). */
34
+ getData(): Data;
35
+ /** Returns the relational mappings declared under `_rel`. */
11
36
  getRelations(): Relations;
37
+ /**
38
+ * Returns the items in a named collection, or `undefined` if it does not exist.
39
+ *
40
+ * @param name - Collection name as declared in the YAML file (e.g. `"users"`).
41
+ */
12
42
  getCollection(name: string): Resource[] | undefined;
43
+ /**
44
+ * Replaces the items of a named collection in memory.
45
+ * Call {@link persist} afterwards to flush the change to disk.
46
+ *
47
+ * @param name - Collection name.
48
+ * @param items - New array of items to store.
49
+ */
13
50
  setCollection(name: string, items: Resource[]): void;
51
+ /**
52
+ * Atomically writes the current in-memory state to the YAML file.
53
+ *
54
+ * Uses a write-to-temp-then-rename strategy so a crash during the write
55
+ * never leaves the file in a partially written state.
56
+ *
57
+ * @throws {Error} If the filesystem write or rename fails.
58
+ */
14
59
  persist(): void;
60
+ /**
61
+ * Reloads the YAML file from disk and updates the in-memory state in place.
62
+ *
63
+ * Mutates the existing `data` and `relations` objects rather than replacing them,
64
+ * so any code holding a reference to the storage instance sees the updated values
65
+ * without needing to re-fetch.
66
+ *
67
+ * @throws {Error} If the file cannot be read or the YAML is malformed.
68
+ */
69
+ reload(): void;
15
70
  }
71
+ /**
72
+ * Creates a {@link YamlStorage} instance backed by the given YAML file.
73
+ *
74
+ * The file is read and parsed eagerly on construction. The `_rel` key is
75
+ * extracted as relational metadata; all other top-level keys become collections.
76
+ *
77
+ * @param filePath - Relative or absolute path to the YAML database file.
78
+ * @throws {Error} If the file cannot be read or its YAML is invalid.
79
+ */
16
80
  declare function createYamlStorage(filePath: string): YamlStorage;
17
81
 
82
+ /**
83
+ * Zod schema for all server runtime options.
84
+ *
85
+ * Validates and normalises options from three sources in ascending priority:
86
+ * schema defaults → `yrest.config.yml` → explicit CLI flags.
87
+ */
18
88
  declare const serverOptionsSchema: z.ZodObject<{
89
+ /** Path to the YAML database file. Must be a non-empty string. */
19
90
  file: z.ZodString;
91
+ /** TCP port the server listens on. Accepts string input and coerces to number. */
20
92
  port: z.ZodDefault<z.ZodNumber>;
93
+ /** Hostname or IP address to bind. */
21
94
  host: z.ZodDefault<z.ZodString>;
95
+ /**
96
+ * URL prefix prepended to every route (e.g. `/api`).
97
+ * A leading slash is added automatically if omitted.
98
+ */
22
99
  base: z.ZodEffects<z.ZodDefault<z.ZodString>, string, string | undefined>;
100
+ /** When `true`, the server reloads the YAML file automatically on disk changes. */
101
+ watch: z.ZodDefault<z.ZodBoolean>;
102
+ /** When `true`, all mutating requests (POST, PUT, PATCH, DELETE) are rejected with 405. */
103
+ readonly: z.ZodDefault<z.ZodBoolean>;
104
+ /** Milliseconds to delay every response, simulating network latency. `0` = disabled. */
105
+ delay: z.ZodDefault<z.ZodNumber>;
106
+ /**
107
+ * Wraps GET collection responses in a `{ data, pagination }` envelope.
108
+ * Accepts `true` (default limit 10), `false` (disabled), or a positive integer (custom limit).
109
+ */
110
+ pageable: z.ZodEffects<z.ZodDefault<z.ZodUnion<[z.ZodBoolean, z.ZodNumber]>>, {
111
+ enabled: boolean;
112
+ limit: number;
113
+ }, number | boolean | undefined>;
23
114
  }, "strip", z.ZodTypeAny, {
24
115
  file: string;
25
116
  port: number;
26
117
  host: string;
27
118
  base: string;
119
+ watch: boolean;
120
+ readonly: boolean;
121
+ delay: number;
122
+ pageable: {
123
+ enabled: boolean;
124
+ limit: number;
125
+ };
28
126
  }, {
29
127
  file: string;
30
128
  port?: number | undefined;
31
129
  host?: string | undefined;
32
130
  base?: string | undefined;
131
+ watch?: boolean | undefined;
132
+ readonly?: boolean | undefined;
133
+ delay?: number | undefined;
134
+ pageable?: number | boolean | undefined;
33
135
  }>;
136
+ /**
137
+ * Resolved server configuration after Zod validation and transformation.
138
+ * Inferred from {@link serverOptionsSchema}.
139
+ */
34
140
  type ServerOptions = z.infer<typeof serverOptionsSchema>;
35
141
 
142
+ /**
143
+ * Creates and configures a Fastify instance wired to the given YAML storage.
144
+ *
145
+ * Registers, in order:
146
+ * 1. CORS (all origins, permissive defaults).
147
+ * 2. Readonly guard hook — rejects mutating requests with 405 when enabled.
148
+ * 3. Delay hook — defers `onSend` by N ms when enabled.
149
+ * 4. All resource routes derived from the storage collections.
150
+ *
151
+ * The server is returned before `listen()` is called so tests can inject
152
+ * requests without binding a real port.
153
+ *
154
+ * @param storage - Initialised YAML storage instance.
155
+ * @param options - Validated server options.
156
+ */
36
157
  declare function createServer(storage: YamlStorage, options: ServerOptions): Promise<fastify.FastifyInstance<http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>, http.IncomingMessage, http.ServerResponse<http.IncomingMessage>, fastify.FastifyBaseLogger, fastify.FastifyTypeProviderDefault>>;
37
158
 
38
- export { type DbData, type Relations, type Resource, type ServerOptions, createServer, createYamlStorage, serverOptionsSchema };
159
+ export { type Data, type Relations, type Resource, type ServerOptions, createServer, createYamlStorage, serverOptionsSchema };
package/dist/index.d.ts CHANGED
@@ -2,37 +2,158 @@ import * as fastify from 'fastify';
2
2
  import * as http from 'http';
3
3
  import { z } from 'zod';
4
4
 
5
+ /** A single REST resource item. Field names and value types are user-defined in the YAML file. */
5
6
  type Resource = Record<string, unknown>;
6
- type DbData = Record<string, Resource[]>;
7
+ /**
8
+ * The full in-memory database.
9
+ * Keys are collection names (e.g. `"users"`); values are arrays of {@link Resource} items.
10
+ */
11
+ type Data = Record<string, Resource[]>;
12
+ /**
13
+ * Relational mappings declared under `_rel` in the YAML file.
14
+ *
15
+ * - Outer key: child collection name.
16
+ * - Inner key: foreign key field on the child.
17
+ * - Inner value: parent collection name.
18
+ *
19
+ * @example
20
+ * // Given: _rel: { posts: { userId: users } }
21
+ * // GET /users/1/posts → returns posts where userId === "1"
22
+ */
7
23
  type Relations = Record<string, Record<string, string>>;
8
24
 
25
+ /**
26
+ * In-memory store backed by a YAML file.
27
+ *
28
+ * All reads operate on a live in-memory snapshot. Writes must be explicitly
29
+ * flushed to disk by calling {@link persist}. Use {@link reload} to pull in
30
+ * changes made to the file externally (e.g. in watch mode).
31
+ */
9
32
  interface YamlStorage {
10
- getData(): DbData;
33
+ /** Returns the full in-memory dataset (all collections). */
34
+ getData(): Data;
35
+ /** Returns the relational mappings declared under `_rel`. */
11
36
  getRelations(): Relations;
37
+ /**
38
+ * Returns the items in a named collection, or `undefined` if it does not exist.
39
+ *
40
+ * @param name - Collection name as declared in the YAML file (e.g. `"users"`).
41
+ */
12
42
  getCollection(name: string): Resource[] | undefined;
43
+ /**
44
+ * Replaces the items of a named collection in memory.
45
+ * Call {@link persist} afterwards to flush the change to disk.
46
+ *
47
+ * @param name - Collection name.
48
+ * @param items - New array of items to store.
49
+ */
13
50
  setCollection(name: string, items: Resource[]): void;
51
+ /**
52
+ * Atomically writes the current in-memory state to the YAML file.
53
+ *
54
+ * Uses a write-to-temp-then-rename strategy so a crash during the write
55
+ * never leaves the file in a partially written state.
56
+ *
57
+ * @throws {Error} If the filesystem write or rename fails.
58
+ */
14
59
  persist(): void;
60
+ /**
61
+ * Reloads the YAML file from disk and updates the in-memory state in place.
62
+ *
63
+ * Mutates the existing `data` and `relations` objects rather than replacing them,
64
+ * so any code holding a reference to the storage instance sees the updated values
65
+ * without needing to re-fetch.
66
+ *
67
+ * @throws {Error} If the file cannot be read or the YAML is malformed.
68
+ */
69
+ reload(): void;
15
70
  }
71
+ /**
72
+ * Creates a {@link YamlStorage} instance backed by the given YAML file.
73
+ *
74
+ * The file is read and parsed eagerly on construction. The `_rel` key is
75
+ * extracted as relational metadata; all other top-level keys become collections.
76
+ *
77
+ * @param filePath - Relative or absolute path to the YAML database file.
78
+ * @throws {Error} If the file cannot be read or its YAML is invalid.
79
+ */
16
80
  declare function createYamlStorage(filePath: string): YamlStorage;
17
81
 
82
+ /**
83
+ * Zod schema for all server runtime options.
84
+ *
85
+ * Validates and normalises options from three sources in ascending priority:
86
+ * schema defaults → `yrest.config.yml` → explicit CLI flags.
87
+ */
18
88
  declare const serverOptionsSchema: z.ZodObject<{
89
+ /** Path to the YAML database file. Must be a non-empty string. */
19
90
  file: z.ZodString;
91
+ /** TCP port the server listens on. Accepts string input and coerces to number. */
20
92
  port: z.ZodDefault<z.ZodNumber>;
93
+ /** Hostname or IP address to bind. */
21
94
  host: z.ZodDefault<z.ZodString>;
95
+ /**
96
+ * URL prefix prepended to every route (e.g. `/api`).
97
+ * A leading slash is added automatically if omitted.
98
+ */
22
99
  base: z.ZodEffects<z.ZodDefault<z.ZodString>, string, string | undefined>;
100
+ /** When `true`, the server reloads the YAML file automatically on disk changes. */
101
+ watch: z.ZodDefault<z.ZodBoolean>;
102
+ /** When `true`, all mutating requests (POST, PUT, PATCH, DELETE) are rejected with 405. */
103
+ readonly: z.ZodDefault<z.ZodBoolean>;
104
+ /** Milliseconds to delay every response, simulating network latency. `0` = disabled. */
105
+ delay: z.ZodDefault<z.ZodNumber>;
106
+ /**
107
+ * Wraps GET collection responses in a `{ data, pagination }` envelope.
108
+ * Accepts `true` (default limit 10), `false` (disabled), or a positive integer (custom limit).
109
+ */
110
+ pageable: z.ZodEffects<z.ZodDefault<z.ZodUnion<[z.ZodBoolean, z.ZodNumber]>>, {
111
+ enabled: boolean;
112
+ limit: number;
113
+ }, number | boolean | undefined>;
23
114
  }, "strip", z.ZodTypeAny, {
24
115
  file: string;
25
116
  port: number;
26
117
  host: string;
27
118
  base: string;
119
+ watch: boolean;
120
+ readonly: boolean;
121
+ delay: number;
122
+ pageable: {
123
+ enabled: boolean;
124
+ limit: number;
125
+ };
28
126
  }, {
29
127
  file: string;
30
128
  port?: number | undefined;
31
129
  host?: string | undefined;
32
130
  base?: string | undefined;
131
+ watch?: boolean | undefined;
132
+ readonly?: boolean | undefined;
133
+ delay?: number | undefined;
134
+ pageable?: number | boolean | undefined;
33
135
  }>;
136
+ /**
137
+ * Resolved server configuration after Zod validation and transformation.
138
+ * Inferred from {@link serverOptionsSchema}.
139
+ */
34
140
  type ServerOptions = z.infer<typeof serverOptionsSchema>;
35
141
 
142
+ /**
143
+ * Creates and configures a Fastify instance wired to the given YAML storage.
144
+ *
145
+ * Registers, in order:
146
+ * 1. CORS (all origins, permissive defaults).
147
+ * 2. Readonly guard hook — rejects mutating requests with 405 when enabled.
148
+ * 3. Delay hook — defers `onSend` by N ms when enabled.
149
+ * 4. All resource routes derived from the storage collections.
150
+ *
151
+ * The server is returned before `listen()` is called so tests can inject
152
+ * requests without binding a real port.
153
+ *
154
+ * @param storage - Initialised YAML storage instance.
155
+ * @param options - Validated server options.
156
+ */
36
157
  declare function createServer(storage: YamlStorage, options: ServerOptions): Promise<fastify.FastifyInstance<http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>, http.IncomingMessage, http.ServerResponse<http.IncomingMessage>, fastify.FastifyBaseLogger, fastify.FastifyTypeProviderDefault>>;
37
158
 
38
- export { type DbData, type Relations, type Resource, type ServerOptions, createServer, createYamlStorage, serverOptionsSchema };
159
+ export { type Data, type Relations, type Resource, type ServerOptions, createServer, createYamlStorage, serverOptionsSchema };