@mistriwork/engine 0.0.0-stage → 1.0.0-rc.10

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 (546) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +17 -2
  3. package/dist/adapters/adapter.d.ts +693 -0
  4. package/dist/adapters/adapter.js +444 -0
  5. package/dist/adapters/cache/cacheStore.d.ts +75 -0
  6. package/dist/adapters/cache/cacheStore.js +160 -0
  7. package/dist/adapters/cache/resp.d.ts +52 -0
  8. package/dist/adapters/cache/resp.js +237 -0
  9. package/dist/adapters/commands/canonicalJson.d.ts +19 -0
  10. package/dist/adapters/commands/canonicalJson.js +154 -0
  11. package/dist/adapters/connect.d.ts +29 -0
  12. package/dist/adapters/connect.js +40 -0
  13. package/dist/adapters/connectionBudget.d.ts +101 -0
  14. package/dist/adapters/connectionBudget.js +128 -0
  15. package/dist/adapters/dbLatency.d.ts +35 -0
  16. package/dist/adapters/dbLatency.js +79 -0
  17. package/dist/adapters/epochCache.d.ts +50 -0
  18. package/dist/adapters/epochCache.js +85 -0
  19. package/dist/adapters/http/egress.d.ts +48 -0
  20. package/dist/adapters/http/egress.js +175 -0
  21. package/dist/adapters/http/httpAdapter.d.ts +71 -0
  22. package/dist/adapters/http/httpAdapter.js +512 -0
  23. package/dist/adapters/http/httpDescription.d.ts +32 -0
  24. package/dist/adapters/http/httpDescription.js +246 -0
  25. package/dist/adapters/http/openapi.d.ts +98 -0
  26. package/dist/adapters/http/openapi.js +487 -0
  27. package/dist/adapters/layoutRefusal.d.ts +24 -0
  28. package/dist/adapters/layoutRefusal.js +35 -0
  29. package/dist/adapters/net/networkPolicy.d.ts +44 -0
  30. package/dist/adapters/net/networkPolicy.js +123 -0
  31. package/dist/adapters/net/untrustedDatabase.d.ts +18 -0
  32. package/dist/adapters/net/untrustedDatabase.js +120 -0
  33. package/dist/adapters/poolAdmission.d.ts +43 -0
  34. package/dist/adapters/poolAdmission.js +184 -0
  35. package/dist/adapters/poolMetrics.d.ts +121 -0
  36. package/dist/adapters/poolMetrics.js +185 -0
  37. package/dist/adapters/postgres.d.ts +436 -0
  38. package/dist/adapters/postgres.js +1890 -0
  39. package/dist/adapters/postgresCatalog.d.ts +96 -0
  40. package/dist/adapters/postgresCatalog.js +387 -0
  41. package/dist/adapters/postgresCatalogDigest.d.ts +30 -0
  42. package/dist/adapters/postgresCatalogDigest.js +87 -0
  43. package/dist/adapters/postgresCatalogRows.d.ts +62 -0
  44. package/dist/adapters/postgresCatalogRows.js +37 -0
  45. package/dist/adapters/postgresDates.d.ts +1 -0
  46. package/dist/adapters/postgresDates.js +39 -0
  47. package/dist/adapters/postgresMaintenance.d.ts +33 -0
  48. package/dist/adapters/postgresMaintenance.js +179 -0
  49. package/dist/adapters/postgresPool.d.ts +255 -0
  50. package/dist/adapters/postgresPool.js +838 -0
  51. package/dist/adapters/postgresPooler.d.ts +28 -0
  52. package/dist/adapters/postgresPooler.js +267 -0
  53. package/dist/adapters/postgresReadCatalog.d.ts +31 -0
  54. package/dist/adapters/postgresReadCatalog.js +226 -0
  55. package/dist/adapters/postgresReadSnapshot.d.ts +46 -0
  56. package/dist/adapters/postgresReadSnapshot.js +133 -0
  57. package/dist/adapters/postgresSchemaEpoch.d.ts +24 -0
  58. package/dist/adapters/postgresSchemaEpoch.js +149 -0
  59. package/dist/adapters/postgresTransactionHandle.d.ts +173 -0
  60. package/dist/adapters/postgresTransactionHandle.js +524 -0
  61. package/dist/adapters/postgresValues.d.ts +30 -0
  62. package/dist/adapters/postgresValues.js +75 -0
  63. package/dist/adapters/replicas.d.ts +70 -0
  64. package/dist/adapters/replicas.js +208 -0
  65. package/dist/adapters/reservedSql.d.ts +38 -0
  66. package/dist/adapters/reservedSql.js +264 -0
  67. package/dist/adapters/rolePrivileges.d.ts +17 -0
  68. package/dist/adapters/rolePrivileges.js +22 -0
  69. package/dist/adapters/scoped/keyRows.d.ts +65 -0
  70. package/dist/adapters/scoped/keyRows.js +173 -0
  71. package/dist/adapters/scoped/postgresScopeCatalog.d.ts +16 -0
  72. package/dist/adapters/scoped/postgresScopeCatalog.js +117 -0
  73. package/dist/adapters/scoped/scopedCommandOperations.d.ts +5 -0
  74. package/dist/adapters/scoped/scopedCommandOperations.js +48 -0
  75. package/dist/adapters/scoped/scopedReads.d.ts +20 -0
  76. package/dist/adapters/scoped/scopedReads.js +174 -0
  77. package/dist/adapters/scoped/scopedTransaction.d.ts +89 -0
  78. package/dist/adapters/scoped/scopedTransaction.js +303 -0
  79. package/dist/adapters/scoped/sqliteScopeCatalog.d.ts +16 -0
  80. package/dist/adapters/scoped/sqliteScopeCatalog.js +241 -0
  81. package/dist/adapters/scoped/updateGuard.d.ts +3 -0
  82. package/dist/adapters/scoped/updateGuard.js +40 -0
  83. package/dist/adapters/serverSettings.d.ts +45 -0
  84. package/dist/adapters/serverSettings.js +46 -0
  85. package/dist/adapters/sqlite.d.ts +262 -0
  86. package/dist/adapters/sqlite.js +1434 -0
  87. package/dist/adapters/sqliteCostlyReads.d.ts +33 -0
  88. package/dist/adapters/sqliteCostlyReads.js +49 -0
  89. package/dist/adapters/sqliteDecimals.d.ts +22 -0
  90. package/dist/adapters/sqliteDecimals.js +57 -0
  91. package/dist/adapters/sqliteHandles.d.ts +43 -0
  92. package/dist/adapters/sqliteHandles.js +143 -0
  93. package/dist/adapters/sqliteStatementProcess.d.ts +29 -0
  94. package/dist/adapters/sqliteStatementProcess.js +131 -0
  95. package/dist/adapters/statementControl.d.ts +34 -0
  96. package/dist/adapters/statementControl.js +90 -0
  97. package/dist/adapters/storeHost.d.ts +130 -0
  98. package/dist/adapters/storeHost.js +13 -0
  99. package/dist/adapters/telemetry/drivers.d.ts +21 -0
  100. package/dist/adapters/telemetry/drivers.js +321 -0
  101. package/dist/adapters/telemetry/metrics.d.ts +63 -0
  102. package/dist/adapters/telemetry/metrics.js +122 -0
  103. package/dist/adapters/telemetry/otlp.d.ts +12 -0
  104. package/dist/adapters/telemetry/otlp.js +320 -0
  105. package/dist/adapters/telemetry/otlpEncode.d.ts +48 -0
  106. package/dist/adapters/telemetry/otlpEncode.js +366 -0
  107. package/dist/adapters/telemetry/otlpEnv.d.ts +1 -0
  108. package/dist/adapters/telemetry/otlpEnv.js +12 -0
  109. package/dist/adapters/telemetry/serverTiming.d.ts +83 -0
  110. package/dist/adapters/telemetry/serverTiming.js +503 -0
  111. package/dist/adapters/telemetry/start.d.ts +10 -0
  112. package/dist/adapters/telemetry/start.js +25 -0
  113. package/dist/adapters/telemetry/statement.d.ts +16 -0
  114. package/dist/adapters/telemetry/statement.js +134 -0
  115. package/dist/adapters/telemetry/trace.d.ts +127 -0
  116. package/dist/adapters/telemetry/trace.js +295 -0
  117. package/dist/adapters/writeAhead.d.ts +27 -0
  118. package/dist/adapters/writeAhead.js +46 -0
  119. package/dist/adapters/writeAttribution.d.ts +18 -0
  120. package/dist/adapters/writeAttribution.js +23 -0
  121. package/dist/adapters/writeCapture.d.ts +73 -0
  122. package/dist/adapters/writeCapture.js +20 -0
  123. package/dist/adapters/writeLanes.d.ts +94 -0
  124. package/dist/adapters/writeLanes.js +232 -0
  125. package/dist/engine.d.ts +15 -0
  126. package/dist/engine.js +13 -0
  127. package/dist/server/auth/credentials.d.ts +61 -0
  128. package/dist/server/auth/credentials.js +260 -0
  129. package/dist/server/cacheService.d.ts +50 -0
  130. package/dist/server/cacheService.js +110 -0
  131. package/dist/server/cli/args.d.ts +176 -0
  132. package/dist/server/cli/args.js +342 -0
  133. package/dist/server/cli/bin.d.ts +5 -0
  134. package/dist/server/cli/bin.js +66 -0
  135. package/dist/server/cli/browser.d.ts +15 -0
  136. package/dist/server/cli/browser.js +37 -0
  137. package/dist/server/cli/config.d.ts +50 -0
  138. package/dist/server/cli/config.js +206 -0
  139. package/dist/server/cli/startup.d.ts +36 -0
  140. package/dist/server/cli/startup.js +128 -0
  141. package/dist/server/cli/startupOptions.d.ts +63 -0
  142. package/dist/server/cli/startupOptions.js +143 -0
  143. package/dist/server/cli/subcommand.d.ts +28 -0
  144. package/dist/server/cli/subcommand.js +32 -0
  145. package/dist/server/cli/usage.d.ts +13 -0
  146. package/dist/server/cli/usage.js +31 -0
  147. package/dist/server/clientHttp.d.ts +184 -0
  148. package/dist/server/clientHttp.js +700 -0
  149. package/dist/server/clientSurface.d.ts +128 -0
  150. package/dist/server/clientSurface.js +182 -0
  151. package/dist/server/columnGrants.d.ts +103 -0
  152. package/dist/server/columnGrants.js +730 -0
  153. package/dist/server/compileCache.d.ts +1 -0
  154. package/dist/server/compileCache.js +30 -0
  155. package/dist/server/config/locations.d.ts +1 -0
  156. package/dist/server/config/locations.js +15 -0
  157. package/dist/server/configPaths.d.ts +7 -0
  158. package/dist/server/configPaths.js +34 -0
  159. package/dist/server/configSections.d.ts +64 -0
  160. package/dist/server/configSections.js +72 -0
  161. package/dist/server/connectionRedaction.d.ts +30 -0
  162. package/dist/server/connectionRedaction.js +77 -0
  163. package/dist/server/connections.d.ts +353 -0
  164. package/dist/server/connections.js +978 -0
  165. package/dist/server/constraints.d.ts +82 -0
  166. package/dist/server/constraints.js +169 -0
  167. package/dist/server/demo.d.ts +9 -0
  168. package/dist/server/demo.js +554 -0
  169. package/dist/server/devclient.d.ts +108 -0
  170. package/dist/server/devclient.js +361 -0
  171. package/dist/server/evidence.d.ts +55 -0
  172. package/dist/server/evidence.js +323 -0
  173. package/dist/server/hiddenColumns.d.ts +32 -0
  174. package/dist/server/hiddenColumns.js +238 -0
  175. package/dist/server/http/baselineHeaders.d.ts +24 -0
  176. package/dist/server/http/baselineHeaders.js +12 -0
  177. package/dist/server/http/captured.d.ts +35 -0
  178. package/dist/server/http/captured.js +73 -0
  179. package/dist/server/http/clock.d.ts +1 -0
  180. package/dist/server/http/clock.js +14 -0
  181. package/dist/server/http/connectionSource.d.ts +4 -0
  182. package/dist/server/http/connectionSource.js +48 -0
  183. package/dist/server/http/context.d.ts +189 -0
  184. package/dist/server/http/context.js +11 -0
  185. package/dist/server/http/crawlerText.d.ts +15 -0
  186. package/dist/server/http/crawlerText.js +32 -0
  187. package/dist/server/http/dataRoutes.d.ts +88 -0
  188. package/dist/server/http/dataRoutes.js +137 -0
  189. package/dist/server/http/door.d.ts +57 -0
  190. package/dist/server/http/door.js +39 -0
  191. package/dist/server/http/exportRoute.d.ts +15 -0
  192. package/dist/server/http/exportRoute.js +320 -0
  193. package/dist/server/http/firstPaint.d.ts +108 -0
  194. package/dist/server/http/firstPaint.js +262 -0
  195. package/dist/server/http/httpOperationRoutes.d.ts +11 -0
  196. package/dist/server/http/httpOperationRoutes.js +50 -0
  197. package/dist/server/http/pageReads.d.ts +20 -0
  198. package/dist/server/http/pageReads.js +205 -0
  199. package/dist/server/http/pageRoutes.d.ts +39 -0
  200. package/dist/server/http/pageRoutes.js +291 -0
  201. package/dist/server/http/probes.d.ts +22 -0
  202. package/dist/server/http/probes.js +27 -0
  203. package/dist/server/http/rateLimit.d.ts +131 -0
  204. package/dist/server/http/rateLimit.js +351 -0
  205. package/dist/server/http/readRoutes.d.ts +9 -0
  206. package/dist/server/http/readRoutes.js +131 -0
  207. package/dist/server/http/readRouting.d.ts +20 -0
  208. package/dist/server/http/readRouting.js +80 -0
  209. package/dist/server/http/recordCompose.d.ts +67 -0
  210. package/dist/server/http/recordCompose.js +167 -0
  211. package/dist/server/http/recordWrites.d.ts +89 -0
  212. package/dist/server/http/recordWrites.js +298 -0
  213. package/dist/server/http/refusalReport.d.ts +38 -0
  214. package/dist/server/http/refusalReport.js +63 -0
  215. package/dist/server/http/reply.d.ts +130 -0
  216. package/dist/server/http/reply.js +394 -0
  217. package/dist/server/http/requestOrigin.d.ts +11 -0
  218. package/dist/server/http/requestOrigin.js +8 -0
  219. package/dist/server/http/router.d.ts +45 -0
  220. package/dist/server/http/router.js +22 -0
  221. package/dist/server/http/serverCore.d.ts +68 -0
  222. package/dist/server/http/serverCore.js +177 -0
  223. package/dist/server/http/traceRequest.d.ts +30 -0
  224. package/dist/server/http/traceRequest.js +224 -0
  225. package/dist/server/http/trust.d.ts +261 -0
  226. package/dist/server/http/trust.js +472 -0
  227. package/dist/server/http/writeRefusal.d.ts +33 -0
  228. package/dist/server/http/writeRefusal.js +24 -0
  229. package/dist/server/httpConnection.d.ts +49 -0
  230. package/dist/server/httpConnection.js +170 -0
  231. package/dist/server/impact.d.ts +55 -0
  232. package/dist/server/impact.js +47 -0
  233. package/dist/server/journal.d.ts +134 -0
  234. package/dist/server/journal.js +398 -0
  235. package/dist/server/keysetReadHttp.d.ts +52 -0
  236. package/dist/server/keysetReadHttp.js +85 -0
  237. package/dist/server/layouts.d.ts +49 -0
  238. package/dist/server/layouts.js +192 -0
  239. package/dist/server/migrate/cli.d.ts +55 -0
  240. package/dist/server/migrate/cli.js +517 -0
  241. package/dist/server/migrate/database.d.ts +37 -0
  242. package/dist/server/migrate/database.js +247 -0
  243. package/dist/server/migrate/desired.d.ts +76 -0
  244. package/dist/server/migrate/desired.js +292 -0
  245. package/dist/server/migrate/files.d.ts +34 -0
  246. package/dist/server/migrate/files.js +141 -0
  247. package/dist/server/migrate/flyway.d.ts +7 -0
  248. package/dist/server/migrate/flyway.js +69 -0
  249. package/dist/server/migrate/history.d.ts +70 -0
  250. package/dist/server/migrate/history.js +211 -0
  251. package/dist/server/migrate/runner.d.ts +100 -0
  252. package/dist/server/migrate/runner.js +409 -0
  253. package/dist/server/migrate/snapshot.d.ts +30 -0
  254. package/dist/server/migrate/snapshot.js +239 -0
  255. package/dist/server/migrate/target.d.ts +33 -0
  256. package/dist/server/migrate/target.js +82 -0
  257. package/dist/server/openapiDraft.d.ts +25 -0
  258. package/dist/server/openapiDraft.js +171 -0
  259. package/dist/server/operations/diagnostics.d.ts +101 -0
  260. package/dist/server/operations/diagnostics.js +284 -0
  261. package/dist/server/operations/requestMetrics.d.ts +33 -0
  262. package/dist/server/operations/requestMetrics.js +94 -0
  263. package/dist/server/packageVersion.d.ts +1 -0
  264. package/dist/server/packageVersion.js +11 -0
  265. package/dist/server/poolConfig.d.ts +34 -0
  266. package/dist/server/poolConfig.js +114 -0
  267. package/dist/server/product.d.ts +20 -0
  268. package/dist/server/product.js +12 -0
  269. package/dist/server/recordHistoryOperations.d.ts +39 -0
  270. package/dist/server/recordHistoryOperations.js +43 -0
  271. package/dist/server/recordWriteOperations.d.ts +111 -0
  272. package/dist/server/recordWriteOperations.js +329 -0
  273. package/dist/server/resourceReadHttp.d.ts +81 -0
  274. package/dist/server/resourceReadHttp.js +606 -0
  275. package/dist/server/resourceReadOperations.d.ts +147 -0
  276. package/dist/server/resourceReadOperations.js +452 -0
  277. package/dist/server/scaffoldMachine.d.ts +54 -0
  278. package/dist/server/scaffoldMachine.js +184 -0
  279. package/dist/server/seed/cli.d.ts +20 -0
  280. package/dist/server/seed/cli.js +164 -0
  281. package/dist/server/seed/lexicon.d.ts +26 -0
  282. package/dist/server/seed/lexicon.js +585 -0
  283. package/dist/server/seed/seed.d.ts +70 -0
  284. package/dist/server/seed/seed.js +779 -0
  285. package/dist/server/seed/words.d.ts +21 -0
  286. package/dist/server/seed/words.js +164 -0
  287. package/dist/server/serverRequests.d.ts +6 -0
  288. package/dist/server/serverRequests.js +33 -0
  289. package/dist/server/serverTimeouts.d.ts +33 -0
  290. package/dist/server/serverTimeouts.js +32 -0
  291. package/dist/server/shapeonly.d.ts +32 -0
  292. package/dist/server/shapeonly.js +110 -0
  293. package/dist/server/startupWarnings.d.ts +32 -0
  294. package/dist/server/startupWarnings.js +92 -0
  295. package/dist/shared/addressParams.d.ts +28 -0
  296. package/dist/shared/addressParams.js +47 -0
  297. package/dist/shared/appCards.d.ts +123 -0
  298. package/dist/shared/appCards.js +385 -0
  299. package/dist/shared/appComponents.d.ts +177 -0
  300. package/dist/shared/appComponents.js +422 -0
  301. package/dist/shared/appDocuments.d.ts +43 -0
  302. package/dist/shared/appDocuments.js +131 -0
  303. package/dist/shared/appEmbeds.d.ts +21 -0
  304. package/dist/shared/appEmbeds.js +24 -0
  305. package/dist/shared/appIcons.d.ts +28 -0
  306. package/dist/shared/appIcons.js +223 -0
  307. package/dist/shared/appLinks.d.ts +17 -0
  308. package/dist/shared/appLinks.js +124 -0
  309. package/dist/shared/appListColumns.d.ts +3 -0
  310. package/dist/shared/appListColumns.js +66 -0
  311. package/dist/shared/appLocale.d.ts +36 -0
  312. package/dist/shared/appLocale.js +86 -0
  313. package/dist/shared/appMessages.d.ts +44 -0
  314. package/dist/shared/appMessages.js +78 -0
  315. package/dist/shared/appNoun.d.ts +21 -0
  316. package/dist/shared/appNoun.js +32 -0
  317. package/dist/shared/autoBucket.d.ts +98 -0
  318. package/dist/shared/autoBucket.js +305 -0
  319. package/dist/shared/autoValues.d.ts +25 -0
  320. package/dist/shared/autoValues.js +25 -0
  321. package/dist/shared/breakdown.d.ts +228 -0
  322. package/dist/shared/breakdown.js +557 -0
  323. package/dist/shared/breakdowntext.d.ts +41 -0
  324. package/dist/shared/breakdowntext.js +400 -0
  325. package/dist/shared/builtInThemes.d.ts +2 -0
  326. package/dist/shared/builtInThemes.js +771 -0
  327. package/dist/shared/chartSeparation.d.ts +11 -0
  328. package/dist/shared/chartSeparation.js +58 -0
  329. package/dist/shared/clauses.d.ts +22 -0
  330. package/dist/shared/clauses.js +97 -0
  331. package/dist/shared/columnCaption.d.ts +16 -0
  332. package/dist/shared/columnCaption.js +90 -0
  333. package/dist/shared/commandFieldPath.d.ts +2 -0
  334. package/dist/shared/commandFieldPath.js +7 -0
  335. package/dist/shared/commandWire.d.ts +26 -0
  336. package/dist/shared/commandWire.js +41 -0
  337. package/dist/shared/computed.d.ts +161 -0
  338. package/dist/shared/computed.js +378 -0
  339. package/dist/shared/computedParse.d.ts +13 -0
  340. package/dist/shared/computedParse.js +278 -0
  341. package/dist/shared/computedValue.d.ts +47 -0
  342. package/dist/shared/computedValue.js +191 -0
  343. package/dist/shared/connection.d.ts +30 -0
  344. package/dist/shared/connection.js +1 -0
  345. package/dist/shared/csv.d.ts +20 -0
  346. package/dist/shared/csv.js +63 -0
  347. package/dist/shared/dashLayout.d.ts +30 -0
  348. package/dist/shared/dashLayout.js +132 -0
  349. package/dist/shared/dashboardAsks.d.ts +93 -0
  350. package/dist/shared/dashboardAsks.js +129 -0
  351. package/dist/shared/dashboardTrend.d.ts +20 -0
  352. package/dist/shared/dashboardTrend.js +50 -0
  353. package/dist/shared/declaredReferences.d.ts +50 -0
  354. package/dist/shared/declaredReferences.js +202 -0
  355. package/dist/shared/definedFields.d.ts +63 -0
  356. package/dist/shared/definedFields.js +103 -0
  357. package/dist/shared/definedValues.d.ts +63 -0
  358. package/dist/shared/definedValues.js +184 -0
  359. package/dist/shared/displayDefaults.d.ts +135 -0
  360. package/dist/shared/displayDefaults.js +529 -0
  361. package/dist/shared/dueDate.d.ts +6 -0
  362. package/dist/shared/dueDate.js +6 -0
  363. package/dist/shared/duration.d.ts +4 -0
  364. package/dist/shared/duration.js +23 -0
  365. package/dist/shared/fileBounds.d.ts +9 -0
  366. package/dist/shared/fileBounds.js +9 -0
  367. package/dist/shared/filter.d.ts +217 -0
  368. package/dist/shared/filter.js +305 -0
  369. package/dist/shared/firstPaint.d.ts +24 -0
  370. package/dist/shared/firstPaint.js +33 -0
  371. package/dist/shared/form.d.ts +21 -0
  372. package/dist/shared/form.js +25 -0
  373. package/dist/shared/formValues.d.ts +104 -0
  374. package/dist/shared/formValues.js +352 -0
  375. package/dist/shared/funnel.d.ts +45 -0
  376. package/dist/shared/funnel.js +108 -0
  377. package/dist/shared/httpOperations.d.ts +48 -0
  378. package/dist/shared/httpOperations.js +9 -0
  379. package/dist/shared/iconGlyphs.d.ts +4 -0
  380. package/dist/shared/iconGlyphs.js +151 -0
  381. package/dist/shared/iconWeights.d.ts +3 -0
  382. package/dist/shared/iconWeights.js +162 -0
  383. package/dist/shared/imageWidths.d.ts +32 -0
  384. package/dist/shared/imageWidths.js +38 -0
  385. package/dist/shared/keysetPage.d.ts +64 -0
  386. package/dist/shared/keysetPage.js +161 -0
  387. package/dist/shared/like.d.ts +20 -0
  388. package/dist/shared/like.js +29 -0
  389. package/dist/shared/listEmpty.d.ts +12 -0
  390. package/dist/shared/listEmpty.js +36 -0
  391. package/dist/shared/listFilters.d.ts +28 -0
  392. package/dist/shared/listFilters.js +84 -0
  393. package/dist/shared/listPresentations.d.ts +199 -0
  394. package/dist/shared/listPresentations.js +7 -0
  395. package/dist/shared/listQuestion.d.ts +52 -0
  396. package/dist/shared/listQuestion.js +137 -0
  397. package/dist/shared/lookPalettes.d.ts +62 -0
  398. package/dist/shared/lookPalettes.js +306 -0
  399. package/dist/shared/maskQuoted.d.ts +24 -0
  400. package/dist/shared/maskQuoted.js +48 -0
  401. package/dist/shared/mentionLabel.d.ts +19 -0
  402. package/dist/shared/mentionLabel.js +38 -0
  403. package/dist/shared/mentionLookup.d.ts +17 -0
  404. package/dist/shared/mentionLookup.js +64 -0
  405. package/dist/shared/menuCounts.d.ts +16 -0
  406. package/dist/shared/menuCounts.js +74 -0
  407. package/dist/shared/model.d.ts +79 -0
  408. package/dist/shared/model.js +153 -0
  409. package/dist/shared/money.d.ts +44 -0
  410. package/dist/shared/money.js +81 -0
  411. package/dist/shared/moneyEntry.d.ts +7 -0
  412. package/dist/shared/moneyEntry.js +27 -0
  413. package/dist/shared/mount.d.ts +118 -0
  414. package/dist/shared/mount.js +248 -0
  415. package/dist/shared/niceTicks.d.ts +26 -0
  416. package/dist/shared/niceTicks.js +50 -0
  417. package/dist/shared/order.d.ts +59 -0
  418. package/dist/shared/order.js +133 -0
  419. package/dist/shared/page.d.ts +135 -0
  420. package/dist/shared/page.js +1187 -0
  421. package/dist/shared/pageAnatomy.d.ts +99 -0
  422. package/dist/shared/pageAnatomy.js +370 -0
  423. package/dist/shared/pageConfig.d.ts +25 -0
  424. package/dist/shared/pageConfig.js +1308 -0
  425. package/dist/shared/pageEmptyActions.d.ts +12 -0
  426. package/dist/shared/pageEmptyActions.js +20 -0
  427. package/dist/shared/pageLayouts.d.ts +72 -0
  428. package/dist/shared/pageLayouts.js +205 -0
  429. package/dist/shared/pageModel.d.ts +785 -0
  430. package/dist/shared/pageModel.js +121 -0
  431. package/dist/shared/pagePaths.d.ts +180 -0
  432. package/dist/shared/pagePaths.js +869 -0
  433. package/dist/shared/pagePlans.d.ts +52 -0
  434. package/dist/shared/pagePlans.js +108 -0
  435. package/dist/shared/pageRoutes.d.ts +9 -0
  436. package/dist/shared/pageRoutes.js +9 -0
  437. package/dist/shared/query.d.ts +166 -0
  438. package/dist/shared/query.js +1302 -0
  439. package/dist/shared/queryDates.d.ts +12 -0
  440. package/dist/shared/queryDates.js +101 -0
  441. package/dist/shared/queryOperands.d.ts +99 -0
  442. package/dist/shared/queryOperands.js +131 -0
  443. package/dist/shared/reads.d.ts +103 -0
  444. package/dist/shared/reads.js +154 -0
  445. package/dist/shared/recordLabel.d.ts +51 -0
  446. package/dist/shared/recordLabel.js +123 -0
  447. package/dist/shared/recordReadKeys.d.ts +30 -0
  448. package/dist/shared/recordReadKeys.js +51 -0
  449. package/dist/shared/recordReads.d.ts +268 -0
  450. package/dist/shared/recordReads.js +368 -0
  451. package/dist/shared/recordview.d.ts +198 -0
  452. package/dist/shared/recordview.js +356 -0
  453. package/dist/shared/referenceModel.d.ts +58 -0
  454. package/dist/shared/referenceModel.js +194 -0
  455. package/dist/shared/refusal.d.ts +64 -0
  456. package/dist/shared/refusal.js +144 -0
  457. package/dist/shared/relatedCreate.d.ts +30 -0
  458. package/dist/shared/relatedCreate.js +162 -0
  459. package/dist/shared/resourceHttp.d.ts +464 -0
  460. package/dist/shared/resourceHttp.js +1 -0
  461. package/dist/shared/richText.d.ts +85 -0
  462. package/dist/shared/richText.js +305 -0
  463. package/dist/shared/rollups.d.ts +143 -0
  464. package/dist/shared/rollups.js +64 -0
  465. package/dist/shared/rowScope.d.ts +72 -0
  466. package/dist/shared/rowScope.js +376 -0
  467. package/dist/shared/runtimeTables.d.ts +44 -0
  468. package/dist/shared/runtimeTables.js +79 -0
  469. package/dist/shared/schema.d.ts +523 -0
  470. package/dist/shared/schema.js +627 -0
  471. package/dist/shared/schematext.d.ts +38 -0
  472. package/dist/shared/schematext.js +101 -0
  473. package/dist/shared/scopeCatalog.d.ts +29 -0
  474. package/dist/shared/scopeCatalog.js +468 -0
  475. package/dist/shared/servedApp.d.ts +681 -0
  476. package/dist/shared/servedApp.js +45 -0
  477. package/dist/shared/sessionLease.d.ts +34 -0
  478. package/dist/shared/sessionLease.js +3 -0
  479. package/dist/shared/shape.d.ts +55 -0
  480. package/dist/shared/shape.js +168 -0
  481. package/dist/shared/slug.d.ts +1 -0
  482. package/dist/shared/slug.js +12 -0
  483. package/dist/shared/sortText.d.ts +14 -0
  484. package/dist/shared/sortText.js +26 -0
  485. package/dist/shared/sqlRelation.d.ts +4 -0
  486. package/dist/shared/sqlRelation.js +8 -0
  487. package/dist/shared/sqlsaved.d.ts +44 -0
  488. package/dist/shared/sqlsaved.js +63 -0
  489. package/dist/shared/stitchedPaths.d.ts +27 -0
  490. package/dist/shared/stitchedPaths.js +38 -0
  491. package/dist/shared/structuredFilter.d.ts +22 -0
  492. package/dist/shared/structuredFilter.js +1 -0
  493. package/dist/shared/subtitlePath.d.ts +20 -0
  494. package/dist/shared/subtitlePath.js +24 -0
  495. package/dist/shared/suggest.d.ts +18 -0
  496. package/dist/shared/suggest.js +59 -0
  497. package/dist/shared/tableSizing.d.ts +4 -0
  498. package/dist/shared/tableSizing.js +9 -0
  499. package/dist/shared/tagLists.d.ts +57 -0
  500. package/dist/shared/tagLists.js +34 -0
  501. package/dist/shared/textRules.d.ts +54 -0
  502. package/dist/shared/textRules.js +133 -0
  503. package/dist/shared/theme.d.ts +94 -0
  504. package/dist/shared/theme.js +800 -0
  505. package/dist/shared/themeColor.d.ts +34 -0
  506. package/dist/shared/themeColor.js +109 -0
  507. package/dist/shared/themeFaces.d.ts +30 -0
  508. package/dist/shared/themeFaces.js +42 -0
  509. package/dist/shared/themeInk.d.ts +20 -0
  510. package/dist/shared/themeInk.js +52 -0
  511. package/dist/shared/themeLooks.d.ts +9 -0
  512. package/dist/shared/themeLooks.js +572 -0
  513. package/dist/shared/themeParts.d.ts +26 -0
  514. package/dist/shared/themeParts.js +71 -0
  515. package/dist/shared/themePartsCheck.d.ts +21 -0
  516. package/dist/shared/themePartsCheck.js +91 -0
  517. package/dist/shared/themePresets.d.ts +85 -0
  518. package/dist/shared/themePresets.js +139 -0
  519. package/dist/shared/themeRecipeWords.d.ts +156 -0
  520. package/dist/shared/themeRecipeWords.js +156 -0
  521. package/dist/shared/themeRecipes.d.ts +213 -0
  522. package/dist/shared/themeRecipes.js +234 -0
  523. package/dist/shared/themeResolve.d.ts +55 -0
  524. package/dist/shared/themeResolve.js +52 -0
  525. package/dist/shared/themeTokens.d.ts +107 -0
  526. package/dist/shared/themeTokens.js +116 -0
  527. package/dist/shared/themeType.d.ts +38 -0
  528. package/dist/shared/themeType.js +205 -0
  529. package/dist/shared/unitWord.d.ts +4 -0
  530. package/dist/shared/unitWord.js +37 -0
  531. package/dist/shared/view.d.ts +195 -0
  532. package/dist/shared/view.js +987 -0
  533. package/dist/shared/viewLabels.d.ts +47 -0
  534. package/dist/shared/viewLabels.js +459 -0
  535. package/dist/shared/viewPaths.d.ts +248 -0
  536. package/dist/shared/viewPaths.js +294 -0
  537. package/dist/shared/viewtext.d.ts +57 -0
  538. package/dist/shared/viewtext.js +282 -0
  539. package/dist/shared/vocabulary.d.ts +71 -0
  540. package/dist/shared/vocabulary.js +249 -0
  541. package/dist/shared/weekStart.d.ts +7 -0
  542. package/dist/shared/weekStart.js +36 -0
  543. package/mark.svg +1 -0
  544. package/package.json +261 -4
  545. package/schema/model.d.ts +298 -0
  546. package/schema/theme.d.ts +587 -0
