@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.
Files changed (140) hide show
  1. package/AGENTS.md +2 -0
  2. package/README.md +14 -5
  3. package/dist/api/api.config.stub +9 -0
  4. package/dist/api/config.d.ts +13 -0
  5. package/dist/api/config.js +14 -0
  6. package/dist/api/index.d.ts +16 -0
  7. package/dist/api/index.js +13 -0
  8. package/dist/api/provider.d.ts +10 -0
  9. package/dist/api/provider.js +17 -0
  10. package/dist/api/query.d.ts +35 -0
  11. package/dist/api/query.js +42 -0
  12. package/dist/api/resource.d.ts +91 -0
  13. package/dist/api/resource.js +188 -0
  14. package/dist/core/application.js +6 -0
  15. package/dist/core/cache.d.ts +1 -2
  16. package/dist/core/cache.js +9 -2
  17. package/dist/core/cli/stubs.d.ts +14 -0
  18. package/dist/core/cli/stubs.js +105 -0
  19. package/dist/core/console-prompt.d.ts +79 -0
  20. package/dist/core/console-prompt.js +239 -0
  21. package/dist/core/console-ui.d.ts +96 -0
  22. package/dist/core/console-ui.js +187 -0
  23. package/dist/core/console.d.ts +188 -0
  24. package/dist/core/console.js +395 -0
  25. package/dist/core/database.d.ts +70 -1
  26. package/dist/core/database.js +174 -15
  27. package/dist/core/env.d.ts +96 -0
  28. package/dist/core/env.js +140 -0
  29. package/dist/core/health.d.ts +2 -2
  30. package/dist/core/health.js +2 -2
  31. package/dist/core/http/kernel.d.ts +2 -0
  32. package/dist/core/http/kernel.js +48 -0
  33. package/dist/core/http/router.d.ts +5 -5
  34. package/dist/core/http/router.js +5 -5
  35. package/dist/core/i18n.d.ts +162 -0
  36. package/dist/core/i18n.js +472 -0
  37. package/dist/core/index.d.ts +25 -4
  38. package/dist/core/index.js +13 -3
  39. package/dist/core/instrumentation.d.ts +113 -0
  40. package/dist/core/instrumentation.js +52 -0
  41. package/dist/core/logger.d.ts +7 -0
  42. package/dist/core/logger.js +28 -1
  43. package/dist/core/notification.js +10 -1
  44. package/dist/core/package.d.ts +120 -0
  45. package/dist/core/package.js +169 -0
  46. package/dist/core/pages.d.ts +108 -0
  47. package/dist/core/pages.js +199 -0
  48. package/dist/core/queue.js +26 -5
  49. package/dist/core/repl.d.ts +33 -0
  50. package/dist/core/repl.js +88 -0
  51. package/dist/core/scheduler.js +6 -0
  52. package/dist/core/social.d.ts +4 -4
  53. package/dist/core/social.js +4 -4
  54. package/dist/core/storage.js +15 -3
  55. package/dist/core/telemetry.d.ts +208 -0
  56. package/dist/core/telemetry.js +383 -0
  57. package/dist/core/template.d.ts +2 -3
  58. package/dist/core/template.js +2 -3
  59. package/dist/core/testing.d.ts +170 -1
  60. package/dist/core/testing.js +504 -2
  61. package/dist/db/d1.js +13 -0
  62. package/dist/db/pg.d.ts +13 -0
  63. package/dist/db/pg.js +46 -4
  64. package/dist/openapi/config.d.ts +28 -0
  65. package/dist/openapi/config.js +25 -0
  66. package/dist/openapi/doc.d.ts +40 -0
  67. package/dist/openapi/doc.js +20 -0
  68. package/dist/openapi/export.d.ts +8 -0
  69. package/dist/openapi/export.js +19 -0
  70. package/dist/openapi/gate.d.ts +15 -0
  71. package/dist/openapi/gate.js +27 -0
  72. package/dist/openapi/index.d.ts +19 -0
  73. package/dist/openapi/index.js +15 -0
  74. package/dist/openapi/openapi.config.stub +29 -0
  75. package/dist/openapi/provider.d.ts +18 -0
  76. package/dist/openapi/provider.js +35 -0
  77. package/dist/openapi/routes.d.ts +9 -0
  78. package/dist/openapi/routes.js +23 -0
  79. package/dist/openapi/spec.d.ts +23 -0
  80. package/dist/openapi/spec.js +132 -0
  81. package/dist/openapi/ui.d.ts +8 -0
  82. package/dist/openapi/ui.js +31 -0
  83. package/dist/openapi/zod.d.ts +12 -0
  84. package/dist/openapi/zod.js +46 -0
  85. package/dist/watch/config.d.ts +33 -0
  86. package/dist/watch/config.js +38 -0
  87. package/dist/watch/entry.d.ts +53 -0
  88. package/dist/watch/entry.js +105 -0
  89. package/dist/watch/gate.d.ts +20 -0
  90. package/dist/watch/gate.js +32 -0
  91. package/dist/watch/index.d.ts +21 -0
  92. package/dist/watch/index.js +17 -0
  93. package/dist/watch/migration.d.ts +7 -0
  94. package/dist/watch/migration.js +20 -0
  95. package/dist/watch/provider.d.ts +22 -0
  96. package/dist/watch/provider.js +58 -0
  97. package/dist/watch/prune.d.ts +11 -0
  98. package/dist/watch/prune.js +20 -0
  99. package/dist/watch/recorder.d.ts +24 -0
  100. package/dist/watch/recorder.js +39 -0
  101. package/dist/watch/routes.d.ts +13 -0
  102. package/dist/watch/routes.js +55 -0
  103. package/dist/watch/store.d.ts +54 -0
  104. package/dist/watch/store.js +158 -0
  105. package/dist/watch/ui/dist/watch.css +1 -0
  106. package/dist/watch/ui/dist/watch.js +555 -0
  107. package/dist/watch/ui-shell.d.ts +12 -0
  108. package/dist/watch/ui-shell.js +24 -0
  109. package/dist/watch/watch.config.stub +47 -0
  110. package/dist/watch/watchers.d.ts +12 -0
  111. package/dist/watch/watchers.js +156 -0
  112. package/docs/ai-manifest.json +737 -3
  113. package/docs/api-resources.md +118 -0
  114. package/docs/configuration.md +74 -0
  115. package/docs/console.md +193 -13
  116. package/docs/database.md +101 -0
  117. package/docs/examples/configuration.ts +40 -0
  118. package/docs/examples/console.ts +134 -0
  119. package/docs/examples/database.ts +90 -0
  120. package/docs/examples/i18n.ts +117 -0
  121. package/docs/examples/logger.ts +74 -0
  122. package/docs/examples/mail.ts +103 -0
  123. package/docs/examples/pages.ts +82 -0
  124. package/docs/examples/telemetry.ts +127 -0
  125. package/docs/examples/testing.ts +149 -0
  126. package/docs/health.md +4 -4
  127. package/docs/i18n.md +302 -0
  128. package/docs/logger.md +156 -10
  129. package/docs/mail.md +73 -0
  130. package/docs/openapi.md +111 -0
  131. package/docs/packages.md +118 -0
  132. package/docs/pages.md +217 -0
  133. package/docs/storage.md +5 -3
  134. package/docs/telemetry.md +263 -0
  135. package/docs/templates.md +3 -4
  136. package/docs/testing.md +251 -0
  137. package/docs/watch.md +118 -0
  138. package/llms-full.txt +2370 -248
  139. package/llms.txt +12 -1
  140. package/package.json +18 -2
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Terminal UI for console commands — colors, a logger, tables, boxes, and a task
3
+ * runner. No dependency: ANSI codes are a dozen escape sequences, not a package.
4
+ *
5
+ * ui.success("Migrated 3 tables");
6
+ * ui.table(["Name", "Rows"]).row(["users", "42"]).render();
7
+ *
8
+ * Everything goes through the same `write`, which is what makes the whole thing
9
+ * testable: `createUi({ raw: true })` strips the colors and buffers the output
10
+ * instead of printing it, so a test can assert on exactly what a command said.
11
+ */
12
+ /* -------------------------------- colors ---------------------------------- */
13
+ const CODES = {
14
+ reset: 0,
15
+ bold: 1,
16
+ dim: 2,
17
+ italic: 3,
18
+ underline: 4,
19
+ red: 31,
20
+ green: 32,
21
+ yellow: 33,
22
+ blue: 34,
23
+ magenta: 35,
24
+ cyan: 36,
25
+ white: 37,
26
+ gray: 90,
27
+ bgRed: 41,
28
+ bgGreen: 42,
29
+ bgYellow: 43,
30
+ };
31
+ function makeColors(enabled) {
32
+ const fn = ((name, text) => enabled ? `\u001b[${CODES[name]}m${text}\u001b[0m` : text);
33
+ fn.enabled = enabled;
34
+ return fn;
35
+ }
36
+ /** Strip ANSI escapes — used by the raw mode, and handy in assertions. */
37
+ export function stripAnsi(text) {
38
+ // eslint-disable-next-line no-control-regex
39
+ return text.replace(/\u001b\[\d+m/g, "");
40
+ }
41
+ const SYMBOLS = {
42
+ info: "›",
43
+ success: "✔",
44
+ warning: "⚠",
45
+ error: "✖",
46
+ debug: "·",
47
+ };
48
+ export function createUi(options = {}) {
49
+ const raw = options.raw ?? false;
50
+ const useColors = options.colors ?? (!raw && !process.env.NO_COLOR);
51
+ const colors = makeColors(useColors);
52
+ const logs = [];
53
+ const errors = [];
54
+ const write = (line) => {
55
+ if (raw)
56
+ logs.push(stripAnsi(line));
57
+ else
58
+ console.log(line);
59
+ };
60
+ const writeError = (line) => {
61
+ if (raw)
62
+ errors.push(stripAnsi(line));
63
+ else
64
+ console.error(line);
65
+ };
66
+ const label = (symbol, color, message) => `${colors(color, symbol)} ${message}`;
67
+ const ui = {
68
+ colors,
69
+ logs,
70
+ errors,
71
+ write,
72
+ debug: (message) => write(label(SYMBOLS.debug, "gray", colors("gray", message))),
73
+ info: (message) => write(label(SYMBOLS.info, "blue", message)),
74
+ success: (message) => write(label(SYMBOLS.success, "green", message)),
75
+ warning: (message) => write(label(SYMBOLS.warning, "yellow", message)),
76
+ error: (message) => writeError(label(SYMBOLS.error, "red", message)),
77
+ fatal: (message) => writeError(label(SYMBOLS.error, "red", colors("bold", message))),
78
+ action(verb, target, status = "done") {
79
+ const color = status === "failed" ? "red" : status === "skipped" ? "yellow" : "green";
80
+ const line = `${colors(color, verb.toUpperCase().padEnd(8))}${target}`;
81
+ if (status === "failed")
82
+ writeError(line);
83
+ else
84
+ write(line);
85
+ },
86
+ table(head) {
87
+ const headers = head ? [...head] : [];
88
+ const body = [];
89
+ const table = {
90
+ head(...columns) {
91
+ headers.length = 0;
92
+ headers.push(...columns);
93
+ return table;
94
+ },
95
+ row(cells) {
96
+ body.push(cells);
97
+ return table;
98
+ },
99
+ rows(list) {
100
+ body.push(...list);
101
+ return table;
102
+ },
103
+ toString() {
104
+ const all = headers.length ? [headers, ...body] : body;
105
+ if (!all.length)
106
+ return "";
107
+ const columns = Math.max(...all.map((r) => r.length));
108
+ const widths = Array.from({ length: columns }, (_, i) => Math.max(...all.map((row) => stripAnsi(row[i] ?? "").length)));
109
+ const line = (cells) => cells
110
+ .map((cell, i) => cell + " ".repeat(Math.max(0, widths[i] - stripAnsi(cell).length)))
111
+ .join(" ")
112
+ .trimEnd();
113
+ const out = [];
114
+ if (headers.length) {
115
+ out.push(line(headers.map((h) => colors("bold", h))));
116
+ out.push(widths.map((w) => "─".repeat(w)).join(" "));
117
+ }
118
+ for (const row of body)
119
+ out.push(line(row));
120
+ return out.join("\n");
121
+ },
122
+ render() {
123
+ const text = table.toString();
124
+ if (text)
125
+ write(text);
126
+ },
127
+ };
128
+ return table;
129
+ },
130
+ sticker(lines, title) {
131
+ const content = title ? [colors("bold", title), "", ...lines] : [...lines];
132
+ const width = Math.max(...content.map((l) => stripAnsi(l).length));
133
+ write(`┌─${"─".repeat(width)}─┐`);
134
+ for (const line of content) {
135
+ const pad = " ".repeat(width - stripAnsi(line).length);
136
+ write(`│ ${line}${pad} │`);
137
+ }
138
+ write(`└─${"─".repeat(width)}─┘`);
139
+ },
140
+ instructions(lines, title) {
141
+ if (title)
142
+ write(colors("bold", title));
143
+ lines.forEach((line, i) => write(` ${colors("gray", `${i + 1}.`)} ${line}`));
144
+ },
145
+ tasks() {
146
+ const queue = [];
147
+ const runner = {
148
+ add(title, run) {
149
+ queue.push({ title, run });
150
+ return runner;
151
+ },
152
+ async run() {
153
+ let ok = true;
154
+ for (const { title, run } of queue) {
155
+ let note = "";
156
+ const handle = {
157
+ update: (message) => {
158
+ note = message;
159
+ },
160
+ };
161
+ const started = Date.now();
162
+ try {
163
+ const result = await run(handle);
164
+ const detail = result || note;
165
+ const ms = Date.now() - started;
166
+ ui.write(`${colors("green", SYMBOLS.success)} ${title}${detail ? ` ${colors("gray", `— ${detail}`)}` : ""} ${colors("gray", `(${ms}ms)`)}`);
167
+ }
168
+ catch (error) {
169
+ ok = false;
170
+ // Stop at the first failure: the tasks after it almost certainly
171
+ // depend on it, and a cascade of red tells you nothing new.
172
+ ui.error(`${title} — ${error instanceof Error ? error.message : String(error)}`);
173
+ break;
174
+ }
175
+ }
176
+ return ok;
177
+ },
178
+ };
179
+ return runner;
180
+ },
181
+ clear() {
182
+ logs.length = 0;
183
+ errors.length = 0;
184
+ },
185
+ };
186
+ return ui;
187
+ }
@@ -0,0 +1,188 @@
1
+ /**
2
+ * The console — a real command system, not a wrapper round `process.argv`.
3
+ *
4
+ * export const greet = defineCommand({
5
+ * name: "greet",
6
+ * description: "Greet someone",
7
+ * args: { name: arg.string({ description: "who to greet" }) },
8
+ * flags: { loud: flag.boolean({ alias: "l", description: "SHOUT IT" }) },
9
+ *
10
+ * async run({ args, flags, ui }) {
11
+ * const message = `Hello, ${args.name}!`;
12
+ * ui.success(flags.loud ? message.toUpperCase() : message);
13
+ * },
14
+ * });
15
+ *
16
+ * `args.name` is a `string` and `flags.loud` is a `boolean` — **inferred from the
17
+ * spec**, not cast. Declare an arg optional and its type becomes `string |
18
+ * undefined`; give it a default and it's a `string` again. The types can't drift
19
+ * from the parsing, because the parsing is generated from them.
20
+ *
21
+ * A command gets a `ui` (colors, tables, tasks, spinners) and a `prompt` (ask,
22
+ * confirm, choice…), both of which switch to a captured, colorless "raw" mode
23
+ * under test, so you can assert on what a command printed and script its answers.
24
+ */
25
+ import type { Ui } from "./console-ui.js";
26
+ import type { Prompt } from "./console-prompt.js";
27
+ export type ArgType = "string" | "number" | "spread";
28
+ export type FlagType = "string" | "number" | "boolean" | "array";
29
+ export interface ArgSpec<T = unknown> {
30
+ readonly kind: "arg";
31
+ readonly type: ArgType;
32
+ readonly description?: string;
33
+ readonly required: boolean;
34
+ readonly default?: T;
35
+ readonly parse?: (raw: string) => T;
36
+ /** @internal — carries the value type. */
37
+ readonly __value?: T;
38
+ }
39
+ export interface FlagSpec<T = unknown> {
40
+ readonly kind: "flag";
41
+ readonly type: FlagType;
42
+ readonly description?: string;
43
+ readonly required: boolean;
44
+ readonly default?: T;
45
+ /** A single-character shorthand: `-f`. */
46
+ readonly alias?: string;
47
+ readonly parse?: (raw: string) => T;
48
+ /** @internal — carries the value type. */
49
+ readonly __value?: T;
50
+ }
51
+ interface BaseOptions {
52
+ description?: string;
53
+ }
54
+ interface ArgOptions<T> extends BaseOptions {
55
+ /** Args are required by default. */
56
+ required?: boolean;
57
+ default?: T;
58
+ parse?: (raw: string) => T;
59
+ }
60
+ interface FlagOptions<T> extends BaseOptions {
61
+ /** Flags are optional by default. */
62
+ required?: boolean;
63
+ default?: T;
64
+ alias?: string;
65
+ parse?: (raw: string) => T;
66
+ }
67
+ /**
68
+ * Whether a spec's value can be absent. Required, or defaulted, means present —
69
+ * which is exactly what makes `args.name` a `string` rather than a
70
+ * `string | undefined` you have to keep checking.
71
+ */
72
+ type Present<O, Fallback extends boolean> = O extends {
73
+ required: true;
74
+ } ? true : O extends {
75
+ default: unknown;
76
+ } ? true : O extends {
77
+ required: false;
78
+ } ? false : Fallback;
79
+ type ArgValue<O, T> = Present<O, true> extends true ? T : T | undefined;
80
+ type FlagValue<O, T> = Present<O, false> extends true ? T : T | undefined;
81
+ /** Positional arguments: `keel greet <name>`. */
82
+ export declare const arg: {
83
+ string<const O extends ArgOptions<string> = Record<never, never>>(options?: O): ArgSpec<ArgValue<O, string>>;
84
+ number<const O extends ArgOptions<number> = Record<never, never>>(options?: O): ArgSpec<ArgValue<O, number>>;
85
+ /** Swallows every remaining value. Must be the last argument. */
86
+ spread<const O extends ArgOptions<string[]> = Record<never, never>>(options?: O): ArgSpec<ArgValue<O, string[]>>;
87
+ };
88
+ /** Named options: `--force`, `-f`, `--name=Ada`. */
89
+ export declare const flag: {
90
+ /** `--force` / `-f`, and `--no-force`. Defaults to `false`, so it's never undefined. */
91
+ boolean<const O extends FlagOptions<boolean> = Record<never, never>>(options?: O): FlagSpec<boolean>;
92
+ string<const O extends FlagOptions<string> = Record<never, never>>(options?: O): FlagSpec<FlagValue<O, string>>;
93
+ number<const O extends FlagOptions<number> = Record<never, never>>(options?: O): FlagSpec<FlagValue<O, number>>;
94
+ /** Repeatable: `--tag a --tag b` gives `["a", "b"]`. Defaults to `[]`. */
95
+ array<const O extends FlagOptions<string[]> = Record<never, never>>(options?: O): FlagSpec<string[]>;
96
+ };
97
+ export type ArgsSpec = Record<string, ArgSpec<unknown>>;
98
+ export type FlagsSpec = Record<string, FlagSpec<unknown>>;
99
+ /** The values a spec produces — this is where `args.name: string` comes from. */
100
+ export type Values<S extends Record<string, {
101
+ __value?: unknown;
102
+ }>> = {
103
+ [K in keyof S]: S[K] extends {
104
+ __value?: infer V;
105
+ } ? V : never;
106
+ };
107
+ /** What a command's `run` receives. */
108
+ export interface CommandContext<A extends ArgsSpec, F extends FlagsSpec> {
109
+ args: Values<A>;
110
+ flags: Values<F>;
111
+ /** Everything after `--`, plus any unrecognized flags. */
112
+ rest: string[];
113
+ ui: Ui;
114
+ prompt: Prompt;
115
+ /** The kernel running this command — for `keel help`, or calling a sibling. */
116
+ kernel: ConsoleKernel;
117
+ }
118
+ export interface CommandDefinition<A extends ArgsSpec = ArgsSpec, F extends FlagsSpec = FlagsSpec> {
119
+ /** What the user types. `:` namespaces it — `make:controller`. */
120
+ name: string;
121
+ description?: string;
122
+ /** Extra lines shown under `keel help <name>`. */
123
+ help?: string[];
124
+ /** Other names this command answers to. */
125
+ aliases?: string[];
126
+ args?: A;
127
+ flags?: F;
128
+ /** Don't fail on flags you didn't declare — they land in `rest`. */
129
+ allowUnknownFlags?: boolean;
130
+ /** Return a number to set the exit code. Throwing sets it to 1. */
131
+ run(context: CommandContext<A, F>): void | number | Promise<void | number>;
132
+ }
133
+ /** Any command, whatever its arg/flag types — what the kernel stores. */
134
+ export type AnyCommand = CommandDefinition<ArgsSpec, FlagsSpec>;
135
+ /**
136
+ * Define a command. The `args` and `flags` you declare become the types of
137
+ * `args` and `flags` inside `run` — the whole point of the exercise.
138
+ */
139
+ export declare function defineCommand<A extends ArgsSpec = Record<never, never>, F extends FlagsSpec = Record<never, never>>(definition: CommandDefinition<A, F>): CommandDefinition<A, F>;
140
+ /** Thrown when the argv doesn't fit the command's spec. */
141
+ export declare class ConsoleError extends Error {
142
+ constructor(message: string);
143
+ }
144
+ export interface Parsed {
145
+ args: Record<string, unknown>;
146
+ flags: Record<string, unknown>;
147
+ rest: string[];
148
+ }
149
+ /**
150
+ * Turn argv into a command's args and flags.
151
+ *
152
+ * Handles `--flag value`, `--flag=value`, `--no-flag`, `-f value`, bundled short
153
+ * flags (`-abc`), repeatable array flags, a `--` terminator, and a trailing
154
+ * spread argument.
155
+ */
156
+ export declare function parseArgv(argv: string[], definition: AnyCommand): Parsed;
157
+ export interface ConsoleKernelOptions {
158
+ /** The binary's name, shown in help. Default: `"keel"`. */
159
+ binary?: string;
160
+ ui?: Ui;
161
+ prompt?: Prompt;
162
+ }
163
+ /** Registers commands, parses argv, and runs the right one. */
164
+ export declare class ConsoleKernel {
165
+ private options;
166
+ private commands;
167
+ private aliases;
168
+ constructor(options?: ConsoleKernelOptions);
169
+ get binary(): string;
170
+ /** Register one or more commands. */
171
+ register(...commands: AnyCommand[]): this;
172
+ /** Every registered command, sorted by name. */
173
+ list(): AnyCommand[];
174
+ find(name: string): AnyCommand | undefined;
175
+ private ui;
176
+ private prompt;
177
+ /**
178
+ * Run a command from argv (without the node/script prefix). Returns the exit
179
+ * code: 0 for success, 1 for a failure — never throws, because a console is a
180
+ * bad place to surface a stack trace to a user who mistyped a flag.
181
+ */
182
+ run(argv: string[]): Promise<number>;
183
+ /** The `keel help` screen: every command, grouped by namespace. */
184
+ help(): string;
185
+ /** The help screen for a single command: its usage, args, and flags. */
186
+ commandHelp(command: AnyCommand): string;
187
+ }
188
+ export {};