@shaferllc/keel 0.68.0 → 0.77.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 (143) hide show
  1. package/AGENTS.md +2 -0
  2. package/README.md +15 -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 +93 -0
  13. package/dist/api/resource.js +185 -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/index.d.ts +28 -0
  18. package/dist/core/cli/index.js +427 -0
  19. package/dist/core/cli/stubs.d.ts +14 -0
  20. package/dist/core/cli/stubs.js +105 -0
  21. package/dist/core/console-prompt.d.ts +79 -0
  22. package/dist/core/console-prompt.js +239 -0
  23. package/dist/core/console-ui.d.ts +96 -0
  24. package/dist/core/console-ui.js +187 -0
  25. package/dist/core/console.d.ts +188 -0
  26. package/dist/core/console.js +395 -0
  27. package/dist/core/database.d.ts +70 -1
  28. package/dist/core/database.js +174 -15
  29. package/dist/core/env.d.ts +96 -0
  30. package/dist/core/env.js +140 -0
  31. package/dist/core/health.d.ts +2 -2
  32. package/dist/core/health.js +2 -2
  33. package/dist/core/http/kernel.d.ts +2 -0
  34. package/dist/core/http/kernel.js +48 -0
  35. package/dist/core/http/router.d.ts +5 -5
  36. package/dist/core/http/router.js +5 -5
  37. package/dist/core/i18n.d.ts +162 -0
  38. package/dist/core/i18n.js +472 -0
  39. package/dist/core/index.d.ts +25 -4
  40. package/dist/core/index.js +13 -3
  41. package/dist/core/instrumentation.d.ts +113 -0
  42. package/dist/core/instrumentation.js +52 -0
  43. package/dist/core/logger.d.ts +7 -0
  44. package/dist/core/logger.js +28 -1
  45. package/dist/core/notification.js +10 -1
  46. package/dist/core/package.d.ts +117 -0
  47. package/dist/core/package.js +169 -0
  48. package/dist/core/pages.d.ts +108 -0
  49. package/dist/core/pages.js +199 -0
  50. package/dist/core/queue.js +26 -5
  51. package/dist/core/repl.d.ts +33 -0
  52. package/dist/core/repl.js +88 -0
  53. package/dist/core/scheduler.js +6 -0
  54. package/dist/core/social.d.ts +4 -4
  55. package/dist/core/social.js +4 -4
  56. package/dist/core/storage.js +15 -3
  57. package/dist/core/telemetry.d.ts +208 -0
  58. package/dist/core/telemetry.js +383 -0
  59. package/dist/core/template.d.ts +2 -3
  60. package/dist/core/template.js +2 -3
  61. package/dist/core/testing.d.ts +171 -1
  62. package/dist/core/testing.js +505 -2
  63. package/dist/db/d1.js +13 -0
  64. package/dist/db/pg.d.ts +13 -0
  65. package/dist/db/pg.js +46 -4
  66. package/dist/openapi/config.d.ts +28 -0
  67. package/dist/openapi/config.js +25 -0
  68. package/dist/openapi/doc.d.ts +40 -0
  69. package/dist/openapi/doc.js +20 -0
  70. package/dist/openapi/export.d.ts +8 -0
  71. package/dist/openapi/export.js +19 -0
  72. package/dist/openapi/gate.d.ts +15 -0
  73. package/dist/openapi/gate.js +27 -0
  74. package/dist/openapi/index.d.ts +19 -0
  75. package/dist/openapi/index.js +15 -0
  76. package/dist/openapi/openapi.config.stub +29 -0
  77. package/dist/openapi/provider.d.ts +18 -0
  78. package/dist/openapi/provider.js +35 -0
  79. package/dist/openapi/routes.d.ts +9 -0
  80. package/dist/openapi/routes.js +23 -0
  81. package/dist/openapi/spec.d.ts +23 -0
  82. package/dist/openapi/spec.js +132 -0
  83. package/dist/openapi/ui.d.ts +8 -0
  84. package/dist/openapi/ui.js +31 -0
  85. package/dist/openapi/zod.d.ts +12 -0
  86. package/dist/openapi/zod.js +46 -0
  87. package/dist/watch/config.d.ts +33 -0
  88. package/dist/watch/config.js +38 -0
  89. package/dist/watch/entry.d.ts +53 -0
  90. package/dist/watch/entry.js +105 -0
  91. package/dist/watch/gate.d.ts +20 -0
  92. package/dist/watch/gate.js +32 -0
  93. package/dist/watch/index.d.ts +21 -0
  94. package/dist/watch/index.js +17 -0
  95. package/dist/watch/migration.d.ts +7 -0
  96. package/dist/watch/migration.js +20 -0
  97. package/dist/watch/provider.d.ts +22 -0
  98. package/dist/watch/provider.js +58 -0
  99. package/dist/watch/prune.d.ts +11 -0
  100. package/dist/watch/prune.js +22 -0
  101. package/dist/watch/recorder.d.ts +24 -0
  102. package/dist/watch/recorder.js +39 -0
  103. package/dist/watch/routes.d.ts +13 -0
  104. package/dist/watch/routes.js +55 -0
  105. package/dist/watch/store.d.ts +54 -0
  106. package/dist/watch/store.js +158 -0
  107. package/dist/watch/ui/dist/watch.css +1 -0
  108. package/dist/watch/ui/dist/watch.js +555 -0
  109. package/dist/watch/ui-shell.d.ts +12 -0
  110. package/dist/watch/ui-shell.js +24 -0
  111. package/dist/watch/watch.config.stub +47 -0
  112. package/dist/watch/watchers.d.ts +12 -0
  113. package/dist/watch/watchers.js +156 -0
  114. package/docs/ai-manifest.json +737 -3
  115. package/docs/api-resources.md +119 -0
  116. package/docs/configuration.md +74 -0
  117. package/docs/console.md +217 -13
  118. package/docs/database.md +101 -0
  119. package/docs/examples/api-resources.ts +86 -0
  120. package/docs/examples/configuration.ts +40 -0
  121. package/docs/examples/console.ts +134 -0
  122. package/docs/examples/database.ts +90 -0
  123. package/docs/examples/i18n.ts +117 -0
  124. package/docs/examples/logger.ts +74 -0
  125. package/docs/examples/mail.ts +103 -0
  126. package/docs/examples/pages.ts +82 -0
  127. package/docs/examples/telemetry.ts +127 -0
  128. package/docs/examples/testing.ts +150 -0
  129. package/docs/health.md +4 -4
  130. package/docs/i18n.md +302 -0
  131. package/docs/logger.md +156 -10
  132. package/docs/mail.md +73 -0
  133. package/docs/openapi.md +111 -0
  134. package/docs/packages.md +118 -0
  135. package/docs/pages.md +217 -0
  136. package/docs/storage.md +5 -3
  137. package/docs/telemetry.md +263 -0
  138. package/docs/templates.md +3 -4
  139. package/docs/testing.md +252 -0
  140. package/docs/watch.md +118 -0
  141. package/llms-full.txt +2389 -241
  142. package/llms.txt +13 -1
  143. package/package.json +32 -6
