@shaferllc/keel 0.68.0 → 0.74.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/AGENTS.md +2 -0
- package/README.md +14 -5
- package/dist/api/api.config.stub +9 -0
- package/dist/api/config.d.ts +13 -0
- package/dist/api/config.js +14 -0
- package/dist/api/index.d.ts +16 -0
- package/dist/api/index.js +13 -0
- package/dist/api/provider.d.ts +10 -0
- package/dist/api/provider.js +17 -0
- package/dist/api/query.d.ts +35 -0
- package/dist/api/query.js +42 -0
- package/dist/api/resource.d.ts +91 -0
- package/dist/api/resource.js +188 -0
- package/dist/core/application.js +6 -0
- package/dist/core/cache.d.ts +1 -2
- package/dist/core/cache.js +9 -2
- package/dist/core/cli/stubs.d.ts +14 -0
- package/dist/core/cli/stubs.js +105 -0
- package/dist/core/console-prompt.d.ts +79 -0
- package/dist/core/console-prompt.js +239 -0
- package/dist/core/console-ui.d.ts +96 -0
- package/dist/core/console-ui.js +187 -0
- package/dist/core/console.d.ts +188 -0
- package/dist/core/console.js +395 -0
- package/dist/core/database.d.ts +70 -1
- package/dist/core/database.js +174 -15
- package/dist/core/env.d.ts +96 -0
- package/dist/core/env.js +140 -0
- package/dist/core/health.d.ts +2 -2
- package/dist/core/health.js +2 -2
- package/dist/core/http/kernel.d.ts +2 -0
- package/dist/core/http/kernel.js +48 -0
- package/dist/core/http/router.d.ts +5 -5
- package/dist/core/http/router.js +5 -5
- package/dist/core/i18n.d.ts +162 -0
- package/dist/core/i18n.js +472 -0
- package/dist/core/index.d.ts +25 -4
- package/dist/core/index.js +13 -3
- package/dist/core/instrumentation.d.ts +113 -0
- package/dist/core/instrumentation.js +52 -0
- package/dist/core/logger.d.ts +7 -0
- package/dist/core/logger.js +28 -1
- package/dist/core/notification.js +10 -1
- package/dist/core/package.d.ts +120 -0
- package/dist/core/package.js +169 -0
- package/dist/core/pages.d.ts +108 -0
- package/dist/core/pages.js +199 -0
- package/dist/core/queue.js +26 -5
- package/dist/core/repl.d.ts +33 -0
- package/dist/core/repl.js +88 -0
- package/dist/core/scheduler.js +6 -0
- package/dist/core/social.d.ts +4 -4
- package/dist/core/social.js +4 -4
- package/dist/core/storage.js +15 -3
- package/dist/core/telemetry.d.ts +208 -0
- package/dist/core/telemetry.js +383 -0
- package/dist/core/template.d.ts +2 -3
- package/dist/core/template.js +2 -3
- package/dist/core/testing.d.ts +170 -1
- package/dist/core/testing.js +504 -2
- package/dist/db/d1.js +13 -0
- package/dist/db/pg.d.ts +13 -0
- package/dist/db/pg.js +46 -4
- package/dist/openapi/config.d.ts +28 -0
- package/dist/openapi/config.js +25 -0
- package/dist/openapi/doc.d.ts +40 -0
- package/dist/openapi/doc.js +20 -0
- package/dist/openapi/export.d.ts +8 -0
- package/dist/openapi/export.js +19 -0
- package/dist/openapi/gate.d.ts +15 -0
- package/dist/openapi/gate.js +27 -0
- package/dist/openapi/index.d.ts +19 -0
- package/dist/openapi/index.js +15 -0
- package/dist/openapi/openapi.config.stub +29 -0
- package/dist/openapi/provider.d.ts +18 -0
- package/dist/openapi/provider.js +35 -0
- package/dist/openapi/routes.d.ts +9 -0
- package/dist/openapi/routes.js +23 -0
- package/dist/openapi/spec.d.ts +23 -0
- package/dist/openapi/spec.js +132 -0
- package/dist/openapi/ui.d.ts +8 -0
- package/dist/openapi/ui.js +31 -0
- package/dist/openapi/zod.d.ts +12 -0
- package/dist/openapi/zod.js +46 -0
- package/dist/watch/config.d.ts +33 -0
- package/dist/watch/config.js +38 -0
- package/dist/watch/entry.d.ts +53 -0
- package/dist/watch/entry.js +105 -0
- package/dist/watch/gate.d.ts +20 -0
- package/dist/watch/gate.js +32 -0
- package/dist/watch/index.d.ts +21 -0
- package/dist/watch/index.js +17 -0
- package/dist/watch/migration.d.ts +7 -0
- package/dist/watch/migration.js +20 -0
- package/dist/watch/provider.d.ts +22 -0
- package/dist/watch/provider.js +58 -0
- package/dist/watch/prune.d.ts +11 -0
- package/dist/watch/prune.js +20 -0
- package/dist/watch/recorder.d.ts +24 -0
- package/dist/watch/recorder.js +39 -0
- package/dist/watch/routes.d.ts +13 -0
- package/dist/watch/routes.js +55 -0
- package/dist/watch/store.d.ts +54 -0
- package/dist/watch/store.js +158 -0
- package/dist/watch/ui/dist/watch.css +1 -0
- package/dist/watch/ui/dist/watch.js +555 -0
- package/dist/watch/ui-shell.d.ts +12 -0
- package/dist/watch/ui-shell.js +24 -0
- package/dist/watch/watch.config.stub +47 -0
- package/dist/watch/watchers.d.ts +12 -0
- package/dist/watch/watchers.js +156 -0
- package/docs/ai-manifest.json +737 -3
- package/docs/api-resources.md +118 -0
- package/docs/configuration.md +74 -0
- package/docs/console.md +193 -13
- package/docs/database.md +101 -0
- package/docs/examples/configuration.ts +40 -0
- package/docs/examples/console.ts +134 -0
- package/docs/examples/database.ts +90 -0
- package/docs/examples/i18n.ts +117 -0
- package/docs/examples/logger.ts +74 -0
- package/docs/examples/mail.ts +103 -0
- package/docs/examples/pages.ts +82 -0
- package/docs/examples/telemetry.ts +127 -0
- package/docs/examples/testing.ts +149 -0
- package/docs/health.md +4 -4
- package/docs/i18n.md +302 -0
- package/docs/logger.md +156 -10
- package/docs/mail.md +73 -0
- package/docs/openapi.md +111 -0
- package/docs/packages.md +118 -0
- package/docs/pages.md +217 -0
- package/docs/storage.md +5 -3
- package/docs/telemetry.md +263 -0
- package/docs/templates.md +3 -4
- package/docs/testing.md +251 -0
- package/docs/watch.md +118 -0
- package/llms-full.txt +2370 -248
- package/llms.txt +12 -1
- package/package.json +18 -2
package/dist/core/testing.d.ts
CHANGED
|
@@ -33,17 +33,79 @@ export declare class TestResponse {
|
|
|
33
33
|
assertHeader(name: string, value: string): this;
|
|
34
34
|
/** Assert a redirect (3xx) to `location`. */
|
|
35
35
|
assertRedirect(location?: string): this;
|
|
36
|
+
assertCreated(): this;
|
|
37
|
+
assertNoContent(): this;
|
|
38
|
+
assertBadRequest(): this;
|
|
39
|
+
assertUnauthorized(): this;
|
|
40
|
+
assertForbidden(): this;
|
|
41
|
+
assertNotFound(): this;
|
|
42
|
+
/** 422 — the status a failed `validate()` returns. */
|
|
43
|
+
assertUnprocessable(): this;
|
|
44
|
+
assertServerError(): this;
|
|
45
|
+
/**
|
|
46
|
+
* Assert the JSON body *contains* `expected` — a subset match, so a test can
|
|
47
|
+
* pin the fields it cares about without breaking every time an unrelated one
|
|
48
|
+
* is added.
|
|
49
|
+
*
|
|
50
|
+
* res.assertJsonContains({ user: { email: "a@b.com" } });
|
|
51
|
+
*/
|
|
52
|
+
assertJsonContains(expected: unknown): this;
|
|
53
|
+
/** Assert the body contains `text` anywhere. */
|
|
54
|
+
assertSee(text: string): this;
|
|
55
|
+
/** Assert the body does *not* contain `text`. */
|
|
56
|
+
assertDontSee(text: string): this;
|
|
57
|
+
/**
|
|
58
|
+
* Assert a 422 carrying an error on each named field. With no fields, it just
|
|
59
|
+
* asserts that validation failed.
|
|
60
|
+
*
|
|
61
|
+
* res.assertValidationErrors("email", "password");
|
|
62
|
+
*/
|
|
63
|
+
assertValidationErrors(...fields: string[]): this;
|
|
64
|
+
/** Assert there is *no* validation error on `field`. */
|
|
65
|
+
assertNoValidationError(field: string): this;
|
|
66
|
+
assertHeaderMissing(name: string): this;
|
|
67
|
+
/** The cookies this response set, by name. */
|
|
68
|
+
cookies(): Record<string, string>;
|
|
69
|
+
/** Assert the response set a cookie — with `value`, if you give one. */
|
|
70
|
+
assertCookie(name: string, value?: string): this;
|
|
71
|
+
assertCookieMissing(name: string): this;
|
|
72
|
+
/** Print status, headers, and body — for when a test fails and you're stuck. */
|
|
73
|
+
dump(): this;
|
|
74
|
+
}
|
|
75
|
+
/** Defaults applied to every request a `TestClient` makes. */
|
|
76
|
+
interface ClientDefaults {
|
|
77
|
+
headers: Record<string, string>;
|
|
78
|
+
cookies: Record<string, string>;
|
|
36
79
|
}
|
|
37
80
|
/** Injects requests into an app and returns `TestResponse`s. */
|
|
38
81
|
export declare class TestClient {
|
|
39
82
|
private target;
|
|
40
|
-
|
|
83
|
+
private defaults;
|
|
84
|
+
constructor(target: Requestable, defaults?: ClientDefaults);
|
|
85
|
+
/** A copy of this client with extra default headers. */
|
|
86
|
+
withHeaders(headers: Record<string, string>): TestClient;
|
|
87
|
+
withHeader(name: string, value: string): TestClient;
|
|
88
|
+
/** A copy of this client that sends these cookies. */
|
|
89
|
+
withCookies(cookies: Record<string, string>): TestClient;
|
|
90
|
+
withCookie(name: string, value: string): TestClient;
|
|
91
|
+
/** Send `Authorization: Bearer <token>` — the shorthand for an API test. */
|
|
92
|
+
withToken(token: string): TestClient;
|
|
93
|
+
/** Send HTTP basic credentials. */
|
|
94
|
+
withBasicAuth(username: string, password: string): TestClient;
|
|
95
|
+
/** Ask for JSON back — sets `Accept: application/json`. */
|
|
96
|
+
acceptJson(): TestClient;
|
|
97
|
+
/** Merge the client's defaults into one request's init. */
|
|
98
|
+
private init;
|
|
41
99
|
request(path: string, init?: RequestInit): Promise<TestResponse>;
|
|
42
100
|
get(path: string, init?: RequestInit): Promise<TestResponse>;
|
|
43
101
|
delete(path: string, init?: RequestInit): Promise<TestResponse>;
|
|
44
102
|
post(path: string, body?: unknown, init?: RequestInit): Promise<TestResponse>;
|
|
45
103
|
put(path: string, body?: unknown, init?: RequestInit): Promise<TestResponse>;
|
|
46
104
|
patch(path: string, body?: unknown, init?: RequestInit): Promise<TestResponse>;
|
|
105
|
+
/** POST a URL-encoded form, the way a browser would. */
|
|
106
|
+
form(path: string, fields: Record<string, string | number | boolean>, init?: RequestInit): Promise<TestResponse>;
|
|
107
|
+
/** POST a multipart form — for file uploads. */
|
|
108
|
+
multipart(path: string, fields: Record<string, string | Blob>, init?: RequestInit): Promise<TestResponse>;
|
|
47
109
|
}
|
|
48
110
|
/**
|
|
49
111
|
* Build a `TestClient` from an `Application`, an `HttpKernel`, or anything with a
|
|
@@ -51,4 +113,111 @@ export declare class TestClient {
|
|
|
51
113
|
* `HttpKernel`; pass a kernel yourself if you need global middleware registered.
|
|
52
114
|
*/
|
|
53
115
|
export declare function testClient(target: Application | HttpKernel | Requestable): TestClient;
|
|
116
|
+
/**
|
|
117
|
+
* Put the framework's global state back the way it was, so one test can't leak
|
|
118
|
+
* into the next. Call it in an `afterEach`.
|
|
119
|
+
*
|
|
120
|
+
* afterEach(() => resetState());
|
|
121
|
+
*
|
|
122
|
+
* It restores every fake (disk, queue, mail, hash, time), drops event listeners,
|
|
123
|
+
* empties the cache, and gives you a fresh lock store. It does **not** touch the
|
|
124
|
+
* database — see `refreshDatabase()`.
|
|
125
|
+
*/
|
|
126
|
+
export declare function resetState(): void;
|
|
127
|
+
/** Whether time is currently frozen. */
|
|
128
|
+
export declare function timeIsFrozen(): boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Freeze the clock, so anything that reads the time sees the same instant —
|
|
131
|
+
* which is how you test a token that expires in an hour without waiting an hour.
|
|
132
|
+
*
|
|
133
|
+
* freezeTime("2026-07-11T12:00:00Z");
|
|
134
|
+
* timeTravel(3600_000); // an hour later
|
|
135
|
+
* restoreTime();
|
|
136
|
+
*
|
|
137
|
+
* Mocks `Date` and `Date.now()`. It does **not** mock timers: a `setTimeout` still
|
|
138
|
+
* fires on the real clock.
|
|
139
|
+
*/
|
|
140
|
+
export declare function freezeTime(at?: Date | number | string): number;
|
|
141
|
+
/** Move the frozen clock forward (or back, with a negative value) by milliseconds. */
|
|
142
|
+
export declare function timeTravel(ms: number): number;
|
|
143
|
+
/** Hand the real clock back. */
|
|
144
|
+
export declare function restoreTime(): void;
|
|
145
|
+
/** Assert at least one row in `table` matches `where` (an exact `count` if given). */
|
|
146
|
+
export declare function assertDatabaseHas(table: string, where: Record<string, unknown>, count?: number): Promise<void>;
|
|
147
|
+
/** Assert no row in `table` matches `where`. */
|
|
148
|
+
export declare function assertDatabaseMissing(table: string, where: Record<string, unknown>): Promise<void>;
|
|
149
|
+
/** Assert `table` holds exactly `count` rows. */
|
|
150
|
+
export declare function assertDatabaseCount(table: string, count: number): Promise<void>;
|
|
151
|
+
/** Assert `table` is empty. */
|
|
152
|
+
export declare function assertDatabaseEmpty(table: string): Promise<void>;
|
|
153
|
+
/**
|
|
154
|
+
* Empty tables between tests. Order matters when foreign keys do — pass children
|
|
155
|
+
* before parents.
|
|
156
|
+
*
|
|
157
|
+
* afterEach(() => truncate("comments", "posts", "users"));
|
|
158
|
+
*
|
|
159
|
+
* This deletes rows; it doesn't roll back a transaction, so it works on every
|
|
160
|
+
* driver (D1, Postgres, libSQL) rather than only the ones with savepoints.
|
|
161
|
+
*/
|
|
162
|
+
export declare function truncate(...tables: string[]): Promise<void>;
|
|
163
|
+
/** A recording stand-in for a function. */
|
|
164
|
+
export interface Spy<A extends unknown[] = unknown[], R = unknown> {
|
|
165
|
+
(...args: A): R;
|
|
166
|
+
/** The arguments of every call, in order. */
|
|
167
|
+
readonly calls: A[];
|
|
168
|
+
readonly callCount: number;
|
|
169
|
+
/** Whether it was called at all. */
|
|
170
|
+
readonly called: boolean;
|
|
171
|
+
/** Whether any call had exactly these arguments. */
|
|
172
|
+
calledWith(...args: A): boolean;
|
|
173
|
+
/** Make it return something (or something new). */
|
|
174
|
+
returns(value: R): Spy<A, R>;
|
|
175
|
+
reset(): void;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* A function that records how it was called — the smallest useful test double.
|
|
179
|
+
*
|
|
180
|
+
* const send = spy<[string], void>();
|
|
181
|
+
* notify(send);
|
|
182
|
+
* assert.equal(send.callCount, 1);
|
|
183
|
+
* assert.ok(send.calledWith("hello"));
|
|
184
|
+
*/
|
|
185
|
+
export declare function spy<A extends unknown[] = unknown[], R = unknown>(implementation?: (...args: A) => R): Spy<A, R>;
|
|
186
|
+
export declare function spyOn<T extends object, K extends keyof T>(target: T, method: K): Spy<unknown[], unknown>;
|
|
187
|
+
/** Undo every `spyOn()`. */
|
|
188
|
+
export declare function restoreSpies(): void;
|
|
189
|
+
/** What a command did: its output, its error output, and its exit code. */
|
|
190
|
+
export declare class CommandResult {
|
|
191
|
+
readonly stdout: string[];
|
|
192
|
+
readonly stderr: string[];
|
|
193
|
+
readonly exitCode: number;
|
|
194
|
+
constructor(stdout: string[], stderr: string[], exitCode: number);
|
|
195
|
+
/** Everything written to stdout, joined. */
|
|
196
|
+
output(): string;
|
|
197
|
+
assertExitCode(expected: number): this;
|
|
198
|
+
/** Exit code 0. */
|
|
199
|
+
assertSucceeded(): this;
|
|
200
|
+
/** A non-zero exit code. */
|
|
201
|
+
assertFailed(): this;
|
|
202
|
+
/** Assert a line of output contains `text`. */
|
|
203
|
+
assertOutputContains(text: string): this;
|
|
204
|
+
assertOutputMatches(pattern: RegExp): this;
|
|
205
|
+
assertErrorContains(text: string): this;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Run a console command in-process and capture what it printed and the exit code
|
|
209
|
+
* it set — no subprocess, so it's fast and you can assert on it.
|
|
210
|
+
*
|
|
211
|
+
* You pass the command in, because the console entry point belongs to your app
|
|
212
|
+
* (it's the thing that knows how to build your application), not to the core:
|
|
213
|
+
*
|
|
214
|
+
* import { run } from "@shaferllc/keel/core/cli"; // or your own bin
|
|
215
|
+
*
|
|
216
|
+
* const result = await runCommand(() => run(["node", "keel", "routes"]));
|
|
217
|
+
* result.assertSucceeded().assertOutputContains("GET /users");
|
|
218
|
+
*
|
|
219
|
+
* `console.log`/`warn` are captured as stdout, `console.error` as stderr, and
|
|
220
|
+
* `process.exitCode` is read and then restored.
|
|
221
|
+
*/
|
|
222
|
+
export declare function runCommand(command: () => unknown | Promise<unknown>): Promise<CommandResult>;
|
|
54
223
|
export {};
|