rivetkit 2.0.2 → 2.0.3

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 (253) hide show
  1. package/dist/schemas/actor-persist/v1.ts +228 -0
  2. package/dist/schemas/client-protocol/v1.ts +429 -0
  3. package/dist/schemas/file-system-driver/v1.ts +102 -0
  4. package/dist/tsup/actor/errors.cjs +69 -0
  5. package/dist/tsup/actor/errors.cjs.map +1 -0
  6. package/dist/tsup/actor/errors.d.cts +143 -0
  7. package/dist/tsup/actor/errors.d.ts +143 -0
  8. package/dist/tsup/actor/errors.js +69 -0
  9. package/dist/tsup/actor/errors.js.map +1 -0
  10. package/dist/tsup/chunk-2CRLFV6Z.cjs +202 -0
  11. package/dist/tsup/chunk-2CRLFV6Z.cjs.map +1 -0
  12. package/dist/tsup/chunk-3H7O2A7I.js +525 -0
  13. package/dist/tsup/chunk-3H7O2A7I.js.map +1 -0
  14. package/dist/tsup/chunk-42I3OZ3Q.js +15 -0
  15. package/dist/tsup/chunk-42I3OZ3Q.js.map +1 -0
  16. package/dist/tsup/chunk-4NSUQZ2H.js +1790 -0
  17. package/dist/tsup/chunk-4NSUQZ2H.js.map +1 -0
  18. package/dist/tsup/chunk-6PDXBYI5.js +132 -0
  19. package/dist/tsup/chunk-6PDXBYI5.js.map +1 -0
  20. package/dist/tsup/chunk-6WKQDDUD.cjs +1790 -0
  21. package/dist/tsup/chunk-6WKQDDUD.cjs.map +1 -0
  22. package/dist/tsup/chunk-CTBOSFUH.cjs +116 -0
  23. package/dist/tsup/chunk-CTBOSFUH.cjs.map +1 -0
  24. package/dist/tsup/chunk-EGVZZFE2.js +2857 -0
  25. package/dist/tsup/chunk-EGVZZFE2.js.map +1 -0
  26. package/dist/tsup/chunk-FCCPJNMA.cjs +132 -0
  27. package/dist/tsup/chunk-FCCPJNMA.cjs.map +1 -0
  28. package/dist/tsup/chunk-FLMTTN27.js +244 -0
  29. package/dist/tsup/chunk-FLMTTN27.js.map +1 -0
  30. package/dist/tsup/chunk-GIR3AFFI.cjs +315 -0
  31. package/dist/tsup/chunk-GIR3AFFI.cjs.map +1 -0
  32. package/dist/tsup/chunk-INGJP237.js +315 -0
  33. package/dist/tsup/chunk-INGJP237.js.map +1 -0
  34. package/dist/tsup/chunk-KJCJLKRM.js +116 -0
  35. package/dist/tsup/chunk-KJCJLKRM.js.map +1 -0
  36. package/dist/tsup/chunk-KUPQZYUQ.cjs +15 -0
  37. package/dist/tsup/chunk-KUPQZYUQ.cjs.map +1 -0
  38. package/dist/tsup/chunk-O2MBYIXO.cjs +2857 -0
  39. package/dist/tsup/chunk-O2MBYIXO.cjs.map +1 -0
  40. package/dist/tsup/chunk-OGAPU3UG.cjs +525 -0
  41. package/dist/tsup/chunk-OGAPU3UG.cjs.map +1 -0
  42. package/dist/tsup/chunk-OV6AYD4S.js +4406 -0
  43. package/dist/tsup/chunk-OV6AYD4S.js.map +1 -0
  44. package/dist/tsup/chunk-PO4VLDWA.js +47 -0
  45. package/dist/tsup/chunk-PO4VLDWA.js.map +1 -0
  46. package/dist/tsup/chunk-R2OPSKIV.cjs +244 -0
  47. package/dist/tsup/chunk-R2OPSKIV.cjs.map +1 -0
  48. package/dist/tsup/chunk-TZJKSBUQ.cjs +47 -0
  49. package/dist/tsup/chunk-TZJKSBUQ.cjs.map +1 -0
  50. package/dist/tsup/chunk-UBUC5C3G.cjs +189 -0
  51. package/dist/tsup/chunk-UBUC5C3G.cjs.map +1 -0
  52. package/dist/tsup/chunk-UIM22YJL.cjs +4406 -0
  53. package/dist/tsup/chunk-UIM22YJL.cjs.map +1 -0
  54. package/dist/tsup/chunk-URVFQMYI.cjs +230 -0
  55. package/dist/tsup/chunk-URVFQMYI.cjs.map +1 -0
  56. package/dist/tsup/chunk-UVUPOS46.js +230 -0
  57. package/dist/tsup/chunk-UVUPOS46.js.map +1 -0
  58. package/dist/tsup/chunk-VRRHBNJC.js +189 -0
  59. package/dist/tsup/chunk-VRRHBNJC.js.map +1 -0
  60. package/dist/tsup/chunk-XFSS33EQ.js +202 -0
  61. package/dist/tsup/chunk-XFSS33EQ.js.map +1 -0
  62. package/dist/tsup/client/mod.cjs +32 -0
  63. package/dist/tsup/client/mod.cjs.map +1 -0
  64. package/dist/tsup/client/mod.d.cts +26 -0
  65. package/dist/tsup/client/mod.d.ts +26 -0
  66. package/dist/tsup/client/mod.js +32 -0
  67. package/dist/tsup/client/mod.js.map +1 -0
  68. package/dist/tsup/common/log.cjs +13 -0
  69. package/dist/tsup/common/log.cjs.map +1 -0
  70. package/dist/tsup/common/log.d.cts +20 -0
  71. package/dist/tsup/common/log.d.ts +20 -0
  72. package/dist/tsup/common/log.js +13 -0
  73. package/dist/tsup/common/log.js.map +1 -0
  74. package/dist/tsup/common/websocket.cjs +10 -0
  75. package/dist/tsup/common/websocket.cjs.map +1 -0
  76. package/dist/tsup/common/websocket.d.cts +3 -0
  77. package/dist/tsup/common/websocket.d.ts +3 -0
  78. package/dist/tsup/common/websocket.js +10 -0
  79. package/dist/tsup/common/websocket.js.map +1 -0
  80. package/dist/tsup/common-CpqORuCq.d.cts +218 -0
  81. package/dist/tsup/common-CpqORuCq.d.ts +218 -0
  82. package/dist/tsup/connection-BR_Ve4ku.d.cts +2117 -0
  83. package/dist/tsup/connection-BwUMoe6n.d.ts +2117 -0
  84. package/dist/tsup/driver-helpers/mod.cjs +33 -0
  85. package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
  86. package/dist/tsup/driver-helpers/mod.d.cts +18 -0
  87. package/dist/tsup/driver-helpers/mod.d.ts +18 -0
  88. package/dist/tsup/driver-helpers/mod.js +33 -0
  89. package/dist/tsup/driver-helpers/mod.js.map +1 -0
  90. package/dist/tsup/driver-test-suite/mod.cjs +4619 -0
  91. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
  92. package/dist/tsup/driver-test-suite/mod.d.cts +57 -0
  93. package/dist/tsup/driver-test-suite/mod.d.ts +57 -0
  94. package/dist/tsup/driver-test-suite/mod.js +4619 -0
  95. package/dist/tsup/driver-test-suite/mod.js.map +1 -0
  96. package/dist/tsup/inspector/mod.cjs +53 -0
  97. package/dist/tsup/inspector/mod.cjs.map +1 -0
  98. package/dist/tsup/inspector/mod.d.cts +408 -0
  99. package/dist/tsup/inspector/mod.d.ts +408 -0
  100. package/dist/tsup/inspector/mod.js +53 -0
  101. package/dist/tsup/inspector/mod.js.map +1 -0
  102. package/dist/tsup/mod.cjs +73 -0
  103. package/dist/tsup/mod.cjs.map +1 -0
  104. package/dist/tsup/mod.d.cts +100 -0
  105. package/dist/tsup/mod.d.ts +100 -0
  106. package/dist/tsup/mod.js +73 -0
  107. package/dist/tsup/mod.js.map +1 -0
  108. package/dist/tsup/router-endpoints-AYkXG8Tl.d.cts +66 -0
  109. package/dist/tsup/router-endpoints-DAbqVFx2.d.ts +66 -0
  110. package/dist/tsup/test/mod.cjs +21 -0
  111. package/dist/tsup/test/mod.cjs.map +1 -0
  112. package/dist/tsup/test/mod.d.cts +27 -0
  113. package/dist/tsup/test/mod.d.ts +27 -0
  114. package/dist/tsup/test/mod.js +21 -0
  115. package/dist/tsup/test/mod.js.map +1 -0
  116. package/dist/tsup/utils-CT0cv4jd.d.cts +17 -0
  117. package/dist/tsup/utils-CT0cv4jd.d.ts +17 -0
  118. package/dist/tsup/utils.cjs +26 -0
  119. package/dist/tsup/utils.cjs.map +1 -0
  120. package/dist/tsup/utils.d.cts +36 -0
  121. package/dist/tsup/utils.d.ts +36 -0
  122. package/dist/tsup/utils.js +26 -0
  123. package/dist/tsup/utils.js.map +1 -0
  124. package/package.json +208 -5
  125. package/src/actor/action.ts +182 -0
  126. package/src/actor/config.ts +765 -0
  127. package/src/actor/connection.ts +260 -0
  128. package/src/actor/context.ts +171 -0
  129. package/src/actor/database.ts +23 -0
  130. package/src/actor/definition.ts +86 -0
  131. package/src/actor/driver.ts +84 -0
  132. package/src/actor/errors.ts +360 -0
  133. package/src/actor/generic-conn-driver.ts +234 -0
  134. package/src/actor/instance.ts +1800 -0
  135. package/src/actor/log.ts +15 -0
  136. package/src/actor/mod.ts +113 -0
  137. package/src/actor/persisted.ts +42 -0
  138. package/src/actor/protocol/old.ts +281 -0
  139. package/src/actor/protocol/serde.ts +131 -0
  140. package/src/actor/router-endpoints.ts +685 -0
  141. package/src/actor/router.ts +263 -0
  142. package/src/actor/schedule.ts +17 -0
  143. package/src/actor/unstable-react.ts +110 -0
  144. package/src/actor/utils.ts +98 -0
  145. package/src/client/actor-common.ts +30 -0
  146. package/src/client/actor-conn.ts +804 -0
  147. package/src/client/actor-handle.ts +208 -0
  148. package/src/client/client.ts +623 -0
  149. package/src/client/errors.ts +41 -0
  150. package/src/client/http-client-driver.ts +326 -0
  151. package/src/client/log.ts +7 -0
  152. package/src/client/mod.ts +56 -0
  153. package/src/client/raw-utils.ts +92 -0
  154. package/src/client/test.ts +44 -0
  155. package/src/client/utils.ts +150 -0
  156. package/src/common/eventsource-interface.ts +47 -0
  157. package/src/common/eventsource.ts +80 -0
  158. package/src/common/fake-event-source.ts +266 -0
  159. package/src/common/inline-websocket-adapter2.ts +445 -0
  160. package/src/common/log-levels.ts +27 -0
  161. package/src/common/log.ts +139 -0
  162. package/src/common/logfmt.ts +228 -0
  163. package/src/common/network.ts +2 -0
  164. package/src/common/router.ts +87 -0
  165. package/src/common/utils.ts +322 -0
  166. package/src/common/versioned-data.ts +95 -0
  167. package/src/common/websocket-interface.ts +49 -0
  168. package/src/common/websocket.ts +43 -0
  169. package/src/driver-helpers/mod.ts +22 -0
  170. package/src/driver-helpers/utils.ts +17 -0
  171. package/src/driver-test-suite/log.ts +7 -0
  172. package/src/driver-test-suite/mod.ts +213 -0
  173. package/src/driver-test-suite/test-inline-client-driver.ts +402 -0
  174. package/src/driver-test-suite/tests/action-features.ts +136 -0
  175. package/src/driver-test-suite/tests/actor-auth.ts +591 -0
  176. package/src/driver-test-suite/tests/actor-conn-state.ts +249 -0
  177. package/src/driver-test-suite/tests/actor-conn.ts +349 -0
  178. package/src/driver-test-suite/tests/actor-driver.ts +25 -0
  179. package/src/driver-test-suite/tests/actor-error-handling.ts +158 -0
  180. package/src/driver-test-suite/tests/actor-handle.ts +259 -0
  181. package/src/driver-test-suite/tests/actor-inline-client.ts +152 -0
  182. package/src/driver-test-suite/tests/actor-inspector.ts +570 -0
  183. package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
  184. package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
  185. package/src/driver-test-suite/tests/actor-schedule.ts +108 -0
  186. package/src/driver-test-suite/tests/actor-sleep.ts +413 -0
  187. package/src/driver-test-suite/tests/actor-state.ts +54 -0
  188. package/src/driver-test-suite/tests/actor-vars.ts +93 -0
  189. package/src/driver-test-suite/tests/manager-driver.ts +365 -0
  190. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +226 -0
  191. package/src/driver-test-suite/tests/raw-http-request-properties.ts +414 -0
  192. package/src/driver-test-suite/tests/raw-http.ts +347 -0
  193. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +392 -0
  194. package/src/driver-test-suite/tests/raw-websocket.ts +484 -0
  195. package/src/driver-test-suite/tests/request-access.ts +244 -0
  196. package/src/driver-test-suite/utils.ts +68 -0
  197. package/src/drivers/default.ts +31 -0
  198. package/src/drivers/engine/actor-driver.ts +360 -0
  199. package/src/drivers/engine/api-endpoints.ts +128 -0
  200. package/src/drivers/engine/api-utils.ts +70 -0
  201. package/src/drivers/engine/config.ts +39 -0
  202. package/src/drivers/engine/keys.test.ts +266 -0
  203. package/src/drivers/engine/keys.ts +89 -0
  204. package/src/drivers/engine/kv.ts +3 -0
  205. package/src/drivers/engine/log.ts +7 -0
  206. package/src/drivers/engine/manager-driver.ts +391 -0
  207. package/src/drivers/engine/mod.ts +36 -0
  208. package/src/drivers/engine/ws-proxy.ts +170 -0
  209. package/src/drivers/file-system/actor.ts +91 -0
  210. package/src/drivers/file-system/global-state.ts +673 -0
  211. package/src/drivers/file-system/log.ts +7 -0
  212. package/src/drivers/file-system/manager.ts +306 -0
  213. package/src/drivers/file-system/mod.ts +48 -0
  214. package/src/drivers/file-system/utils.ts +109 -0
  215. package/src/globals.d.ts +6 -0
  216. package/src/inline-client-driver/log.ts +7 -0
  217. package/src/inline-client-driver/mod.ts +385 -0
  218. package/src/inspector/actor.ts +298 -0
  219. package/src/inspector/config.ts +83 -0
  220. package/src/inspector/log.ts +5 -0
  221. package/src/inspector/manager.ts +86 -0
  222. package/src/inspector/mod.ts +2 -0
  223. package/src/inspector/protocol/actor.ts +10 -0
  224. package/src/inspector/protocol/common.ts +196 -0
  225. package/src/inspector/protocol/manager.ts +10 -0
  226. package/src/inspector/protocol/mod.ts +2 -0
  227. package/src/inspector/utils.ts +76 -0
  228. package/src/manager/auth.ts +121 -0
  229. package/src/manager/driver.ts +80 -0
  230. package/src/manager/hono-websocket-adapter.ts +333 -0
  231. package/src/manager/log.ts +7 -0
  232. package/src/manager/mod.ts +2 -0
  233. package/src/manager/protocol/mod.ts +24 -0
  234. package/src/manager/protocol/query.ts +89 -0
  235. package/src/manager/router.ts +1792 -0
  236. package/src/mod.ts +20 -0
  237. package/src/registry/config.ts +32 -0
  238. package/src/registry/log.ts +7 -0
  239. package/src/registry/mod.ts +124 -0
  240. package/src/registry/run-config.ts +54 -0
  241. package/src/registry/serve.ts +53 -0
  242. package/src/schemas/actor-persist/mod.ts +1 -0
  243. package/src/schemas/actor-persist/versioned.ts +25 -0
  244. package/src/schemas/client-protocol/mod.ts +1 -0
  245. package/src/schemas/client-protocol/versioned.ts +63 -0
  246. package/src/schemas/file-system-driver/mod.ts +1 -0
  247. package/src/schemas/file-system-driver/versioned.ts +28 -0
  248. package/src/serde.ts +84 -0
  249. package/src/test/config.ts +16 -0
  250. package/src/test/log.ts +7 -0
  251. package/src/test/mod.ts +153 -0
  252. package/src/utils.ts +172 -0
  253. package/README.md +0 -13