@@ -0,0 +1,156 @@
1
+ /**
2
+ * The watchers. Each subscribes to one instrumentation seam and turns it into a
3
+ * recorded entry — the whole reason the framework emits those events. None of
4
+ * them patch anything: they're just listeners, so installing Watch changes no
5
+ * behaviour, only observation.
6
+ *
7
+ * `installWatchers` wires up every enabled watcher and hands back a single
8
+ * teardown function (used on shutdown and in tests).
9
+ */
10
+ import { listen, events } from "../core/helpers.js";
11
+ import { tapLogs } from "../core/logger.js";
12
+ import { familyHash, redactHeaders, sqlShape } from "./entry.js";
13
+ /** Events the Event watcher ignores — the instrumentation stream and things with
14
+ * their own dedicated watcher, so they aren't recorded twice. */
15
+ const OWN_EVENTS = new Set([
16
+ "db.query",
17
+ "request.handled",
18
+ "exception",
19
+ "job.processing",
20
+ "job.processed",
21
+ "job.failed",
22
+ "cache.hit",
23
+ "cache.miss",
24
+ "notification.sent",
25
+ "schedule.task.run",
26
+ "mail.sending",
27
+ "mail.sent",
28
+ "mail.queued",
29
+ ]);
30
+ export function installWatchers(recorder, config) {
31
+ const off = [];
32
+ const dash = "/" + config.path.replace(/^\/|\/$/g, "");
33
+ const ignorePath = (path) => path === dash ||
34
+ path.startsWith(`${dash}/`) ||
35
+ config.ignorePaths.some((p) => path.startsWith(p));
36
+ /* ------------------------------- requests ------------------------------- */
37
+ if (recorder.enabledFor("request")) {
38
+ off.push(listen("request.handled", (e) => {
39
+ if (ignorePath(e.path))
40
+ return;
41
+ recorder.record("request", {
42
+ method: e.method,
43
+ path: e.path,
44
+ status: e.status,
45
+ durationMs: e.durationMs,
46
+ headers: redactHeaders(e.headers),
47
+ ...(e.ip ? { ip: e.ip } : {}),
48
+ }, [
49
+ `status:${e.status}`,
50
+ `method:${e.method}`,
51
+ e.status >= 500 ? "failed" : e.status >= 400 ? "client-error" : "ok",
52
+ ], { batchId: e.id, familyHash: familyHash(`${e.method} ${e.path}`) });
53
+ }));
54
+ }
55
+ /* -------------------------------- queries ------------------------------- */
56
+ if (recorder.enabledFor("query")) {
57
+ off.push(listen("db.query", (e) => {
58
+ // Never record the store's own reads/writes — that would be a loop.
59
+ if (e.sql.includes(config.table))
60
+ return;
61
+ const slow = e.durationMs >= config.slowQueryMs;
62
+ recorder.record("query", {
63
+ sql: e.sql,
64
+ bindings: e.bindings,
65
+ durationMs: e.durationMs,
66
+ connection: e.connection,
67
+ kind: e.kind,
68
+ }, [`connection:${e.connection}`, e.kind, ...(slow ? ["slow"] : [])], {
69
+ ...(e.requestId ? { batchId: e.requestId } : {}),
70
+ familyHash: familyHash(sqlShape(e.sql)),
71
+ });
72
+ }));
73
+ }
74
+ /* ------------------------------ exceptions ------------------------------ */
75
+ if (recorder.enabledFor("exception")) {
76
+ off.push(listen("exception", (e) => {
77
+ const err = e.error;
78
+ const cls = err instanceof Error ? err.name : "Error";
79
+ const message = err instanceof Error ? err.message : String(err);
80
+ recorder.record("exception", {
81
+ class: cls,
82
+ message,
83
+ status: e.status,
84
+ ...(e.method ? { method: e.method } : {}),
85
+ ...(e.path ? { path: e.path } : {}),
86
+ stack: err instanceof Error ? (err.stack ?? "").split("\n").map((l) => l.trim()) : [],
87
+ }, [`status:${e.status}`, cls], {
88
+ ...(e.requestId ? { batchId: e.requestId } : {}),
89
+ familyHash: familyHash(`${cls}:${message}`),
90
+ });
91
+ }));
92
+ }
93
+ /* --------------------------------- logs --------------------------------- */
94
+ if (recorder.enabledFor("log")) {
95
+ off.push(tapLogs((record) => {
96
+ recorder.record("log", { level: record.level, message: record.msg, time: record.time, context: record.fields }, [`level:${record.level}`]);
97
+ }));
98
+ }
99
+ /* --------------------------------- mail --------------------------------- */
100
+ if (recorder.enabledFor("mail")) {
101
+ off.push(listen("mail.sent", (msg) => {
102
+ const m = msg ?? {};
103
+ recorder.record("mail", {
104
+ to: m.to,
105
+ from: m.from,
106
+ ...(m.cc ? { cc: m.cc } : {}),
107
+ ...(m.bcc ? { bcc: m.bcc } : {}),
108
+ subject: m.subject,
109
+ ...(typeof m.text === "string" ? { text: m.text } : {}),
110
+ ...(typeof m.html === "string" ? { html: m.html } : {}),
111
+ }, ["mail:sent"]);
112
+ }));
113
+ }
114
+ /* --------------------------------- jobs --------------------------------- */
115
+ if (recorder.enabledFor("job")) {
116
+ off.push(listen("job.processed", (e) => {
117
+ recorder.record("job", { job: e.job, status: "processed", ...(e.durationMs != null ? { durationMs: e.durationMs } : {}) }, ["job:processed", e.job], e.requestId ? { batchId: e.requestId } : {});
118
+ }));
119
+ off.push(listen("job.failed", (e) => {
120
+ recorder.record("job", { job: e.job, status: "failed", error: e.error }, ["job:failed", e.job], e.requestId ? { batchId: e.requestId } : {});
121
+ }));
122
+ }
123
+ /* ----------------------------- notifications ---------------------------- */
124
+ if (recorder.enabledFor("notification")) {
125
+ off.push(listen("notification.sent", (e) => {
126
+ recorder.record("notification", { notification: e.notification, channels: e.channels, notifiable: e.notifiable }, ["notification:sent", ...e.channels.map((c) => `channel:${c}`)], e.requestId ? { batchId: e.requestId } : {});
127
+ }));
128
+ }
129
+ /* -------------------------------- cache --------------------------------- */
130
+ if (recorder.enabledFor("cache")) {
131
+ const cacheEntry = (hit) => (e) => recorder.record("cache", { key: e.key, hit, store: e.store }, [hit ? "cache:hit" : "cache:miss"], e.requestId ? { batchId: e.requestId } : {});
132
+ off.push(listen("cache.hit", cacheEntry(true)));
133
+ off.push(listen("cache.miss", cacheEntry(false)));
134
+ }
135
+ /* -------------------------------- events -------------------------------- */
136
+ if (recorder.enabledFor("event")) {
137
+ off.push(events().onAny((name, payload) => {
138
+ if (OWN_EVENTS.has(name))
139
+ return;
140
+ recorder.record("event", { name, payload }, [`event:${name}`]);
141
+ }));
142
+ }
143
+ /* ------------------------------- schedule ------------------------------- */
144
+ if (recorder.enabledFor("schedule")) {
145
+ off.push(listen("schedule.task.run", (e) => {
146
+ recorder.record("schedule", { task: e.task, durationMs: e.durationMs }, [
147
+ "schedule:run",
148
+ e.task,
149
+ ]);
150
+ }));
151
+ }
152
+ return () => {
153
+ for (const unsub of off)
154
+ unsub();
155
+ };
156
+ }