@jwilleke/ngdpbase-types 0.0.0 → 5.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +16 -2
  3. package/lib/packages/ngdpbase-types/index.d.ts +32 -0
  4. package/lib/packages/ngdpbase-types/testing.d.ts +43 -0
  5. package/lib/packages/ngdpbase-types/testing.js +53 -0
  6. package/lib/src/cache/CacheDependencies.d.ts +50 -0
  7. package/lib/src/cache/CacheDependencies.js +50 -0
  8. package/lib/src/cache/ICacheAdapter.d.ts +86 -0
  9. package/lib/src/cache/RegionCache.d.ts +171 -0
  10. package/lib/src/context/ActorContext.d.ts +48 -0
  11. package/lib/src/context/ActorContext.js +33 -0
  12. package/lib/src/context/ApiContext.d.ts +194 -0
  13. package/lib/src/context/ApiContext.js +273 -0
  14. package/lib/src/context/BaseContext.d.ts +110 -0
  15. package/lib/src/context/BaseContext.js +143 -0
  16. package/lib/src/context/JobContext.d.ts +153 -0
  17. package/lib/src/context/JobContext.js +144 -0
  18. package/lib/src/context/WikiContext.d.ts +404 -0
  19. package/lib/src/context/bootActions.d.ts +64 -0
  20. package/lib/src/context/bootActions.js +111 -0
  21. package/lib/src/converters/HtmlConverter.d.ts +70 -0
  22. package/lib/src/converters/IContentConverter.d.ts +94 -0
  23. package/lib/src/converters/JSPWikiConverter.d.ts +117 -0
  24. package/lib/src/converters/conversionWarning.d.ts +15 -0
  25. package/lib/src/converters/ncm/bridge.d.ts +22 -0
  26. package/lib/src/converters/ncm/existing.d.ts +23 -0
  27. package/lib/src/converters/ncm/fix/blocks.d.ts +89 -0
  28. package/lib/src/converters/ncm/fix/bulletMarkers.d.ts +21 -0
  29. package/lib/src/converters/ncm/fix/index.d.ts +36 -0
  30. package/lib/src/converters/ncm/fix/jspwikiBullets.d.ts +20 -0
  31. package/lib/src/converters/ncm/fix/jspwikiCodeMarkers.d.ts +38 -0
  32. package/lib/src/converters/ncm/fix/jspwikiHeadings.d.ts +25 -0
  33. package/lib/src/converters/ncm/fix/jspwikiIndent.d.ts +24 -0
  34. package/lib/src/converters/ncm/fix/jspwikiInsert.d.ts +21 -0
  35. package/lib/src/converters/ncm/fix/jspwikiItalic.d.ts +29 -0
  36. package/lib/src/converters/ncm/fix/jspwikiLinkLeftovers.d.ts +27 -0
  37. package/lib/src/converters/ncm/fix/moreInformationFooter.d.ts +25 -0
  38. package/lib/src/converters/ncm/fix/styleClosers.d.ts +25 -0
  39. package/lib/src/converters/ncm/fix/tightenLists.d.ts +30 -0
  40. package/lib/src/converters/ncm/fix/types.d.ts +33 -0
  41. package/lib/src/converters/ncm/footnotes.d.ts +39 -0
  42. package/lib/src/converters/ncm/images.d.ts +49 -0
  43. package/lib/src/converters/ncm/index.d.ts +20 -0
  44. package/lib/src/converters/ncm/links.d.ts +21 -0
  45. package/lib/src/converters/ncm/normalize.d.ts +39 -0
  46. package/lib/src/converters/ncm/placeholder.d.ts +25 -0
  47. package/lib/src/converters/ncm/tables.d.ts +36 -0
  48. package/lib/src/converters/ncm/types.d.ts +42 -0
  49. package/lib/src/http/egressPolicy.d.ts +52 -0
  50. package/lib/src/http/guardedFetch.d.ts +89 -0
  51. package/lib/src/http/guardedFetch.js +113 -0
  52. package/lib/src/http/guardedLookup.d.ts +48 -0
  53. package/lib/src/http/guardedLookup.js +73 -0
  54. package/lib/src/http/ssrf.d.ts +83 -0
  55. package/lib/src/http/ssrf.js +311 -0
  56. package/lib/src/mail/MailProvider.d.ts +36 -0
  57. package/lib/src/mail/NodemailerMailProvider.d.ts +26 -0
  58. package/lib/src/managers/AddonsManager.d.ts +691 -0
  59. package/lib/src/managers/AgentTokenManager.d.ts +269 -0
  60. package/lib/src/managers/AssetManager.d.ts +116 -0
  61. package/lib/src/managers/AttachmentManager.d.ts +1032 -0
  62. package/lib/src/managers/AuthManager.d.ts +1257 -0
  63. package/lib/src/managers/BackgroundJobManager.d.ts +434 -0
  64. package/lib/src/managers/BaseManager.d.ts +391 -0
  65. package/lib/src/managers/BaseManager.js +415 -0
  66. package/lib/src/managers/CacheManager.d.ts +159 -0
  67. package/lib/src/managers/CatalogManager.d.ts +235 -0
  68. package/lib/src/managers/CommentManager.d.ts +75 -0
  69. package/lib/src/managers/ConfigurationManager.d.ts +747 -0
  70. package/lib/src/managers/DatabaseManager.d.ts +89 -0
  71. package/lib/src/managers/DatabaseManager.js +236 -0
  72. package/lib/src/managers/EmailManager.d.ts +47 -0
  73. package/lib/src/managers/ExportManager.d.ts +129 -0
  74. package/lib/src/managers/ExportManager.js +420 -0
  75. package/lib/src/managers/FootnoteManager.d.ts +118 -0
  76. package/lib/src/managers/MediaManager.d.ts +279 -0
  77. package/lib/src/managers/MetricsManager.d.ts +89 -0
  78. package/lib/src/managers/NotificationManager.d.ts +165 -0
  79. package/lib/src/managers/OidcManager.d.ts +210 -0
  80. package/lib/src/managers/OrganizationManager.d.ts +107 -0
  81. package/lib/src/managers/PageManager.d.ts +1645 -0
  82. package/lib/src/managers/PersonManager.d.ts +48 -0
  83. package/lib/src/managers/PluginManager.d.ts +179 -0
  84. package/lib/src/managers/PluginManager.js +393 -0
  85. package/lib/src/managers/PolicyEvaluator.d.ts +213 -0
  86. package/lib/src/managers/RenderingManager.d.ts +358 -0
  87. package/lib/src/managers/RoleManager.d.ts +134 -0
  88. package/lib/src/managers/SearchManager.d.ts +402 -0
  89. package/lib/src/managers/ShareManager.d.ts +251 -0
  90. package/lib/src/managers/TemplateManager.d.ts +176 -0
  91. package/lib/src/managers/ThemeManager.d.ts +56 -0
  92. package/lib/src/managers/UserManager.d.ts +480 -0
  93. package/lib/src/managers/ValidationManager.d.ts +426 -0
  94. package/lib/src/managers/VariableManager.d.ts +145 -0
  95. package/lib/src/middleware/csrf.d.ts +3 -0
  96. package/lib/src/parsers/LinkParser.d.ts +457 -0
  97. package/lib/src/parsers/MarkupParser.d.ts +769 -0
  98. package/lib/src/parsers/context/ParseContext.d.ts +314 -0
  99. package/lib/src/parsers/data/emoji-map.d.ts +18 -0
  100. package/lib/src/parsers/dom/DOMBuilder.d.ts +210 -0
  101. package/lib/src/parsers/dom/DOMParser.d.ts +252 -0
  102. package/lib/src/parsers/dom/Tokenizer.d.ts +358 -0
  103. package/lib/src/parsers/dom/WikiDocument.d.ts +272 -0
  104. package/lib/src/parsers/dom/handlers/DOMLinkHandler.d.ts +260 -0
  105. package/lib/src/parsers/dom/handlers/DOMPluginHandler.d.ts +212 -0
  106. package/lib/src/parsers/dom/handlers/DOMVariableHandler.d.ts +171 -0
  107. package/lib/src/parsers/filters/BaseFilter.d.ts +269 -0
  108. package/lib/src/parsers/filters/FilterChain.d.ts +320 -0
  109. package/lib/src/parsers/handlers/BaseSyntaxHandler.d.ts +331 -0
  110. package/lib/src/parsers/handlers/HandlerRegistry.d.ts +225 -0
  111. package/lib/src/parsers/handlers/JSPWikiPreprocessor.d.ts +89 -0
  112. package/lib/src/parsers/handlers/LinkParserHandler.d.ts +80 -0
  113. package/lib/src/parsers/handlers/PluginSyntaxHandler.d.ts +78 -0
  114. package/lib/src/parsers/handlers/WikiFormHandler.d.ts +149 -0
  115. package/lib/src/parsers/handlers/WikiTagHandler.d.ts +125 -0
  116. package/lib/src/parsers/jspwikiTableRow.d.ts +39 -0
  117. package/lib/src/parsers/styleBlockSyntax.d.ts +14 -0
  118. package/lib/src/plugins/types.d.ts +79 -0
  119. package/lib/src/providers/AgentTokenAuthProvider.d.ts +40 -0
  120. package/lib/src/providers/AuthentikBearerAuthProvider.d.ts +75 -0
  121. package/lib/src/providers/BaseAttachmentProvider.d.ts +197 -0
  122. package/lib/src/providers/BaseAuthProvider.d.ts +220 -0
  123. package/lib/src/providers/BaseCacheProvider.d.ts +140 -0
  124. package/lib/src/providers/BaseCredentialsProvider.d.ts +84 -0
  125. package/lib/src/providers/BaseDatabaseProvider.d.ts +22 -0
  126. package/lib/src/providers/BaseDatabaseProvider.js +12 -0
  127. package/lib/src/providers/BaseLoggingProvider.d.ts +68 -0
  128. package/lib/src/providers/BaseLoggingProvider.js +37 -0
  129. package/lib/src/providers/BaseMediaProvider.d.ts +308 -0
  130. package/lib/src/providers/BasePageProvider.d.ts +337 -0
  131. package/lib/src/providers/BaseProvider.d.ts +98 -0
  132. package/lib/src/providers/BaseProvider.js +74 -0
  133. package/lib/src/providers/BaseSearchProvider.d.ts +362 -0
  134. package/lib/src/providers/BasicAttachmentProvider.d.ts +599 -0
  135. package/lib/src/providers/CloudflareAccessAuthProvider.d.ts +72 -0
  136. package/lib/src/providers/FileCredentialsProvider.d.ts +33 -0
  137. package/lib/src/providers/FileJobStateProvider.d.ts +58 -0
  138. package/lib/src/providers/FileLoggingProvider.d.ts +43 -0
  139. package/lib/src/providers/FileLoggingProvider.js +120 -0
  140. package/lib/src/providers/FileOidcAdapter.d.ts +25 -0
  141. package/lib/src/providers/FileSystemMediaProvider.d.ts +403 -0
  142. package/lib/src/providers/LunrSearchProvider.d.ts +280 -0
  143. package/lib/src/providers/MagicLinkAuthProvider.d.ts +125 -0
  144. package/lib/src/providers/NullCacheProvider.d.ts +72 -0
  145. package/lib/src/providers/OidcAuthProvider.d.ts +180 -0
  146. package/lib/src/providers/OidcBearerAuthProvider.d.ts +30 -0
  147. package/lib/src/providers/PasskeyAuthProvider.d.ts +58 -0
  148. package/lib/src/providers/PasswordAuthProvider.d.ts +20 -0
  149. package/lib/src/providers/SqliteDatabaseProvider.d.ts +55 -0
  150. package/lib/src/providers/SqliteDatabaseProvider.js +90 -0
  151. package/lib/src/providers/SqliteJobStateProvider.d.ts +41 -0
  152. package/lib/src/providers/databaseMigrations.d.ts +8 -0
  153. package/lib/src/providers/databaseMigrations.js +47 -0
  154. package/lib/src/providers/jobState.d.ts +99 -0
  155. package/lib/src/providers/lunrQueryToMiniSearch.d.ts +32 -0
  156. package/lib/src/providers/mediaFilenameDate.d.ts +22 -0
  157. package/lib/src/providers/sqliteLocation.d.ts +17 -0
  158. package/lib/src/providers/sqliteLocation.js +55 -0
  159. package/lib/src/providers/sqliteMigrations.d.ts +48 -0
  160. package/lib/src/providers/sqliteMigrations.js +72 -0
  161. package/lib/src/rendering/githubAlerts.d.ts +22 -0
  162. package/lib/src/rendering/htmlPolicy.d.ts +76 -0
  163. package/lib/src/rendering/markdownConverter.d.ts +73 -0
  164. package/lib/src/security/PolicyDecisionPoint.d.ts +245 -0
  165. package/lib/src/security/PolicyInformationPoint.d.ts +448 -0
  166. package/lib/src/security/pageActions.d.ts +40 -0
  167. package/lib/src/security/permissions.generated.d.ts +78 -0
  168. package/lib/src/types/Asset.d.ts +414 -0
  169. package/lib/src/types/Catalog.d.ts +61 -0
  170. package/lib/src/types/Comment.d.ts +11 -0
  171. package/lib/src/types/Config.d.ts +388 -0
  172. package/lib/src/types/Organization.d.ts +78 -0
  173. package/lib/src/types/OrganizationProvider.d.ts +38 -0
  174. package/lib/src/types/Page.d.ts +220 -0
  175. package/lib/src/types/Person.d.ts +56 -0
  176. package/lib/src/types/PersonProvider.d.ts +25 -0
  177. package/lib/src/types/Policy.d.ts +139 -0
  178. package/lib/src/types/Policy.js +17 -0
  179. package/lib/src/types/Provider.d.ts +810 -0
  180. package/lib/src/types/Role.d.ts +84 -0
  181. package/lib/src/types/RoleProvider.d.ts +35 -0
  182. package/lib/src/types/Schema.d.ts +425 -0
  183. package/lib/src/types/Share.d.ts +172 -0
  184. package/lib/src/types/Share.js +81 -0
  185. package/lib/src/types/User.d.ts +304 -0
  186. package/lib/src/types/Version.d.ts +189 -0
  187. package/lib/src/types/WikiEngine.d.ts +128 -0
  188. package/lib/src/types/express.d.ts +120 -0
  189. package/lib/src/types/express.js +1 -0
  190. package/lib/src/types/guards.d.ts +78 -0
  191. package/lib/src/types/heic-decode.d.ts +16 -0
  192. package/lib/src/types/index.d.ts +19 -0
  193. package/lib/src/types/linkedom.d.ts +77 -0
  194. package/lib/src/types/markdown-it-plugins.d.ts +21 -0
  195. package/lib/src/utils/DeltaStorage.d.ts +118 -0
  196. package/lib/src/utils/LocaleUtils.d.ts +105 -0
  197. package/lib/src/utils/LocaleUtils.js +294 -0
  198. package/lib/src/utils/PageNameMatcher.d.ts +98 -0
  199. package/lib/src/utils/PathPreflight.d.ts +38 -0
  200. package/lib/src/utils/PathPreflight.js +50 -0
  201. package/lib/src/utils/SectionUtils.d.ts +40 -0
  202. package/lib/src/utils/addonConfigLayer.d.ts +144 -0
  203. package/lib/src/utils/addonConfigLayer.js +382 -0
  204. package/lib/src/utils/addonDatabaseRules.d.ts +25 -0
  205. package/lib/src/utils/addonDatabaseRules.js +57 -0
  206. package/lib/src/utils/addonHost.d.ts +51 -0
  207. package/lib/src/utils/addonHost.js +72 -0
  208. package/lib/src/utils/addonInstaller.d.ts +109 -0
  209. package/lib/src/utils/addonLock.d.ts +37 -0
  210. package/lib/src/utils/addonLock.js +48 -0
  211. package/lib/src/utils/addonPageSync.d.ts +45 -0
  212. package/lib/src/utils/addonProvenance.d.ts +48 -0
  213. package/lib/src/utils/addonTarball.d.ts +41 -0
  214. package/lib/src/utils/addonsPathResolver.d.ts +76 -0
  215. package/lib/src/utils/addonsPathResolver.js +129 -0
  216. package/lib/src/utils/assetMetadataTags.d.ts +66 -0
  217. package/lib/src/utils/atomicWrite.d.ts +28 -0
  218. package/lib/src/utils/auditConfigChange.d.ts +57 -0
  219. package/lib/src/utils/auditEventNames.d.ts +50 -0
  220. package/lib/src/utils/auditEventNames.generated.d.ts +163 -0
  221. package/lib/src/utils/auditEventNames.generated.js +168 -0
  222. package/lib/src/utils/auditEventNames.js +49 -0
  223. package/lib/src/utils/auditEvents.d.ts +265 -0
  224. package/lib/src/utils/auditEvents.js +309 -0
  225. package/lib/src/utils/auditRegistry.d.ts +102 -0
  226. package/lib/src/utils/auditRegistry.js +168 -0
  227. package/lib/src/utils/bip39English.d.ts +2 -0
  228. package/lib/src/utils/configEnvKeys.d.ts +68 -0
  229. package/lib/src/utils/configFiles.d.ts +74 -0
  230. package/lib/src/utils/configFiles.js +150 -0
  231. package/lib/src/utils/delegation.d.ts +48 -0
  232. package/lib/src/utils/deriveUsername.d.ts +21 -0
  233. package/lib/src/utils/explainMediaPath.d.ts +123 -0
  234. package/lib/src/utils/formerTitles.d.ts +69 -0
  235. package/lib/src/utils/frontmatterAccess.d.ts +54 -0
  236. package/lib/src/utils/headlessAdminPassword.d.ts +55 -0
  237. package/lib/src/utils/imageTransform.d.ts +52 -0
  238. package/lib/src/utils/instanceEnvSecret.d.ts +51 -0
  239. package/lib/src/utils/jobSlots.d.ts +43 -0
  240. package/lib/src/utils/keywordNormalizer.d.ts +127 -0
  241. package/lib/src/utils/logger.d.ts +70 -0
  242. package/lib/src/utils/logger.js +106 -0
  243. package/lib/src/utils/magicLinkDeviceState.d.ts +95 -0
  244. package/lib/src/utils/managerUtils.d.ts +40 -0
  245. package/lib/src/utils/migrateLegacyPrivateAttachments.d.ts +15 -0
  246. package/lib/src/utils/orgFilename.d.ts +22 -0
  247. package/lib/src/utils/pageFeature.d.ts +27 -0
  248. package/lib/src/utils/pageFrontmatter.d.ts +21 -0
  249. package/lib/src/utils/pageNotes.d.ts +150 -0
  250. package/lib/src/utils/pageTitleRule.d.ts +37 -0
  251. package/lib/src/utils/pageToArticle.d.ts +59 -0
  252. package/lib/src/utils/pageUrl.d.ts +18 -0
  253. package/lib/src/utils/passwordChange.d.ts +12 -0
  254. package/lib/src/utils/passwordHash.d.ts +60 -0
  255. package/lib/src/utils/permissionCatalog.d.ts +52 -0
  256. package/lib/src/utils/pluginFormatters.d.ts +452 -0
  257. package/lib/src/utils/pluginFormatters.js +714 -0
  258. package/lib/src/utils/privateLinkRewrite.d.ts +42 -0
  259. package/lib/src/utils/privateStoreAccess.d.ts +57 -0
  260. package/lib/src/utils/privateStoreAccess.js +65 -0
  261. package/lib/src/utils/privateStoreCatalogs.d.ts +40 -0
  262. package/lib/src/utils/privateStoreCrypto.d.ts +127 -0
  263. package/lib/src/utils/privateStoreDoor.d.ts +181 -0
  264. package/lib/src/utils/privateStoreExport.d.ts +72 -0
  265. package/lib/src/utils/privateStoreFiles.d.ts +120 -0
  266. package/lib/src/utils/privateStoreMeta.d.ts +64 -0
  267. package/lib/src/utils/privateStoreMigrations.d.ts +37 -0
  268. package/lib/src/utils/privateStorePath.d.ts +259 -0
  269. package/lib/src/utils/privateStorePath.js +436 -0
  270. package/lib/src/utils/privateStoreTakeout.d.ts +76 -0
  271. package/lib/src/utils/privateStoreUnlock.d.ts +175 -0
  272. package/lib/src/utils/proxyClaim.d.ts +59 -0
  273. package/lib/src/utils/proxyClaim.js +30 -0
  274. package/lib/src/utils/redactPrivateNames.d.ts +21 -0
  275. package/lib/src/utils/redactPrivateNames.js +89 -0
  276. package/lib/src/utils/redactSecrets.d.ts +58 -0
  277. package/lib/src/utils/redactSecrets.js +171 -0
  278. package/lib/src/utils/renameLinkRewrite.d.ts +112 -0
  279. package/lib/src/utils/roleGrants.d.ts +35 -0
  280. package/lib/src/utils/safeRedirect.d.ts +32 -0
  281. package/lib/src/utils/schedule.d.ts +54 -0
  282. package/lib/src/utils/secretFileMode.d.ts +17 -0
  283. package/lib/src/utils/seededShippedPages.d.ts +45 -0
  284. package/lib/src/utils/sensitiveValues.d.ts +59 -0
  285. package/lib/src/utils/sensitiveValues.js +106 -0
  286. package/lib/src/utils/sessionEnd.d.ts +12 -0
  287. package/lib/src/utils/sessionGeneration.d.ts +24 -0
  288. package/lib/src/utils/sessionIdle.d.ts +41 -0
  289. package/lib/src/utils/sessionLimits.d.ts +68 -0
  290. package/lib/src/utils/shareLockbox.d.ts +64 -0
  291. package/lib/src/utils/sigstoreTrustedRoot.d.ts +33 -0
  292. package/lib/src/utils/sniffMime.d.ts +21 -0
  293. package/lib/src/utils/storeSearchIndex.d.ts +75 -0
  294. package/lib/src/utils/subjectMayDo.d.ts +21 -0
  295. package/lib/src/utils/systemCategoryRules.d.ts +30 -0
  296. package/lib/src/utils/systemCategoryRules.js +41 -0
  297. package/lib/src/utils/userCreateError.d.ts +62 -0
  298. package/lib/src/utils/username.d.ts +53 -0
  299. package/lib/src/utils/vaultUrlRewrite.d.ts +27 -0
  300. package/lib/src/utils/version.d.ts +84 -0
  301. package/lib/src/utils/videoFrame.d.ts +21 -0
  302. package/package.json +54 -3
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Rewrite `[Old Title]` link targets to a page's new title (#1094).
3
+ *
4
+ * When a page is renamed, every `[Old Title]` in every other page stops
5
+ * resolving. #1082 answered that with an in-memory former-title map consulted
6
+ * after live resolution fails. That map has no durable backing — a restart
7
+ * forgets every rename — so it works right up until it silently stops.
8
+ *
9
+ * Rewriting the content instead makes the referring pages *correct*, rather
10
+ * than correct-looking because a lookup happens to still be warm.
11
+ *
12
+ * ## What this module is, and is not
13
+ *
14
+ * This is the text half only: pure, synchronous, no engine, no I/O. Given
15
+ * content and a rename it returns new content and a report. Deciding which
16
+ * pages to feed it, bounding the pass, writing the results and surviving a
17
+ * lost race are the caller's job — see `WikiRoutes.rewriteInboundLinksAfterRename`.
18
+ *
19
+ * The split is deliberate: the matching rules below are where the subtle bugs
20
+ * live, and they are worth testing without a server.
21
+ *
22
+ * ## Matching rules
23
+ *
24
+ * The link syntax is the parser's own (`WIKI_LINK_PATTERN_SOURCE`), imported
25
+ * rather than copied so the two cannot drift. It admits three forms:
26
+ *
27
+ * | Form | Target | Also the display text? |
28
+ * |----------------------------|--------------|------------------------|
29
+ * | `[Title]` | `Title` | yes |
30
+ * | `[Display\|Title]` | `Title` | no |
31
+ * | `[Display\|Title\|attrs]` | `Title` | no |
32
+ *
33
+ * A target may carry a fragment — `Title#slug` or `Title#section=Heading Name`
34
+ * — which is preserved verbatim; only the part before the first `#` is
35
+ * compared and replaced.
36
+ *
37
+ * __Case sensitivity differs by form, on purpose.__ In `[Display|Title]` the
38
+ * target is invisible to the reader, so a case variant is rewritten: nothing a
39
+ * human wrote changes. In `[Title]` the target *is* the display text, so only
40
+ * a byte-exact match is rewritten — silently recasing an author's prose to
41
+ * match a title is an edit they did not ask for.
42
+ *
43
+ * __Non-page targets are left alone__ by the same tests the parser uses to
44
+ * classify them: external URLs, `mailto:`, bare `#fragment`, absolute paths,
45
+ * and `Site:path` InterWiki references.
46
+ *
47
+ * __Markdown links are not touched.__ `[text](Target)` is excluded by the
48
+ * pattern's trailing `(?!\()`. The link graph does record them as edges, so a
49
+ * page linking that way can appear in the referrer set and come back with zero
50
+ * rewrites; that shows up in `unchangedTargets` rather than being silently
51
+ * counted as done.
52
+ *
53
+ * ## What it deliberately does not catch
54
+ *
55
+ * A link whose text only *fuzzy*-matches the old title — `[Old Titles]`
56
+ * resolving to `Old Title` through `PageNameMatcher` — is not rewritten. The
57
+ * link graph stores the *resolved* name, so such a page is in the referrer set
58
+ * and will come back unchanged. That is reported, not repaired: turning
59
+ * `[Old Titles]` into `[New Title]` rewrites the author's wording, and those
60
+ * links keep resolving through the #1082 map for as long as it exists.
61
+ */
62
+ /** Outcome of rewriting one page's content. */
63
+ export interface LinkRewriteResult {
64
+ /** The content, rewritten. Identical to the input when `rewritten` is 0. */
65
+ content: string;
66
+ /** How many link targets were replaced. */
67
+ rewritten: number;
68
+ /**
69
+ * Internal page targets seen and left as they were, de-duplicated and in
70
+ * first-seen order. The caller logs these for a referrer that yielded no
71
+ * rewrites: it is the visible trace of a fuzzy variant, a markdown-syntax
72
+ * link, or a link-graph edge that no longer reflects the content.
73
+ */
74
+ unchangedTargets: string[];
75
+ }
76
+ /**
77
+ * What a caller decides about one link target it was shown.
78
+ *
79
+ * @param base - The target as written, without any `#fragment`.
80
+ * @param targetIsDisplayText - True for `[Title]`, where the target IS the
81
+ * text the reader sees, and false for the piped forms, where it is not.
82
+ * The rewriting rule differs by form — see the module comment.
83
+ * @returns The target to write instead, or `null` to leave the link alone.
84
+ * The fragment is re-attached by the caller; a resolver never sees one.
85
+ */
86
+ export type LinkTargetResolver = (base: string, targetIsDisplayText: boolean) => string | null;
87
+ /**
88
+ * Rewrite link targets by the caller's rule — the matcher, once.
89
+ *
90
+ * The rename rewrite below and the private-link migration (#1457) decide
91
+ * different things about a target and agree on everything else: which
92
+ * bracket forms are links at all, that a task-list checkbox is not one, that
93
+ * external, mail, anchor, absolute and InterWiki targets are left alone, and
94
+ * that a `#fragment` survives. A second pass with its own regex would be a
95
+ * second place for those to drift, so both come through here.
96
+ *
97
+ * @param content - The page's markdown.
98
+ * @param resolve - What to do with each internal target seen.
99
+ * @returns The rewritten content and a report.
100
+ */
101
+ export declare function rewriteLinkTargetsBy(content: string, resolve: LinkTargetResolver): LinkRewriteResult;
102
+ /**
103
+ * Rewrite links pointing at `oldTitle` so they point at `newTitle`.
104
+ *
105
+ * @param content - The referring page's markdown.
106
+ * @param oldTitle - The title the page was renamed away from.
107
+ * @param newTitle - The title it now has.
108
+ * @returns The rewritten content and a report. Returns the input unchanged
109
+ * (and `rewritten: 0`) when there is nothing to do, including when either
110
+ * title is blank or the two are equal.
111
+ */
112
+ export declare function rewriteLinkTargets(content: string, oldTitle: string, newTitle: string): LinkRewriteResult;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * What each role is granted, read from the access policies (#1521).
3
+ *
4
+ * For the admin user forms: beside each role, the permissions its policies
5
+ * grant, so an admin can see that `contributor` already carries everything
6
+ * `reader` does under the shipped policies. Read from the merged policies —
7
+ * core, add-ons and the instance's own — so it shows what this site grants.
8
+ *
9
+ * Display only. Roles are independent in the code; whether a request is
10
+ * allowed is still decided by the evaluator, policy by policy and resource by
11
+ * resource. A grant that applies only to some resources (a policy naming
12
+ * particular pages or system-categories) is marked `limited`.
13
+ */
14
+ import type { Policy } from '../types/Policy.js';
15
+ export interface RoleGrant {
16
+ action: string;
17
+ /** True when every policy granting it applies to some resources only. */
18
+ limited: boolean;
19
+ /** For a limited grant, the resource types it is limited to — `vault` reads "in your own vaults" (#1539). */
20
+ where: string[];
21
+ }
22
+ export interface RoleGrants {
23
+ allows: RoleGrant[];
24
+ /** Actions a deny policy names for this role. */
25
+ denies: string[];
26
+ }
27
+ /**
28
+ * Every role a policy names, with what its policies allow and deny — the one
29
+ * reading of "what a role grants" (#1539): the user forms, the profile, the
30
+ * admin roles page and `PolicyDecisionPoint.rolePermissions` all come from
31
+ * here. Policies are applied lowest priority first, so a deny takes away what
32
+ * a lower-priority allow gave and an allow above it gives it back — the order
33
+ * the evaluator's first-match-by-priority decides in.
34
+ */
35
+ export declare function roleGrants(policies: readonly Policy[]): Record<string, RoleGrants>;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * safeRedirect — constrain a request-supplied redirect target to this site (#1041).
3
+ *
4
+ * `POST /login` passed `req.body.redirect` straight to `res.redirect`, so the
5
+ * login endpoint sent the browser anywhere the request named:
6
+ *
7
+ * redirect=//example.com/ → HTTP/1.1 302 Location: //example.com/
8
+ *
9
+ * That is the worst place in the application to have an open redirect. The
10
+ * victim authenticates against the real site, sees a genuine successful login,
11
+ * and is then handed to an attacker-controlled page — a clone asking them to
12
+ * "sign in again" is very convincing at that point.
13
+ *
14
+ * The rule is deliberately a strict allow-list rather than a blocklist of bad
15
+ * prefixes: a single leading slash, and nothing that could be read as a host or
16
+ * a scheme. Blocklists here fail to the open case, which is the wrong direction
17
+ * for a redirect sink.
18
+ */
19
+ /**
20
+ * Return `target` when it is a same-site path, otherwise `/`.
21
+ *
22
+ * Accepts: `/`, `/view/Welcome`, `/search?q=x#frag`
23
+ *
24
+ * Rejects, among others:
25
+ * - `//evil.example` — protocol-relative; the browser reads it as a host
26
+ * - `https://evil.example`, `javascript:…`, `data:…` — any scheme
27
+ * - `/\evil.example` — browsers normalise the backslash to `/`
28
+ * - `\\evil.example`, or anything not starting with `/`
29
+ * - a CR/LF, which would let a caller inject a second header
30
+ */
31
+ export declare function safeRedirect(target: unknown): string;
32
+ export default safeRedirect;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The schedule engine for scheduled jobs (#1713, epic #1611).
3
+ *
4
+ * A schedule is an iCalendar recurrence rule (RFC 5545 RRULE), the format the
5
+ * calendar add-on already stores, with a start (`dtstart`) and a time zone.
6
+ * Cron is not used: it cannot say "every 30 days" or "the last business day".
7
+ * Named shorthands (`daily 06:00`, `end-of-month`, …) expand to an RRULE.
8
+ *
9
+ * Recurrence is computed on wall-clock time and then placed in the time zone,
10
+ * so daylight saving does what a person expects:
11
+ * - spring forward: a slot inside the skipped hour runs at the next valid
12
+ * instant (02:30 becomes 03:30), rather than not at all;
13
+ * - fall back: a slot inside the repeated hour runs once, at its first
14
+ * occurrence.
15
+ * A date that does not exist is skipped, as RFC 5545 says: `BYMONTHDAY=31`
16
+ * skips short months; the last day of a month is `BYMONTHDAY=-1`. RFC 7529
17
+ * (RSCALE / SKIP) is not used (operator, 2026-10-08).
18
+ *
19
+ * Pure: no configuration is read here. The caller passes the default time zone
20
+ * (`ngdpbase.default.timezone`) and the minimum interval.
21
+ *
22
+ * @module utils/schedule
23
+ */
24
+ /** What a job declares. A string is a shorthand or a bare RRULE (`FREQ=…`). */
25
+ export type ScheduleInput = string | {
26
+ rrule: string;
27
+ dtstart?: string;
28
+ tz?: string;
29
+ };
30
+ export interface ScheduleOptions {
31
+ /** IANA time zone used when the schedule names none. */
32
+ defaultTimeZone: string;
33
+ /** Slots closer together than this are refused. Default 60 000 ms. */
34
+ minIntervalMs?: number;
35
+ }
36
+ export interface Schedule {
37
+ /** The RRULE that was compiled (after shorthand expansion). */
38
+ rrule: string;
39
+ /** The wall-clock start the recurrence is counted from, e.g. `2000-01-01T00:00:00`. */
40
+ dtstart: string;
41
+ timeZone: string;
42
+ /** The first slot strictly after `after`, or null when the rule has ended. */
43
+ nextSlot(after: Date): Date | null;
44
+ /** Every slot in `[from, to]`, oldest first. */
45
+ slotsBetween(from: Date, to: Date): Date[];
46
+ }
47
+ /** A shorthand's RRULE, a bare RRULE as given, or an error naming what was not understood. */
48
+ export declare function expandShorthand(text: string): string;
49
+ /**
50
+ * Compile a schedule. Throws, with a message a job author can act on, for an
51
+ * unknown shorthand, an invalid rule, an unknown time zone, `FREQ=SECONDLY`,
52
+ * an `RSCALE` other than GREGORIAN, or slots closer than the minimum interval.
53
+ */
54
+ export declare function parseSchedule(input: ScheduleInput, options: ScheduleOptions): Schedule;
@@ -0,0 +1,17 @@
1
+ export declare const SECRET_FILE_MODE = 384;
2
+ export declare const SECRET_DIR_MODE = 448;
3
+ /**
4
+ * Check an existing secret file at boot. Missing is fine (it is created
5
+ * owner-only on first write). Returns a line to log when it was tightened.
6
+ * Throws, naming both UIDs, when another account owns it.
7
+ */
8
+ export declare function secureExistingSecretFile(file: string): string | null;
9
+ /**
10
+ * Make a directory holding secrets owner-only, creating it when absent.
11
+ * Best effort on a filesystem that does not honour modes (an SMB share):
12
+ * returns a warning instead of failing, since refusing to write a backup
13
+ * over it would be worse than writing it with the share's permissions.
14
+ */
15
+ export declare function ensureSecretDir(dir: string): string | null;
16
+ /** After writing a secret file directly (not through writeFileAtomic's mode), make it owner-only. */
17
+ export declare function chmodSecretFile(file: string): string | null;
@@ -0,0 +1,45 @@
1
+ export declare const SEEDED_SHIPPED_PAGES_FILE = "seeded-shipped-pages.json";
2
+ /** Why a site declined a shipped page, and who decided. */
3
+ export interface DeclinedShippedPage {
4
+ /** When it was declined (ISO 8601) */
5
+ at: string;
6
+ /** Who declined it */
7
+ by: string;
8
+ /** The conflict that prompted it */
9
+ reason: string;
10
+ }
11
+ export declare class SeededShippedPages {
12
+ private readonly filePath;
13
+ private readonly data;
14
+ private constructor();
15
+ /**
16
+ * Load the record from the instance data folder. A missing file is an empty
17
+ * record; an unreadable one is an error, so the seeder cannot mistake a broken
18
+ * record for a site that has seeded nothing.
19
+ */
20
+ static load(instanceDataFolder: string): Promise<SeededShippedPages>;
21
+ /** Whether this site has a record for the source at all. */
22
+ hasSource(sourceId: string): boolean;
23
+ /** Whether the uuid was ever seeded from the source on this site. */
24
+ has(sourceId: string, uuid: string): boolean;
25
+ /** Whether the uuid was ever seeded from any source on this site. */
26
+ hasUuid(uuid: string): boolean;
27
+ /** Record a uuid as seeded from the source. Returns true when it was not recorded before. */
28
+ add(sourceId: string, uuid: string, at?: string): boolean;
29
+ /** Whether this site declined the uuid from that source (#1412). */
30
+ isDeclined(sourceId: string, uuid: string): boolean;
31
+ /** Why this site declined the uuid, or undefined. */
32
+ declinedEntry(sourceId: string, uuid: string): DeclinedShippedPage | undefined;
33
+ /** Every declined uuid of a source, as uuid → entry. */
34
+ declinedOf(sourceId: string): Record<string, DeclinedShippedPage>;
35
+ /** Every source that has declines, as source id → uuid → entry. */
36
+ allDeclined(): Record<string, Record<string, DeclinedShippedPage>>;
37
+ /** Decline a uuid from a source. Returns true when it was not declined before. */
38
+ decline(sourceId: string, uuid: string, entry: DeclinedShippedPage): boolean;
39
+ /** Undo a decline. Returns true when there was one. */
40
+ allow(sourceId: string, uuid: string): boolean;
41
+ /** Start an empty record for the source, so `hasSource` is true from now on. */
42
+ startSource(sourceId: string): void;
43
+ save(): Promise<void>;
44
+ private source;
45
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Which configuration values may be shown, and to whom (#1750).
3
+ *
4
+ * One declaration, `ngdpbase.config.sensitive-values` (renamed from
5
+ * `ngdpbase.config.secret-keys`, still read as an alias), maps a key to a level:
6
+ *
7
+ * - `secret` — never shown except to a holder of `secret-reveal` (which
8
+ * asks for a fresh sign-in), never written to the audit log
9
+ * or a log line;
10
+ * - `sensitive` — shown only to a holder of `admin-read`: how the instance is
11
+ * run (the access policies, storage paths, outside services).
12
+ *
13
+ * A key that isn't listed but whose name looks like a secret is treated as
14
+ * `secret` — a backstop, so a forgotten entry fails closed. The same backstop
15
+ * hides secret-looking fields nested inside an object value (an OIDC client's
16
+ * `client_secret` inside `oidc-auth-server.clients`).
17
+ *
18
+ * Hidden values are replaced on the server, before any HTML is built: they
19
+ * never reach a page, its source or the parse cache.
20
+ *
21
+ * @module utils/sensitiveValues
22
+ */
23
+ export declare const SENSITIVE_VALUES_KEY = "ngdpbase.config.sensitive-values";
24
+ /** The list's name before #1750; still read, with a boot warning to rename it. */
25
+ export declare const LEGACY_SECRET_KEYS_KEY = "ngdpbase.config.secret-keys";
26
+ export type ValueLevel = 'secret' | 'sensitive';
27
+ /** What a viewer may see: sensitive values (`admin-read`), secret values (`secret-reveal`). */
28
+ export interface ValueViewer {
29
+ sensitive: boolean;
30
+ secret: boolean;
31
+ }
32
+ /** Whether a key or field name looks like a secret (the backstop's test; also `npm run lint:sensitive`). */
33
+ export declare function looksSecret(name: string): boolean;
34
+ /** What a hidden value is shown as. */
35
+ export declare const HIDDEN = "(hidden)";
36
+ type Read = (key: string, fallback: unknown) => unknown;
37
+ /**
38
+ * The declared levels: the legacy list's keys as `secret`, then the new map
39
+ * (`"secret"`, `"sensitive"`, `true` = secret; `false` / `null` removes an
40
+ * entry, so an instance can override a shipped one).
41
+ */
42
+ export declare function valueLevels(read: Read): Map<string, ValueLevel>;
43
+ /** The keys declared `secret`: what logs, the audit log and the admin screen never print. */
44
+ export declare function secretKeys(read: Read): string[];
45
+ /**
46
+ * A value's level: as declared, else `secret` when the key's name looks like
47
+ * one and the value is a string. A boolean or number can't be a secret, so
48
+ * `ngdpbase.auth.password.enabled` stays visible; only a declared entry hides
49
+ * whatever its type.
50
+ */
51
+ export declare function levelOf(key: string, levels: Map<string, ValueLevel>, value?: unknown): ValueLevel | null;
52
+ /** Whether the legacy list is still set (to warn at boot). */
53
+ export declare function usesLegacyName(read: Read): boolean;
54
+ /**
55
+ * The value a viewer may see for a key: itself, or `HIDDEN`. An empty value
56
+ * is shown as it is — "not set" reveals nothing.
57
+ */
58
+ export declare function shownValue(key: string, value: unknown, levels: Map<string, ValueLevel>, viewer: ValueViewer): unknown;
59
+ export {};
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Which configuration values may be shown, and to whom (#1750).
3
+ *
4
+ * One declaration, `ngdpbase.config.sensitive-values` (renamed from
5
+ * `ngdpbase.config.secret-keys`, still read as an alias), maps a key to a level:
6
+ *
7
+ * - `secret` — never shown except to a holder of `secret-reveal` (which
8
+ * asks for a fresh sign-in), never written to the audit log
9
+ * or a log line;
10
+ * - `sensitive` — shown only to a holder of `admin-read`: how the instance is
11
+ * run (the access policies, storage paths, outside services).
12
+ *
13
+ * A key that isn't listed but whose name looks like a secret is treated as
14
+ * `secret` — a backstop, so a forgotten entry fails closed. The same backstop
15
+ * hides secret-looking fields nested inside an object value (an OIDC client's
16
+ * `client_secret` inside `oidc-auth-server.clients`).
17
+ *
18
+ * Hidden values are replaced on the server, before any HTML is built: they
19
+ * never reach a page, its source or the parse cache.
20
+ *
21
+ * @module utils/sensitiveValues
22
+ */
23
+ import { enabledEntries } from './configFiles.js';
24
+ export const SENSITIVE_VALUES_KEY = 'ngdpbase.config.sensitive-values';
25
+ /** The list's name before #1750; still read, with a boot warning to rename it. */
26
+ export const LEGACY_SECRET_KEYS_KEY = 'ngdpbase.config.secret-keys';
27
+ /** Names that look like a secret, for keys and for fields inside object values. */
28
+ const SECRET_NAME_PATTERN = /secret|passw(or)?d|token|credential|api[-_]?key|private[-_]?key/i;
29
+ /** Whether a key or field name looks like a secret (the backstop's test; also `npm run lint:sensitive`). */
30
+ export function looksSecret(name) {
31
+ return SECRET_NAME_PATTERN.test(name);
32
+ }
33
+ /** What a hidden value is shown as. */
34
+ export const HIDDEN = '(hidden)';
35
+ /**
36
+ * The declared levels: the legacy list's keys as `secret`, then the new map
37
+ * (`"secret"`, `"sensitive"`, `true` = secret; `false` / `null` removes an
38
+ * entry, so an instance can override a shipped one).
39
+ */
40
+ export function valueLevels(read) {
41
+ const levels = new Map();
42
+ for (const key of enabledEntries(read(LEGACY_SECRET_KEYS_KEY, {})))
43
+ levels.set(key, 'secret');
44
+ const declared = read(SENSITIVE_VALUES_KEY, {});
45
+ if (declared && typeof declared === 'object' && !Array.isArray(declared)) {
46
+ for (const [key, level] of Object.entries(declared)) {
47
+ if (level === 'secret' || level === true)
48
+ levels.set(key, 'secret');
49
+ else if (level === 'sensitive')
50
+ levels.set(key, 'sensitive');
51
+ else
52
+ levels.delete(key);
53
+ }
54
+ }
55
+ else {
56
+ for (const key of enabledEntries(declared))
57
+ levels.set(key, 'secret');
58
+ }
59
+ return levels;
60
+ }
61
+ /** The keys declared `secret`: what logs, the audit log and the admin screen never print. */
62
+ export function secretKeys(read) {
63
+ return [...valueLevels(read)].filter(([, level]) => level === 'secret').map(([key]) => key);
64
+ }
65
+ /**
66
+ * A value's level: as declared, else `secret` when the key's name looks like
67
+ * one and the value is a string. A boolean or number can't be a secret, so
68
+ * `ngdpbase.auth.password.enabled` stays visible; only a declared entry hides
69
+ * whatever its type.
70
+ */
71
+ export function levelOf(key, levels, value) {
72
+ const declared = levels.get(key);
73
+ if (declared)
74
+ return declared;
75
+ return looksSecret(key) && typeof value === 'string' ? 'secret' : null;
76
+ }
77
+ /** Whether the legacy list is still set (to warn at boot). */
78
+ export function usesLegacyName(read) {
79
+ return enabledEntries(read(LEGACY_SECRET_KEYS_KEY, {})).length > 0;
80
+ }
81
+ /** Secret-looking fields inside an object value, hidden; the rest kept. */
82
+ function hideNestedSecrets(value) {
83
+ if (Array.isArray(value))
84
+ return value.map(hideNestedSecrets);
85
+ if (value && typeof value === 'object') {
86
+ const out = {};
87
+ for (const [k, v] of Object.entries(value)) {
88
+ out[k] = looksSecret(k) && typeof v === 'string' && v !== '' ? HIDDEN : hideNestedSecrets(v);
89
+ }
90
+ return out;
91
+ }
92
+ return value;
93
+ }
94
+ /**
95
+ * The value a viewer may see for a key: itself, or `HIDDEN`. An empty value
96
+ * is shown as it is — "not set" reveals nothing.
97
+ */
98
+ export function shownValue(key, value, levels, viewer) {
99
+ const empty = value === undefined || value === null || value === '';
100
+ const level = levelOf(key, levels, value);
101
+ if (level === 'secret' && !viewer.secret)
102
+ return empty ? value : HIDDEN;
103
+ if (level === 'sensitive' && !viewer.sensitive)
104
+ return empty ? value : HIDDEN;
105
+ return viewer.secret ? value : hideNestedSecrets(value);
106
+ }
@@ -0,0 +1,12 @@
1
+ export type SessionEndReason = 'logout' | 'idle-timeout' | 'max-age' | 'password-changed' | 'superseded';
2
+ export declare function endSession(engine: {
3
+ getManager(name: string): unknown;
4
+ }, session: {
5
+ username?: unknown;
6
+ privateStoreHandle?: unknown;
7
+ pendingConnection?: unknown;
8
+ actingFor?: unknown;
9
+ } | null | undefined, reason: SessionEndReason, from: {
10
+ ipAddress?: string;
11
+ userAgent?: string;
12
+ }): void;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Password-change session generation (#1482).
3
+ *
4
+ * A user record carries `sessionGeneration`, a counter raised whenever the
5
+ * account's password changes — by the owner, an administrator, the recovery
6
+ * words (#1452) or the offline reset script. A session is stamped with the
7
+ * counter when it signs in; a request whose session carries an older value is
8
+ * signed out. That ends every other session of the account without finding
9
+ * sessions on disk, at the cost of one comparison per request.
10
+ *
11
+ * An account that has never changed its password is at 0, and a session
12
+ * signed in before this existed carries nothing, which reads as 0: existing
13
+ * sessions stay signed in until the first password change.
14
+ */
15
+ interface HasGeneration {
16
+ sessionGeneration?: number;
17
+ }
18
+ /** The account's current generation; 0 when it has never been raised. */
19
+ export declare function sessionGenerationOf(user: HasGeneration | null | undefined): number;
20
+ /** Raise the account's generation, in place, and return the new value. */
21
+ export declare function bumpSessionGeneration(user: HasGeneration): number;
22
+ /** Whether a session stamped with `stamped` still belongs to the account as it is now. */
23
+ export declare function sessionIsCurrent(stamped: unknown, user: HasGeneration | null | undefined): boolean;
24
+ export {};
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Session idle timeout (#1546).
3
+ *
4
+ * `ngdpbase.session.idle-timeout-minutes` ends a signed-in session after that
5
+ * many minutes with no request. Shipped at 10080 (7 days, #1767); `0` is off.
6
+ * It is separate from `ngdpbase.session.max-age`, the absolute cap from
7
+ * sign-in (`sessionLimits.ts`); a value at or above that cap has no effect.
8
+ *
9
+ * Enforced server-side on the next request — never only by a browser timer,
10
+ * which a closed laptop or a copied cookie would not run.
11
+ *
12
+ * Writing the last-activity time on every request would save the session on
13
+ * every request, which the file store pays for, so it is written at most once
14
+ * per `touchEveryMs`: a session may then end up to that much later than the
15
+ * exact limit, never earlier.
16
+ */
17
+ /** The configured limit in milliseconds; 0 when off or not a positive number. */
18
+ export declare function idleTimeoutMs(minutes: unknown): number;
19
+ /** How stale the recorded activity may get before it is written again. */
20
+ export declare function touchEveryMs(timeoutMs: number): number;
21
+ /**
22
+ * Whether a session last active at `lastActivity` (epoch ms) has been idle
23
+ * past the limit. A session with no recorded activity — one signed in before
24
+ * the limit was set — is not expired; it starts counting now.
25
+ */
26
+ export declare function idleExpired(lastActivity: unknown, now: number, timeoutMs: number): boolean;
27
+ /** Whether the recorded activity should be written on this request. */
28
+ export declare function shouldTouch(lastActivity: unknown, now: number, timeoutMs: number): boolean;
29
+ /**
30
+ * The limit that applies to one person (#1546): the shortest positive value
31
+ * among the site setting and their roles' `idle-timeout-minutes`. A role can
32
+ * only shorten the site value, never lengthen it; 0 or absent means "no limit
33
+ * from here", so with nothing set anywhere the timeout stays off.
34
+ */
35
+ export declare function effectiveIdleTimeoutMs(siteMinutes: unknown, roleMinutes?: readonly unknown[]): number;
36
+ /** How long before sign-out the page warns: two minutes, or a quarter of a shorter limit. */
37
+ export declare function warnBeforeMs(timeoutMs: number): number;
38
+ /** What is left of the limit, never negative; null when no limit applies. */
39
+ export declare function idleRemainingMs(lastActivity: unknown, now: number, timeoutMs: number): number | null;
40
+ /** The status poll does not count as activity, or the warning would keep the session alive by itself. */
41
+ export declare const IDLE_STATUS_PATH = "/api/session/idle-status";
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Session limits (#1767): the absolute cap on a signed-in session, and how it
3
+ * sits beside the idle timeout (#1546, `sessionIdle.ts`).
4
+ *
5
+ * `ngdpbase.session.max-age` (milliseconds) is the longest a sign-in lasts:
6
+ * a signed-in session ends that long after it signed in, however active it
7
+ * has been. Shipped at 30 days; the idle timeout (7 days) usually ends a
8
+ * session first.
9
+ *
10
+ * Why it is enforced here and not by the cookie (found 2026-10-12, #1767):
11
+ * before this, `max-age` only set express-session's `cookie.maxAge` and the
12
+ * file store's `ttl`, and neither is a cap.
13
+ *
14
+ * - express-session (`rolling: false`, the default) re-issues the cookie with
15
+ * a fresh expiry, now + maxAge, on every response whose session changed;
16
+ * the app changes it often (CSRF token, IP capture, the idle timer's
17
+ * last-activity write).
18
+ * - On every other request it calls the store's `touch()`, and
19
+ * session-file-store rewrites `__lastAccess`; a stored session expires
20
+ * `cookie.originalMaxAge` after its LAST access, not its first.
21
+ *
22
+ * So `max-age` was a rolling lifetime: a session in use never ended. The cap
23
+ * is now checked on every request from `signedInAt`, which only sign-in
24
+ * completion writes (`AuthManager.completeSignIn`, on the new session after
25
+ * regeneration); a re-authentication (step-up) does not move it.
26
+ *
27
+ * The cookie and the store keep their rolling behaviour and only have to be
28
+ * long enough: a signed-in session's cookie lives `max-age` from its last
29
+ * change (set at sign-in), so it never ends a session before the cap. An
30
+ * anonymous session (every visitor gets one, for the CSRF token) keeps the
31
+ * shorter `ngdpbase.session.anonymous-max-age`, so a 30-day cap does not keep a month of
32
+ * one-visit sessions in the store.
33
+ */
34
+ /** The shipped `ngdpbase.session.max-age`: 30 days. */
35
+ export declare const DEFAULT_SESSION_MAX_AGE_MS: number;
36
+ /** The shipped `ngdpbase.session.anonymous-max-age`: a day, the old shipped `max-age`. */
37
+ export declare const DEFAULT_ANONYMOUS_SESSION_MS: number;
38
+ /**
39
+ * How long a session nobody signed in to lives after its last change:
40
+ * `ngdpbase.session.anonymous-max-age` (the shipped day when not a positive
41
+ * number), or the cap when that is shorter.
42
+ */
43
+ export declare function anonymousSessionMs(capMs: number, configured?: unknown): number;
44
+ /** The configured cap in milliseconds; the shipped 30 days when not a positive number. There is no "off". */
45
+ export declare function sessionCapMs(value: unknown): number;
46
+ /** Whether a session signed in at `signedInAt` (epoch ms) is past the cap. No recorded time is not expired. */
47
+ export declare function capExpired(signedInAt: unknown, now: number, capMs: number): boolean;
48
+ /** What one request does to a signed-in session. */
49
+ export type SessionLimitVerdict = {
50
+ end: 'max-age' | 'idle-timeout';
51
+ } | {
52
+ end: null;
53
+ stampSignedIn: boolean;
54
+ touch: boolean;
55
+ };
56
+ /**
57
+ * The per-request check of a signed-in session against both limits: the cap
58
+ * first (it holds whatever the activity), then the idle timeout. A session
59
+ * signed in before `signedInAt` was recorded starts its cap now
60
+ * (`stampSignedIn`), as the idle timer does for a missing last activity.
61
+ */
62
+ export declare function checkSessionLimits(session: {
63
+ signedInAt?: unknown;
64
+ lastActivity?: unknown;
65
+ }, now: number, limits: {
66
+ idleMs: number;
67
+ capMs: number;
68
+ }): SessionLimitVerdict;