@@ -0,0 +1,351 @@
1
+ import { CacheUnavailable, scopedCache } from '../../adapters/cache/cacheStore.js';
2
+ import { forwardedClient, ipv6Groups } from './trust.js';
3
+ const MAX_CLIENTS = 10_000;
4
+ function assertWindows(windows) {
5
+ if (!windows.length || windows.some((w) => !Number.isSafeInteger(w.limit) || w.limit < 1 || !Number.isFinite(w.ms) || w.ms <= 0)) {
6
+ throw new Error('A rate limiter needs at least one window of a positive limit over a positive span.');
7
+ }
8
+ }
9
+ /** One budget over a set of windows: where each window started and what it has counted. */
10
+ class Budget {
11
+ starts;
12
+ counts;
13
+ seen;
14
+ constructor(windows, now) {
15
+ this.starts = windows.map(() => now);
16
+ this.counts = windows.map(() => 0);
17
+ this.seen = now;
18
+ }
19
+ /** Roll over the windows that have elapsed; the seconds until the longest exceeded one reopens, or 0. */
20
+ wait(windows, now) {
21
+ let wait = 0;
22
+ windows.forEach((window, i) => {
23
+ if (now - this.starts[i] >= window.ms) {
24
+ this.starts[i] = now;
25
+ this.counts[i] = 0;
26
+ }
27
+ if (this.counts[i] >= window.limit)
28
+ wait = Math.max(wait, Math.ceil((this.starts[i] + window.ms - now) / 1000), 1);
29
+ });
30
+ return wait;
31
+ }
32
+ /** Count one request; what is left in the tightest window. */
33
+ count(windows) {
34
+ let remaining = Infinity;
35
+ windows.forEach((window, i) => {
36
+ this.counts[i]++;
37
+ remaining = Math.min(remaining, window.limit - this.counts[i]);
38
+ });
39
+ return remaining;
40
+ }
41
+ }
42
+ /**
43
+ * The key a client's budget is kept under. IPv4 as it is; an IPv4-mapped
44
+ * IPv6 address (`::ffff:192.0.2.1`, how a dual-stack socket reports an IPv4
45
+ * peer) as that IPv4 address; any other IPv6 address as its /64, the
46
+ * smallest network one subscriber is routinely given — one host can
47
+ * otherwise draw a fresh budget from each of its 2^64 addresses. Anything
48
+ * that is not an address (`unknown`) is its own key.
49
+ */
50
+ export function limitKey(address) {
51
+ if (!address.includes(':'))
52
+ return address;
53
+ const groups = ipv6Groups(address);
54
+ if (!groups)
55
+ return address;
56
+ if (groups.slice(0, 5).every((group) => group === 0) && groups[5] === 0xffff) {
57
+ return `${groups[6] >> 8}.${groups[6] & 255}.${groups[7] >> 8}.${groups[7] & 255}`;
58
+ }
59
+ return `${groups
60
+ .slice(0, 4)
61
+ .map((group) => group.toString(16))
62
+ .join(':')}::/64`;
63
+ }
64
+ export class FixedWindowLimiter {
65
+ windows;
66
+ now;
67
+ /* Least recently seen first. Named `hits` still: the review's probe reads its size. */
68
+ hits = new Map();
69
+ longest;
70
+ maxClients;
71
+ whenFull;
72
+ totalWindows;
73
+ total;
74
+ constructor(windows, now = Date.now, options = {}) {
75
+ this.windows = windows;
76
+ this.now = now;
77
+ assertWindows(windows);
78
+ if (options.total)
79
+ assertWindows(options.total);
80
+ const maxClients = options.maxClients ?? MAX_CLIENTS;
81
+ if (!Number.isSafeInteger(maxClients) || maxClients < 1)
82
+ throw new Error('A rate limiter tracks at least one client.');
83
+ this.longest = Math.max(...windows.map((window) => window.ms));
84
+ this.maxClients = maxClients;
85
+ this.whenFull = options.whenFull ?? 'refuse';
86
+ this.totalWindows = options.total;
87
+ }
88
+ /** Count one request for the client, or say how long it waits. */
89
+ take(address, part = 'both') {
90
+ const now = this.now();
91
+ this.expire(now);
92
+ if (part === 'all')
93
+ return this.takeShared(now) ?? { ok: true, remaining: Infinity };
94
+ const key = limitKey(address);
95
+ const entry = this.hits.get(key);
96
+ if (entry) {
97
+ // Seen again, refused or not: a client still knocking keeps what it spent.
98
+ this.hits.delete(key);
99
+ this.hits.set(key, entry);
100
+ entry.seen = now;
101
+ const wait = entry.wait(this.windows, now);
102
+ if (wait > 0)
103
+ return { ok: false, retryAfterSeconds: wait, scope: 'client' };
104
+ }
105
+ const shared = part === 'both' && this.totalWindows ? (this.total ??= new Budget(this.totalWindows, now)) : undefined;
106
+ const sharedWait = shared ? shared.wait(this.totalWindows, now) : 0;
107
+ if (sharedWait > 0)
108
+ return { ok: false, retryAfterSeconds: sharedWait, scope: 'all' };
109
+ let budget = entry;
110
+ if (!budget) {
111
+ if (this.hits.size >= this.maxClients) {
112
+ const [stalest, oldest] = this.hits.entries().next().value;
113
+ /* Every slot holds a budget still in force. Evicting one forgets
114
+ what that client spent, so a client rotating addresses past the
115
+ cap would come back to a fresh budget — the one thing a limiter
116
+ exists to withhold. `refuse` keeps every budget and turns the
117
+ newcomer away until the stalest slot expires on its own (at most
118
+ the longest window): the fail-safe direction, and the submit
119
+ limiter's. It refuses no one a flood would not already have
120
+ refused, since reaching the cap there needs more admitted
121
+ submissions than the shared ceiling allows in a window. `evict`
122
+ is for reads, where a forgotten budget costs a page of
123
+ presentation and a refusal would let a flood of addresses blank
124
+ the form for everyone arriving after it. */
125
+ if (this.whenFull === 'refuse') {
126
+ return { ok: false, retryAfterSeconds: Math.max(1, Math.ceil((oldest.seen + this.longest - now) / 1000)), scope: 'all' };
127
+ }
128
+ this.hits.delete(stalest);
129
+ }
130
+ budget = new Budget(this.windows, now);
131
+ this.hits.set(key, budget);
132
+ }
133
+ const remaining = budget.count(this.windows);
134
+ shared?.count(this.totalWindows);
135
+ return { ok: true, remaining };
136
+ }
137
+ /* The shared ceiling alone: a refusal, or undefined once counted (or where there is none). */
138
+ takeShared(now) {
139
+ if (!this.totalWindows)
140
+ return undefined;
141
+ const shared = (this.total ??= new Budget(this.totalWindows, now));
142
+ const wait = shared.wait(this.totalWindows, now);
143
+ if (wait > 0)
144
+ return { ok: false, retryAfterSeconds: wait, scope: 'all' };
145
+ shared.count(this.totalWindows);
146
+ return undefined;
147
+ }
148
+ /** How many clients are tracked; tests read it. */
149
+ get size() {
150
+ return this.hits.size;
151
+ }
152
+ /** Forget every client and the shared count; tests and a policy reload use it. */
153
+ reset() {
154
+ this.hits.clear();
155
+ this.total = undefined;
156
+ }
157
+ /* A budget last seen a longest-window ago has nothing left in force:
158
+ each take rolls over what elapsed, so every window then began after
159
+ `seen - longest`. The Map is in seen order, so the sweep stops at the
160
+ first entry still live. */
161
+ expire(now) {
162
+ for (const [key, entry] of this.hits) {
163
+ if (entry.seen + this.longest > now)
164
+ break;
165
+ this.hits.delete(key);
166
+ }
167
+ }
168
+ }
169
+ /**
170
+ * The same windows, counted in the deployment's cache so every instance
171
+ * spends one budget. Each window is a key per client (and one for everyone)
172
+ * counted by the cache's atomic windowed count, which starts the window on
173
+ * the first request; a refused request is counted too, which only keeps an
174
+ * exceeded window exceeded until it ends on its own. There is no cap on
175
+ * tracked clients to keep: every key expires with its window.
176
+ *
177
+ * When the cache cannot count, the process's own limiter decides — the
178
+ * budget degrades to one instance's, never to none.
179
+ */
180
+ export class SharedWindowLimiter {
181
+ name;
182
+ windows;
183
+ cache;
184
+ fallback;
185
+ totalWindows;
186
+ constructor(name, windows, cache, fallback, totalWindows) {
187
+ this.name = name;
188
+ this.windows = windows;
189
+ this.cache = cache;
190
+ this.fallback = fallback;
191
+ this.totalWindows = totalWindows;
192
+ assertWindows(windows);
193
+ if (totalWindows)
194
+ assertWindows(totalWindows);
195
+ }
196
+ async take(address, part = 'both') {
197
+ try {
198
+ let remaining = Infinity;
199
+ if (part !== 'all') {
200
+ const client = await this.count(this.windows, `${this.name}:${limitKey(address)}`);
201
+ if (client.wait > 0)
202
+ return { ok: false, retryAfterSeconds: client.wait, scope: 'client' };
203
+ remaining = client.remaining;
204
+ }
205
+ if (part !== 'client' && this.totalWindows) {
206
+ const all = await this.count(this.totalWindows, `${this.name}:*`);
207
+ if (all.wait > 0)
208
+ return { ok: false, retryAfterSeconds: all.wait, scope: 'all' };
209
+ }
210
+ return { ok: true, remaining };
211
+ }
212
+ catch (error) {
213
+ if (!(error instanceof CacheUnavailable))
214
+ throw error;
215
+ return this.fallback.take(address, part);
216
+ }
217
+ }
218
+ reset() {
219
+ this.fallback.reset();
220
+ }
221
+ async count(windows, key) {
222
+ let wait = 0;
223
+ let remaining = Infinity;
224
+ for (const [i, window] of windows.entries()) {
225
+ const { count, ttlMs } = await this.cache.incr(`${key}:${i}`, window.ms);
226
+ if (count > window.limit)
227
+ wait = Math.max(wait, Math.max(1, Math.ceil(ttlMs / 1000)));
228
+ else
229
+ remaining = Math.min(remaining, window.limit - count);
230
+ }
231
+ return { wait, remaining };
232
+ }
233
+ }
234
+ /** The client a limit counts against; a forwarded header only from a trusted peer (loopback, or `--trust-proxy`). */
235
+ export function clientAddress(req, trusted = []) {
236
+ return forwardedClient(req, trusted);
237
+ }
238
+ /* The public forms' defaults, across every public form of the App: five
239
+ submissions a minute and thirty an hour per client, three hundred an hour
240
+ across every client, sixty reads a minute per client. One instance per
241
+ process, shared by every request; `resetPublicFormLimits` is for tests
242
+ that run several servers in one. */
243
+ export const PUBLIC_FORM_SUBMIT_WINDOWS = Object.freeze([
244
+ { limit: 5, ms: 60_000 },
245
+ { limit: 30, ms: 3_600_000 },
246
+ ]);
247
+ export const PUBLIC_FORM_SUBMIT_TOTAL = Object.freeze([{ limit: 300, ms: 3_600_000 }]);
248
+ export const PUBLIC_FORM_READ_WINDOWS = Object.freeze([{ limit: 60, ms: 60_000 }]);
249
+ /* An account-creating invitation's claim is shaped like a submission — the
250
+ same per-client windows and ceiling, the same refusal — but counted in a
251
+ budget of its own: a busy public form must not use up the claims a dealer's
252
+ new staff can make, nor the other way about. */
253
+ export const INVITATION_CLAIM_WINDOWS = PUBLIC_FORM_SUBMIT_WINDOWS;
254
+ export const INVITATION_CLAIM_TOTAL = PUBLIC_FORM_SUBMIT_TOTAL;
255
+ /* A form saved on every step opens a draft in the App's real tables on its
256
+ first step, so the drafts one client may open are capped apart from its
257
+ submissions: ten an hour — an applicant who starts over a few times is never
258
+ near it, and a script cannot fill the root table with abandoned drafts. A
259
+ status check is a guess at a receipt and its confirmations, so it is
260
+ counted tighter still, per client here and per receipt in its own lockout
261
+ (forms/statusCheck.ts). */
262
+ const SAVED_FORM_START_WINDOWS = Object.freeze([{ limit: 10, ms: 3_600_000 }]);
263
+ const SAVED_FORM_START_TOTAL = Object.freeze([{ limit: 500, ms: 3_600_000 }]);
264
+ const STATUS_CHECK_WINDOWS = Object.freeze([
265
+ { limit: 5, ms: 60_000 },
266
+ { limit: 20, ms: 3_600_000 },
267
+ ]);
268
+ const STATUS_CHECK_TOTAL = Object.freeze([{ limit: 600, ms: 3_600_000 }]);
269
+ /* Adding an application to an account — spending the browser's claim, or
270
+ linking after a status check — is counted on its own too: a person links
271
+ the one application they made, so a handful a minute is already generous. */
272
+ const LINK_WINDOWS = Object.freeze([
273
+ { limit: 5, ms: 60_000 },
274
+ { limit: 20, ms: 3_600_000 },
275
+ ]);
276
+ const LINK_TOTAL = Object.freeze([{ limit: 300, ms: 3_600_000 }]);
277
+ /* A request that makes the server send an email — a code to prove an
278
+ address — is counted apart and tightest: a person asks for one or two. */
279
+ const CODE_WINDOWS = Object.freeze([
280
+ { limit: 3, ms: 60_000 },
281
+ { limit: 10, ms: 3_600_000 },
282
+ ]);
283
+ const CODE_TOTAL = Object.freeze([{ limit: 300, ms: 3_600_000 }]);
284
+ /* A step's check: a form's own pages asking the server's word as someone goes on, so a page's worth a minute from one
285
+ client, and never counted against what that client may submit. */
286
+ const CHECK_WINDOWS = Object.freeze([{ limit: 60, ms: 60_000 }]);
287
+ const CHECK_TOTAL = Object.freeze([{ limit: 6_000, ms: 60_000 }]);
288
+ const check = new FixedWindowLimiter(CHECK_WINDOWS, Date.now, { total: CHECK_TOTAL, whenFull: 'evict' });
289
+ const submit = new FixedWindowLimiter(PUBLIC_FORM_SUBMIT_WINDOWS, Date.now, { total: PUBLIC_FORM_SUBMIT_TOTAL, whenFull: 'refuse' });
290
+ const read = new FixedWindowLimiter(PUBLIC_FORM_READ_WINDOWS, Date.now, { whenFull: 'evict' });
291
+ const claim = new FixedWindowLimiter(INVITATION_CLAIM_WINDOWS, Date.now, { total: INVITATION_CLAIM_TOTAL, whenFull: 'refuse' });
292
+ const start = new FixedWindowLimiter(SAVED_FORM_START_WINDOWS, Date.now, { total: SAVED_FORM_START_TOTAL, whenFull: 'refuse' });
293
+ const status = new FixedWindowLimiter(STATUS_CHECK_WINDOWS, Date.now, { total: STATUS_CHECK_TOTAL, whenFull: 'refuse' });
294
+ const link = new FixedWindowLimiter(LINK_WINDOWS, Date.now, { total: LINK_TOTAL, whenFull: 'refuse' });
295
+ const code = new FixedWindowLimiter(CODE_WINDOWS, Date.now, { total: CODE_TOTAL, whenFull: 'refuse' });
296
+ let shared;
297
+ export function publicFormLimiter(kind) {
298
+ if (shared)
299
+ return shared[kind];
300
+ if (kind === 'check')
301
+ return check;
302
+ return kind === 'submit'
303
+ ? submit
304
+ : kind === 'read'
305
+ ? read
306
+ : kind === 'start'
307
+ ? start
308
+ : kind === 'link'
309
+ ? link
310
+ : kind === 'code'
311
+ ? code
312
+ : status;
313
+ }
314
+ /** The invitation claims' own budget (tenantInvitationHttp.ts), never the forms'. */
315
+ export function invitationClaimLimiter() {
316
+ return shared ? shared.claim : claim;
317
+ }
318
+ /**
319
+ * Count the public forms' windows in the deployment's cache, under the
320
+ * deployment's namespace (`tw:<app>:form:`), or — with no cache, or the
321
+ * process's own — in this process, as before.
322
+ */
323
+ export function configurePublicFormLimits(cache, namespace) {
324
+ if (!cache || cache.kind === 'memory') {
325
+ shared = undefined;
326
+ return;
327
+ }
328
+ const scoped = scopedCache(cache, `tw:${namespace}:form:`);
329
+ shared = {
330
+ submit: new SharedWindowLimiter('submit', PUBLIC_FORM_SUBMIT_WINDOWS, scoped, submit, PUBLIC_FORM_SUBMIT_TOTAL),
331
+ read: new SharedWindowLimiter('read', PUBLIC_FORM_READ_WINDOWS, scoped, read),
332
+ // Its own key prefix, so the claims' windows are counted apart from the forms'.
333
+ claim: new SharedWindowLimiter('claim', INVITATION_CLAIM_WINDOWS, scoped, claim, INVITATION_CLAIM_TOTAL),
334
+ start: new SharedWindowLimiter('start', SAVED_FORM_START_WINDOWS, scoped, start, SAVED_FORM_START_TOTAL),
335
+ status: new SharedWindowLimiter('status', STATUS_CHECK_WINDOWS, scoped, status, STATUS_CHECK_TOTAL),
336
+ link: new SharedWindowLimiter('link', LINK_WINDOWS, scoped, link, LINK_TOTAL),
337
+ code: new SharedWindowLimiter('code', CODE_WINDOWS, scoped, code, CODE_TOTAL),
338
+ check: new SharedWindowLimiter('check', CHECK_WINDOWS, scoped, check, CHECK_TOTAL),
339
+ };
340
+ }
341
+ /** Forgets the forms' budgets and the claims'; tests and a policy reload use it. */
342
+ export function resetPublicFormLimits() {
343
+ submit.reset();
344
+ read.reset();
345
+ claim.reset();
346
+ start.reset();
347
+ status.reset();
348
+ link.reset();
349
+ code.reset();
350
+ check.reset();
351
+ }
@@ -0,0 +1,9 @@
1
+ import { type RequestContext, type ResolvedSource } from './context.js';
2
+ /** What a product serves among the reads. */
3
+ export interface ReadHooks {
4
+ /** What the client draws around the data: the App, its pages, the stored layouts and filters. True when answered. */
5
+ projection(ctx: RequestContext, source: ResolvedSource): Promise<boolean>;
6
+ /** One file's bytes, from a resource whose rows are files. False where the resource holds none. */
7
+ file?(ctx: RequestContext, source: ResolvedSource): Promise<boolean>;
8
+ }
9
+ export declare function readRoutes(ctx: RequestContext, source: ResolvedSource, hooks: ReadHooks): Promise<boolean>;
@@ -0,0 +1,131 @@
1
+ /**
2
+ * The GET reads that need a resolved database: the schema and the
3
+ * connection-scoped halves of the config file — views, saved SQL, a table's
4
+ * DDL. What a product draws around the data (`ReadHooks.projection`: an
5
+ * App's payload and pages, or the database browser's) sits between them in
6
+ * the same chain, and a resource whose rows are files is the App's
7
+ * (`ReadHooks.file`, appFileRead.ts).
8
+ */
9
+ import { validateView } from '../../shared/view.js';
10
+ import { textToView, viewToTextWithSchema } from '../../shared/viewtext.js';
11
+ import { queriesFor } from '../../shared/sqlsaved.js';
12
+ import { findTable, renderDDL } from '../../shared/schema.js';
13
+ import { send, sendRevalidated } from './reply.js';
14
+ import { principalOf } from './context.js';
15
+ /** The `Sec-Fetch-Dest` values that load what they fetch as code. */
16
+ const SCRIPT_DESTINATIONS = new Set(['script', 'style', 'worker', 'sharedworker', 'serviceworker', 'audioworklet', 'paintworklet', 'xslt']);
17
+ export async function readRoutes(ctx, source, hooks) {
18
+ const { res, url, path, registry, configViews, configQueries } = ctx;
19
+ const { adapter, schema, access, connectionId, publicScope, publicDefinition } = source;
20
+ /**
21
+ * Views defined in the config file, for the connection in hand.
22
+ *
23
+ * Saved views live in the browser, per connection — they are one person's
24
+ * working set, and writing them into a file the server owns would make a
25
+ * page silently edit something on disk. Config views are the shared half:
26
+ * checked into a repo, the same for everyone, and read-only from here.
27
+ *
28
+ * A view whose base table does not exist on this connection is returned
29
+ * *with its reason* rather than dropped. Dropping it shows a shorter list
30
+ * and no explanation, which is the failure this whole tool argues against.
31
+ */
32
+ if (path === '/api/views') {
33
+ const name = registry.list().find((c) => c.id === connectionId)?.name;
34
+ const mine = configViews.filter((v) => !v.connection || v.connection === connectionId || v.connection === name);
35
+ send(res, 200, {
36
+ ...publicScope,
37
+ views: access ? [] : mine.map((v) => publicDefinition(materialise(schema, v))),
38
+ });
39
+ return true;
40
+ }
41
+ if (path === '/api/schema') {
42
+ sendRevalidated(res, schema, principalOf(ctx.identity));
43
+ return true;
44
+ }
45
+ /**
46
+ * One file's bytes, from a resource whose rows are files (`file` on the
47
+ * resource). The read is the ordinary query, so the App's table and field
48
+ * grants apply to it, asked for the bytes instead of their label. A
49
+ * download, unless `inline=1` asks for a picture and the bytes are one: a
50
+ * stored type is only the uploader's claim, so it never decides either.
51
+ * `variant=thumb` asks for the resource's smaller copy (`file.thumbnail`),
52
+ * which a card draws at a third of the width; a resource or a row without
53
+ * one answers with the file itself.
54
+ */
55
+ if (path === '/api/file') {
56
+ /* An upload is never code to run. A page that loads one as a script or a
57
+ stylesheet (`<script src="/api/file?…">`) asks with its destination,
58
+ and is refused before anything is read: with nosniff and a download's
59
+ type the browser would refuse it too, but only if it honours both. */
60
+ if (SCRIPT_DESTINATIONS.has(String(ctx.req.headers['sec-fetch-dest'] ?? '').toLowerCase())) {
61
+ send(res, 403, { error: 'A file is not served as a script or a stylesheet.' });
62
+ return true;
63
+ }
64
+ if (!(await hooks.file?.(ctx, source)))
65
+ send(res, 404, { error: 'This resource does not hold files.' });
66
+ return true;
67
+ }
68
+ if (await hooks.projection(ctx, source))
69
+ return true;
70
+ /**
71
+ * SQL statements the config file names, for the connection in hand.
72
+ *
73
+ * The committable half of saved SQL. The other half lives in the browser,
74
+ * and the client merges them — a statement someone checked in and one you
75
+ * saved this morning are the same kind of thing to whoever is looking for
76
+ * one, and only differ in whether you may delete it.
77
+ */
78
+ if (path === '/api/queries') {
79
+ const name = registry.list().find((c) => c.id === connectionId)?.name;
80
+ send(res, 200, {
81
+ connection: connectionId,
82
+ queries: queriesFor(configQueries, connectionId, name),
83
+ });
84
+ return true;
85
+ }
86
+ /**
87
+ * A table's definition. `exact` tells the client whether it is looking at
88
+ * the database's own stored DDL or a reconstruction from the catalog, so
89
+ * the page can label it rather than implying an authority it lacks.
90
+ */
91
+ if (path === '/api/ddl') {
92
+ const tableId = url.searchParams.get('table') ?? '';
93
+ if (!findTable(schema, tableId)) {
94
+ send(res, 404, { error: `Unknown table "${tableId}"` });
95
+ return true;
96
+ }
97
+ const stored = adapter.ddl ? await adapter.ddl(tableId) : undefined;
98
+ send(res, 200, {
99
+ table: tableId,
100
+ sql: stored ?? renderDDL(schema, tableId),
101
+ exact: Boolean(stored),
102
+ });
103
+ return true;
104
+ }
105
+ return false;
106
+ }
107
+ /**
108
+ * Expand a config view against a live schema, and say what is wrong with it.
109
+ *
110
+ * A view written as text cannot be expanded when the config file is read —
111
+ * there is no connection open yet, and the text names tables. So it is
112
+ * carried through and resolved here, where a schema exists. Both halves are
113
+ * returned: the structure, so the composer can edit it by clicking, and the
114
+ * text, so it can be read and edited as a statement.
115
+ *
116
+ * A view that does not resolve comes back *with its reason*, never dropped.
117
+ * Dropping it gives someone a shorter list and no explanation, which is the
118
+ * failure this whole tool argues against.
119
+ */
120
+ function materialise(schema, view) {
121
+ if (!view.text) {
122
+ const error = validateView(schema, view);
123
+ return { ...view, error, text: error ? undefined : viewToTextWithSchema(schema, view) };
124
+ }
125
+ const parsed = textToView(schema, view.text, { id: view.id, name: view.name });
126
+ if (!parsed.view || parsed.errors.length) {
127
+ return { ...view, error: parsed.errors[0]?.message ?? `"${view.name}" could not be read.` };
128
+ }
129
+ const expanded = { ...parsed.view, source: view.source, connection: view.connection, text: view.text };
130
+ return { ...expanded, error: validateView(schema, expanded) };
131
+ }
@@ -0,0 +1,20 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { type ReadContext } from '../../adapters/replicas.js';
3
+ /** Whether the POST `path` with `body` may read from a replica. */
4
+ export declare function toleratesLag(path: string, body: Readonly<Record<string, unknown>>): boolean;
5
+ /** The cookie a write sets so the same browser's next reads go to the primary, in the running product's name. */
6
+ export declare const freshCookie: () => string;
7
+ /**
8
+ * The read-your-write context for one request (replicas.ts `readsAs`).
9
+ *
10
+ * A browser carries the marker: a write sets `<product>_fresh=<write time>` (`mistri_fresh`, or `tablewalk_fresh` in the browser)
11
+ * for FRESH_READ_MS on the App's base path, and a request that brings one
12
+ * back within that time reads the primary. It needs no shared state, so it
13
+ * holds whichever pod the next request reaches, and each visitor — signed
14
+ * in or not — has their own. It is HttpOnly and SameSite=Lax like the
15
+ * other cookies here, and never Secure-only: it holds a time, not a
16
+ * secret, and a forged or stolen one buys nothing but primary reads for
17
+ * ten seconds. A caller sending a bearer token has no cookie jar, so its
18
+ * writes are remembered in this process under a digest of the token.
19
+ */
20
+ export declare function readFreshness(request: Pick<IncomingMessage, 'headers'>, response: Pick<ServerResponse, 'headersSent' | 'getHeader' | 'setHeader'>, base: string, now?: () => number): ReadContext;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Which body routes may read from a replica (packages/engine/src/adapters/replicas.ts).
3
+ *
4
+ * Lag-tolerant: a list's page and its counts (`/api/query`, `/api/run`,
5
+ * `/api/view/run`, `/api/count`, `/api/counts`), a dashboard's breakdowns
6
+ * (`/api/breakdown`, `/api/breakdowns`) and an export (`/api/export`) —
7
+ * the Workbench grid and an App's lists, search and charts all arrive as
8
+ * these. A row a moment old is what anyone reading a list already accepts:
9
+ * it was a moment old by the time it was drawn.
10
+ *
11
+ * Everything else reads the primary, and so does a read of one row
12
+ * (`limit: 1`): that is a record's own read — the record page, the
13
+ * Workbench record, a section's probe — and a record is where a person
14
+ * looks for what they just saved. A composed record page is pinned whole
15
+ * (handler.ts), related lists and all. Commands, writes, the catalog,
16
+ * the stores, raw SQL and the MCP tools never ask for a replica.
17
+ */
18
+ import { createHash } from 'node:crypto';
19
+ import { FRESH_READ_MS } from '../../adapters/replicas.js';
20
+ import { product } from '../product.js';
21
+ const LAG_TOLERANT = new Set([
22
+ '/api/query',
23
+ '/api/run',
24
+ '/api/view/run',
25
+ '/api/count',
26
+ '/api/counts',
27
+ '/api/breakdown',
28
+ '/api/breakdowns',
29
+ '/api/export',
30
+ ]);
31
+ /** Whether the POST `path` with `body` may read from a replica. */
32
+ export function toleratesLag(path, body) {
33
+ if (!LAG_TOLERANT.has(path))
34
+ return false;
35
+ const view = body.view && typeof body.view === 'object' ? body.view : undefined;
36
+ return body.limit !== 1 && view?.limit !== 1;
37
+ }
38
+ /** The cookie a write sets so the same browser's next reads go to the primary, in the running product's name. */
39
+ export const freshCookie = () => `${product()}_fresh`;
40
+ /**
41
+ * The read-your-write context for one request (replicas.ts `readsAs`).
42
+ *
43
+ * A browser carries the marker: a write sets `<product>_fresh=<write time>` (`mistri_fresh`, or `tablewalk_fresh` in the browser)
44
+ * for FRESH_READ_MS on the App's base path, and a request that brings one
45
+ * back within that time reads the primary. It needs no shared state, so it
46
+ * holds whichever pod the next request reaches, and each visitor — signed
47
+ * in or not — has their own. It is HttpOnly and SameSite=Lax like the
48
+ * other cookies here, and never Secure-only: it holds a time, not a
49
+ * secret, and a forged or stolen one buys nothing but primary reads for
50
+ * ten seconds. A caller sending a bearer token has no cookie jar, so its
51
+ * writes are remembered in this process under a digest of the token.
52
+ */
53
+ export function readFreshness(request, response, base, now = Date.now) {
54
+ const bearer = /^Bearer\s+(\S+)/i.exec(request.headers.authorization ?? '')?.[1];
55
+ if (bearer)
56
+ return { fresh: false, key: `bearer:${createHash('sha256').update(bearer).digest('base64url').slice(0, 22)}` };
57
+ const at = now();
58
+ const fresh = cookieValues(request.headers.cookie, freshCookie()).some((value) => {
59
+ const wrote = /^\d{1,16}$/.test(value) ? Number(value) : NaN;
60
+ // A time ahead of this clock by more than a little is not one this server wrote.
61
+ return wrote <= at + 1_000 && at - wrote < FRESH_READ_MS;
62
+ });
63
+ return {
64
+ fresh,
65
+ onWrite: () => {
66
+ if (response.headersSent)
67
+ return;
68
+ const cookie = `${freshCookie()}=${now()}; Path=${base || '/'}; Max-Age=${FRESH_READ_MS / 1000}; HttpOnly; SameSite=Lax`;
69
+ const prior = response.getHeader('set-cookie');
70
+ response.setHeader('set-cookie', prior === undefined ? cookie : [...(Array.isArray(prior) ? prior : [String(prior)]), cookie]);
71
+ },
72
+ };
73
+ }
74
+ function cookieValues(header, name) {
75
+ return (header ?? '')
76
+ .split(';')
77
+ .map((part) => part.trim())
78
+ .filter((part) => part.startsWith(`${name}=`))
79
+ .map((part) => part.slice(name.length + 1));
80
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * A record page in one request (shared/recordReads.ts says why).
3
+ *
4
+ * `POST /api/pages/compose` takes what `/api/pages/plan` takes — the page,
5
+ * by name or as itself, and the record's key — with the reader's page size
6
+ * for related lists (`rows`) and the tab it opens on (`tab`). It plans the
7
+ * page, then asks every read the sections it draws will send: the record's
8
+ * row once for every section that reads it, each related list's first page
9
+ * and totals, each figure, each timeline and custom read, each `when`, the
10
+ * record's history and which of its commands are available. Each is asked
11
+ * of the route the section's own request reaches, on this request's source —
12
+ * one admission, one session, one row-policy context, the same grants, row
13
+ * scope and hidden columns — through `post`, which is the dispatcher's own,
14
+ * into a reply held in memory. What a signed-out visitor or a row policy may
15
+ * not ask on its own is not asked here either.
16
+ *
17
+ * The answer is the plan, as `/api/pages/plan` answers it, and beside it
18
+ * each read that succeeded with the request it answers. A read that failed
19
+ * is left out: the section asks it itself, and is refused in its own words.
20
+ */
21
+ import type { ServerResponse } from 'node:http';
22
+ import { type PageDef } from '../../shared/page.js';
23
+ import type { RequestContext, ResolvedSource } from './context.js';
24
+ export declare const COMPOSE_PATH = "/api/pages/compose";
25
+ /** The resources of the App a page is drawn in, as far as composing its reads needs them. */
26
+ export type ComposeResources = Record<string, {
27
+ recordLabel?: string | false;
28
+ defined?: Record<string, {
29
+ per?: string;
30
+ }>;
31
+ actions?: Array<{
32
+ when?: string;
33
+ command?: {
34
+ id: string;
35
+ version: number;
36
+ target: string;
37
+ };
38
+ }>;
39
+ }>;
40
+ /** One availability check of a record's command, as `/api/commands/availability` takes it. */
41
+ interface CommandCheck {
42
+ readonly command: string;
43
+ readonly commandVersion: number;
44
+ readonly keys: Record<string, unknown>[];
45
+ }
46
+ /** What a product decides of a composed page. The database browser asks every part, has no App, and runs no commands. */
47
+ export interface ComposeHooks {
48
+ /** Whether this request's reader may ask `path` on its own: the gate's and the row policy's rule for that route. */
49
+ mayAsk(ctx: RequestContext, path: string): boolean;
50
+ /** The App's resources as this reader is served them, or none. */
51
+ resources(ctx: RequestContext, source: ResolvedSource): ComposeResources;
52
+ /** A table's suggested page (`suggested:<table>`). */
53
+ suggested(source: ResolvedSource, table: string): PageDef | null;
54
+ /** Which of the record's commands are available to this reader: the availability route's answer, or none. */
55
+ availability?(ctx: RequestContext, checks: CommandCheck[]): Promise<{
56
+ status: number;
57
+ body: unknown;
58
+ } | undefined>;
59
+ }
60
+ export declare function composeRecordPage({ ctx, source, body, post, hooks, }: {
61
+ ctx: RequestContext;
62
+ source: ResolvedSource;
63
+ body: Record<string, unknown>;
64
+ post: (reply: ServerResponse, path: string, body: Record<string, unknown>) => Promise<void>;
65
+ hooks: ComposeHooks;
66
+ }): Promise<void>;
67
+ export {};