@@ -0,0 +1,228 @@
1
+ import { type LogLevel, LogLevels } from "./log-levels";
2
+
3
+ export type LogEntry = [string, LogValue];
4
+ export type LogValue = string | number | bigint | boolean | null | undefined;
5
+
6
+ const LOG_LEVEL_COLORS: Record<number, string> = {
7
+ [LogLevels.CRITICAL]: "\x1b[31m", // Red
8
+ [LogLevels.ERROR]: "\x1b[31m", // Red
9
+ [LogLevels.WARN]: "\x1b[33m", // Yellow
10
+ [LogLevels.INFO]: "\x1b[32m", // Green
11
+ [LogLevels.DEBUG]: "\x1b[36m", // Cyan
12
+ [LogLevels.TRACE]: "\x1b[36m", // Cyan
13
+ };
14
+
15
+ const RESET_COLOR = "\x1b[0m";
16
+
17
+ /**
18
+ * Serializes logfmt line using orderer parameters.
19
+ *
20
+ * We use varargs because it's ordered & it has less overhead than an object.
21
+ *
22
+ * ## Styling Methodology
23
+ *
24
+ * The three things you need to know for every log line is the level, the
25
+ * message, and who called it. These properties are highlighted in different colros
26
+ * and sorted in th eorder that you usually read them.
27
+ *
28
+ * Once you've found a log line you care about, then you want to find the
29
+ * property you need to see. The property names are bolded and the default color
30
+ * while the rest of the data is dim. This lets you scan to find the property
31
+ * name quickly then look closer to read the data associated with the
32
+ * property.
33
+ */
34
+ export function stringify(...data: LogEntry[]) {
35
+ let line = "";
36
+
37
+ for (let i = 0; i < data.length; i++) {
38
+ const [key, valueRaw] = data[i];
39
+
40
+ let isNull = false;
41
+ let valueString: string;
42
+ if (valueRaw == null) {
43
+ isNull = true;
44
+ valueString = "";
45
+ } else {
46
+ valueString = valueRaw.toString();
47
+ }
48
+
49
+ // Clip value unless specifically the error message
50
+ if (valueString.length > 512 && key !== "msg" && key !== "error")
51
+ valueString = `${valueString.slice(0, 512)}...`;
52
+
53
+ const needsQuoting =
54
+ valueString.indexOf(" ") > -1 || valueString.indexOf("=") > -1;
55
+ const needsEscaping =
56
+ valueString.indexOf('"') > -1 || valueString.indexOf("\\") > -1;
57
+
58
+ valueString = valueString.replace(/\n/g, "\\n");
59
+ if (needsEscaping) valueString = valueString.replace(/["\\]/g, "\\$&");
60
+ if (needsQuoting || needsEscaping) valueString = `"${valueString}"`;
61
+ if (valueString === "" && !isNull) valueString = '""';
62
+
63
+ if (LOGGER_CONFIG.enableColor) {
64
+ // With color
65
+
66
+ // Special message colors
67
+ let color = "\x1b[2m";
68
+ if (key === "level") {
69
+ const level = LogLevels[valueString as LogLevel];
70
+ const levelColor = LOG_LEVEL_COLORS[level];
71
+ if (levelColor) {
72
+ color = levelColor;
73
+ }
74
+ } else if (key === "msg") {
75
+ color = "\x1b[32m";
76
+ } else if (key === "trace") {
77
+ color = "\x1b[34m";
78
+ }
79
+
80
+ // Format line
81
+ line += `\x1b[0m\x1b[1m${key}\x1b[0m\x1b[2m=\x1b[0m${color}${valueString}${RESET_COLOR}`;
82
+ } else {
83
+ // No color
84
+ line += `${key}=${valueString}`;
85
+ }
86
+
87
+ if (i !== data.length - 1) {
88
+ line += " ";
89
+ }
90
+ }
91
+
92
+ return line;
93
+ }
94
+
95
+ export function formatTimestamp(date: Date): string {
96
+ const year = date.getUTCFullYear();
97
+ const month = String(date.getUTCMonth() + 1).padStart(2, "0");
98
+ const day = String(date.getUTCDate()).padStart(2, "0");
99
+ const hours = String(date.getUTCHours()).padStart(2, "0");
100
+ const minutes = String(date.getUTCMinutes()).padStart(2, "0");
101
+ const seconds = String(date.getUTCSeconds()).padStart(2, "0");
102
+ const milliseconds = String(date.getUTCMilliseconds()).padStart(3, "0");
103
+
104
+ return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}Z`;
105
+ }
106
+
107
+ export function castToLogValue(v: unknown): LogValue {
108
+ if (
109
+ typeof v === "string" ||
110
+ typeof v === "number" ||
111
+ typeof v === "bigint" ||
112
+ typeof v === "boolean" ||
113
+ v === null ||
114
+ v === undefined
115
+ ) {
116
+ return v;
117
+ }
118
+ if (v instanceof Error) {
119
+ //args.push(...errorToLogEntries(k, v));
120
+ return String(v);
121
+ }
122
+ try {
123
+ return JSON.stringify(v);
124
+ } catch {
125
+ return "[cannot stringify]";
126
+ }
127
+ }
128
+
129
+ // MARK: Config
130
+ interface GlobalLoggerConfig {
131
+ enableColor: boolean;
132
+ enableSpreadObject: boolean;
133
+ enableErrorStack: boolean;
134
+ }
135
+
136
+ export const LOGGER_CONFIG: GlobalLoggerConfig = {
137
+ enableColor: false,
138
+ enableSpreadObject: false,
139
+ enableErrorStack: false,
140
+ };
141
+
142
+ // MARK: Utils
143
+ /**
144
+ * Converts an object in to an easier to read KV of entries.
145
+ */
146
+ export function spreadObjectToLogEntries(
147
+ base: string,
148
+ data: unknown,
149
+ ): LogEntry[] {
150
+ if (
151
+ LOGGER_CONFIG.enableSpreadObject &&
152
+ typeof data === "object" &&
153
+ !Array.isArray(data) &&
154
+ data !== null &&
155
+ Object.keys(data).length !== 0 &&
156
+ Object.keys(data).length < 16
157
+ ) {
158
+ const logData: LogEntry[] = [];
159
+ for (const key in data) {
160
+ // logData.push([`${base}.${key}`, JSON.stringify((data as any)[key])]);
161
+
162
+ logData.push(
163
+ ...spreadObjectToLogEntries(
164
+ `${base}.${key}`,
165
+ // biome-ignore lint/suspicious/noExplicitAny: FIXME
166
+ (data as any)[key],
167
+ ),
168
+ );
169
+ }
170
+ return logData;
171
+ }
172
+
173
+ return [[base, JSON.stringify(data)]];
174
+ }
175
+
176
+ export function errorToLogEntries(base: string, error: unknown): LogEntry[] {
177
+ if (error instanceof Error) {
178
+ return [
179
+ //[`${base}.name`, error.name],
180
+ [`${base}.message`, error.message],
181
+ ...(LOGGER_CONFIG.enableErrorStack && error.stack
182
+ ? [[`${base}.stack`, formatStackTrace(error.stack)] as LogEntry]
183
+ : []),
184
+ ...(error.cause ? errorToLogEntries(`${base}.cause`, error.cause) : []),
185
+ ];
186
+ }
187
+ return [[base, `${error}`]];
188
+ }
189
+
190
+ // export function errorToLogEntries(base: string, error: unknown): LogEntry[] {
191
+ // if (error instanceof RuntimeError) {
192
+ // return [
193
+ // [`${base}.code`, error.code],
194
+ // [`${base}.description`, error.errorConfig?.description],
195
+ // [`${base}.module`, error.moduleName],
196
+ // ...(error.trace ? [[`${base}.trace`, stringifyTrace(error.trace)] as LogEntry] : []),
197
+ // ...(LOGGER_CONFIG.enableErrorStack && error.stack
198
+ // ? [[`${base}.stack`, formatStackTrace(error.stack)] as LogEntry]
199
+ // : []),
200
+ // ...(error.meta ? [[`${base}.meta`, JSON.stringify(error.meta)] as LogEntry] : []),
201
+ // ...(error.cause ? errorToLogEntries(`${base}.cause`, error.cause) : []),
202
+ // ];
203
+ // } else if (error instanceof Error) {
204
+ // return [
205
+ // [`${base}.name`, error.name],
206
+ // [`${base}.message`, error.message],
207
+ // ...(LOGGER_CONFIG.enableErrorStack && error.stack
208
+ // ? [[`${base}.stack`, formatStackTrace(error.stack)] as LogEntry]
209
+ // : []),
210
+ // ...(error.cause ? errorToLogEntries(`${base}.cause`, error.cause) : []),
211
+ // ];
212
+ // } else {
213
+ // return [
214
+ // [base, `${error}`],
215
+ // ];
216
+ // }
217
+ // }
218
+
219
+ /**
220
+ * Formats a JS stack trace in to a legible one-liner.
221
+ */
222
+ function formatStackTrace(stackTrace: string): string {
223
+ const regex = /at (.+?)$/gm;
224
+ const matches = [...stackTrace.matchAll(regex)];
225
+ // Reverse array since the stack goes from top level -> bottom level
226
+ matches.reverse();
227
+ return matches.map((match) => match[1].trim()).join(" > ");
228
+ }
@@ -0,0 +1,2 @@
1
+ /** Only enforced client-side in order to prevent building malformed URLs. */
2
+ export const MAX_CONN_PARAMS_SIZE = 4096;
@@ -0,0 +1,87 @@
1
+ import * as cbor from "cbor-x";
2
+ import type { Context as HonoContext, Next } from "hono";
3
+ import type { Encoding } from "@/actor/protocol/serde";
4
+ import {
5
+ getRequestEncoding,
6
+ getRequestExposeInternalError,
7
+ } from "@/actor/router-endpoints";
8
+ import { HttpResponseError } from "@/schemas/client-protocol/mod";
9
+ import { HTTP_RESPONSE_ERROR_VERSIONED } from "@/schemas/client-protocol/versioned";
10
+ import { serializeWithEncoding } from "@/serde";
11
+ import { bufferToArrayBuffer } from "@/utils";
12
+ import { getLogger, type Logger } from "./log";
13
+ import { deconstructError, stringifyError } from "./utils";
14
+
15
+ export function logger() {
16
+ return getLogger("router");
17
+ }
18
+
19
+ export function loggerMiddleware(logger: Logger) {
20
+ return async (c: HonoContext, next: Next) => {
21
+ const method = c.req.method;
22
+ const path = c.req.path;
23
+ const startTime = Date.now();
24
+
25
+ await next();
26
+
27
+ const duration = Date.now() - startTime;
28
+ logger.debug("http request", {
29
+ method,
30
+ path,
31
+ status: c.res.status,
32
+ dt: `${duration}ms`,
33
+ reqSize: c.req.header("content-length"),
34
+ resSize: c.res.headers.get("content-length"),
35
+ userAgent: c.req.header("user-agent"),
36
+ });
37
+ };
38
+ }
39
+
40
+ export function handleRouteNotFound(c: HonoContext) {
41
+ return c.text("Not Found (RivetKit)", 404);
42
+ }
43
+
44
+ export interface HandleRouterErrorOpts {
45
+ enableExposeInternalError?: boolean;
46
+ }
47
+
48
+ export function handleRouteError(
49
+ opts: HandleRouterErrorOpts,
50
+ error: unknown,
51
+ c: HonoContext,
52
+ ) {
53
+ const exposeInternalError =
54
+ opts.enableExposeInternalError && getRequestExposeInternalError(c.req.raw);
55
+
56
+ const { statusCode, code, message, metadata } = deconstructError(
57
+ error,
58
+ logger(),
59
+ {
60
+ method: c.req.method,
61
+ path: c.req.path,
62
+ },
63
+ exposeInternalError,
64
+ );
65
+
66
+ let encoding: Encoding;
67
+ try {
68
+ encoding = getRequestEncoding(c.req);
69
+ } catch (err) {
70
+ logger().debug("failed to extract encoding", {
71
+ error: stringifyError(err),
72
+ });
73
+ encoding = "json";
74
+ }
75
+
76
+ const output = serializeWithEncoding(
77
+ encoding,
78
+ {
79
+ code,
80
+ message,
81
+ metadata: bufferToArrayBuffer(cbor.encode(metadata)),
82
+ },
83
+ HTTP_RESPONSE_ERROR_VERSIONED,
84
+ );
85
+
86
+ return c.body(output, { status: statusCode });
87
+ }
@@ -0,0 +1,322 @@
1
+ import type { Next } from "hono";
2
+ import type { ContentfulStatusCode } from "hono/utils/http-status";
3
+ import * as errors from "@/actor/errors";
4
+ import { getEnvUniversal } from "@/utils";
5
+ import type { Logger } from "./log";
6
+
7
+ export function assertUnreachable(x: never): never {
8
+ throw new Error(`Unreachable case: ${x}`);
9
+ }
10
+
11
+ /**
12
+ * Safely stringifies an object, ensuring that the stringified object is under a certain size.
13
+ * @param obj any object to stringify
14
+ * @param maxSize maximum size of the stringified object in bytes
15
+ * @returns stringified object
16
+ */
17
+ export function safeStringify(obj: unknown, maxSize: number) {
18
+ let size = 0;
19
+
20
+ function replacer(key: string, value: unknown) {
21
+ if (value === null || value === undefined) return value;
22
+ const valueSize =
23
+ typeof value === "string" ? value.length : JSON.stringify(value).length;
24
+ size += key.length + valueSize;
25
+
26
+ if (size > maxSize) {
27
+ throw new Error(`JSON object exceeds size limit of ${maxSize} bytes.`);
28
+ }
29
+
30
+ return value;
31
+ }
32
+
33
+ return JSON.stringify(obj, replacer);
34
+ }
35
+
36
+ // TODO: Instead of doing this, use a temp var for state and attempt to write
37
+ // it. Roll back state if fails to serialize.
38
+
39
+ /**
40
+ * Check if a value is CBOR serializable.
41
+ * Optionally pass an onInvalid callback to receive the path to invalid values.
42
+ *
43
+ * For a complete list of supported CBOR tags, see:
44
+ * https://github.com/kriszyp/cbor-x/blob/cc1cf9df8ba72288c7842af1dd374d73e34cdbc1/README.md#list-of-supported-tags-for-decoding
45
+ */
46
+ export function isCborSerializable(
47
+ value: unknown,
48
+ onInvalid?: (path: string) => void,
49
+ currentPath = "",
50
+ ): boolean {
51
+ // Handle primitive types directly
52
+ if (value === null || value === undefined) {
53
+ return true;
54
+ }
55
+
56
+ if (typeof value === "number") {
57
+ if (!Number.isFinite(value)) {
58
+ onInvalid?.(currentPath);
59
+ return false;
60
+ }
61
+ return true;
62
+ }
63
+
64
+ if (typeof value === "boolean" || typeof value === "string") {
65
+ return true;
66
+ }
67
+
68
+ // Handle BigInt (CBOR tags 2 and 3)
69
+ if (typeof value === "bigint") {
70
+ return true;
71
+ }
72
+
73
+ // Handle Date objects (CBOR tags 0 and 1)
74
+ if (value instanceof Date) {
75
+ return true;
76
+ }
77
+
78
+ // Handle typed arrays (CBOR tags 64-82)
79
+ if (
80
+ value instanceof Uint8Array ||
81
+ value instanceof Uint8ClampedArray ||
82
+ value instanceof Uint16Array ||
83
+ value instanceof Uint32Array ||
84
+ value instanceof BigUint64Array ||
85
+ value instanceof Int8Array ||
86
+ value instanceof Int16Array ||
87
+ value instanceof Int32Array ||
88
+ value instanceof BigInt64Array ||
89
+ value instanceof Float32Array ||
90
+ value instanceof Float64Array
91
+ ) {
92
+ return true;
93
+ }
94
+
95
+ // Handle Map (CBOR tag 259)
96
+ if (value instanceof Map) {
97
+ for (const [key, val] of value.entries()) {
98
+ const keyPath = currentPath
99
+ ? `${currentPath}.key(${String(key)})`
100
+ : `key(${String(key)})`;
101
+ const valPath = currentPath
102
+ ? `${currentPath}.value(${String(key)})`
103
+ : `value(${String(key)})`;
104
+ if (
105
+ !isCborSerializable(key, onInvalid, keyPath) ||
106
+ !isCborSerializable(val, onInvalid, valPath)
107
+ ) {
108
+ return false;
109
+ }
110
+ }
111
+ return true;
112
+ }
113
+
114
+ // Handle Set (CBOR tag 258)
115
+ if (value instanceof Set) {
116
+ let index = 0;
117
+ for (const item of value.values()) {
118
+ const itemPath = currentPath
119
+ ? `${currentPath}.set[${index}]`
120
+ : `set[${index}]`;
121
+ if (!isCborSerializable(item, onInvalid, itemPath)) {
122
+ return false;
123
+ }
124
+ index++;
125
+ }
126
+ return true;
127
+ }
128
+
129
+ // Handle RegExp (CBOR tag 27)
130
+ if (value instanceof RegExp) {
131
+ return true;
132
+ }
133
+
134
+ // Handle Error objects (CBOR tag 27)
135
+ if (value instanceof Error) {
136
+ return true;
137
+ }
138
+
139
+ // Handle arrays
140
+ if (Array.isArray(value)) {
141
+ for (let i = 0; i < value.length; i++) {
142
+ const itemPath = currentPath ? `${currentPath}[${i}]` : `[${i}]`;
143
+ if (!isCborSerializable(value[i], onInvalid, itemPath)) {
144
+ return false;
145
+ }
146
+ }
147
+ return true;
148
+ }
149
+
150
+ // Handle plain objects and records (CBOR tags 105, 51, 57344-57599)
151
+ if (typeof value === "object") {
152
+ // Allow plain objects and objects with prototypes (for records and named objects)
153
+ const proto = Object.getPrototypeOf(value);
154
+ if (proto !== null && proto !== Object.prototype) {
155
+ // Check if it's a known serializable object type
156
+ const protoConstructor = value.constructor;
157
+ if (protoConstructor && typeof protoConstructor.name === "string") {
158
+ // Allow objects with named constructors (records, named objects)
159
+ // This includes user-defined classes and built-in objects
160
+ // that CBOR can serialize with tag 27 or record tags
161
+ }
162
+ }
163
+
164
+ // Check all properties recursively
165
+ for (const key in value) {
166
+ const propPath = currentPath ? `${currentPath}.${key}` : key;
167
+ if (
168
+ !isCborSerializable(
169
+ value[key as keyof typeof value],
170
+ onInvalid,
171
+ propPath,
172
+ )
173
+ ) {
174
+ return false;
175
+ }
176
+ }
177
+ return true;
178
+ }
179
+
180
+ // Not serializable
181
+ onInvalid?.(currentPath);
182
+ return false;
183
+ }
184
+
185
+ export interface DeconstructedError {
186
+ __type: "ActorError";
187
+ statusCode: ContentfulStatusCode;
188
+ public: boolean;
189
+ code: string;
190
+ message: string;
191
+ metadata?: unknown;
192
+ }
193
+
194
+ /** Deconstructs error in to components that are used to build responses. */
195
+ export function deconstructError(
196
+ error: unknown,
197
+ logger: Logger,
198
+ extraLog: Record<string, unknown>,
199
+ exposeInternalError = false,
200
+ ): DeconstructedError {
201
+ // Build response error information. Only return errors if flagged as public in order to prevent leaking internal behavior.
202
+ //
203
+ // We log the error here instead of after generating the code & message because we need to log the original error, not the masked internal error.
204
+ let statusCode: ContentfulStatusCode;
205
+ let public_: boolean;
206
+ let code: string;
207
+ let message: string;
208
+ let metadata: unknown;
209
+ if (errors.ActorError.isActorError(error) && error.public) {
210
+ // Check if error has statusCode (could be ActorError instance or DeconstructedError)
211
+ statusCode = (
212
+ "statusCode" in error && error.statusCode ? error.statusCode : 400
213
+ ) as ContentfulStatusCode;
214
+ public_ = true;
215
+ code = error.code;
216
+ message = getErrorMessage(error);
217
+ metadata = error.metadata;
218
+
219
+ logger.info("public error", {
220
+ code,
221
+ message,
222
+ issues: "https://github.com/rivet-gg/rivetkit/issues",
223
+ support: "https://rivet.gg/discord",
224
+ ...extraLog,
225
+ });
226
+ } else if (exposeInternalError) {
227
+ if (errors.ActorError.isActorError(error)) {
228
+ statusCode = 500;
229
+ public_ = false;
230
+ code = error.code;
231
+ message = getErrorMessage(error);
232
+ metadata = error.metadata;
233
+
234
+ logger.info("internal error", {
235
+ code,
236
+ message,
237
+ issues: "https://github.com/rivet-gg/rivetkit/issues",
238
+ support: "https://rivet.gg/discord",
239
+ ...extraLog,
240
+ });
241
+ } else {
242
+ statusCode = 500;
243
+ public_ = false;
244
+ code = errors.INTERNAL_ERROR_CODE;
245
+ message = getErrorMessage(error);
246
+
247
+ logger.info("internal error", {
248
+ code,
249
+ message,
250
+ issues: "https://github.com/rivet-gg/rivetkit/issues",
251
+ support: "https://rivet.gg/discord",
252
+ ...extraLog,
253
+ });
254
+ }
255
+ } else {
256
+ statusCode = 500;
257
+ public_ = false;
258
+ code = errors.INTERNAL_ERROR_CODE;
259
+ message = errors.INTERNAL_ERROR_DESCRIPTION;
260
+ metadata = {
261
+ //url: `https://hub.rivet.gg/projects/${actorMetadata.project.slug}/environments/${actorMetadata.environment.slug}/actors?actorId=${actorMetadata.actor.id}`,
262
+ } satisfies errors.InternalErrorMetadata;
263
+
264
+ logger.warn("internal error", {
265
+ error: getErrorMessage(error),
266
+ stack: (error as Error)?.stack,
267
+ issues: "https://github.com/rivet-gg/rivetkit/issues",
268
+ support: "https://rivet.gg/discord",
269
+ ...extraLog,
270
+ });
271
+ }
272
+
273
+ return {
274
+ __type: "ActorError",
275
+ statusCode,
276
+ public: public_,
277
+ code,
278
+ message,
279
+ metadata,
280
+ };
281
+ }
282
+
283
+ export function stringifyError(error: unknown): string {
284
+ if (error instanceof Error) {
285
+ if (
286
+ typeof process !== "undefined" &&
287
+ getEnvUniversal("_RIVETKIT_ERROR_STACK") === "1"
288
+ ) {
289
+ return `${error.name}: ${error.message}${error.stack ? `\n${error.stack}` : ""}`;
290
+ } else {
291
+ return `${error.name}: ${error.message}`;
292
+ }
293
+ } else if (typeof error === "string") {
294
+ return error;
295
+ } else if (typeof error === "object" && error !== null) {
296
+ try {
297
+ return `${JSON.stringify(error)}`;
298
+ } catch {
299
+ return "[cannot stringify error]";
300
+ }
301
+ } else {
302
+ return `Unknown error: ${getErrorMessage(error)}`;
303
+ }
304
+ }
305
+
306
+ function getErrorMessage(err: unknown): string {
307
+ if (
308
+ err &&
309
+ typeof err === "object" &&
310
+ "message" in err &&
311
+ typeof err.message === "string"
312
+ ) {
313
+ return err.message;
314
+ } else {
315
+ return String(err);
316
+ }
317
+ }
318
+
319
+ /** Generates a `Next` handler to pass to middleware in order to be able to call arbitrary middleware. */
320
+ export function noopNext(): Next {
321
+ return async () => {};
322
+ }