@jwilleke/ngdpbase-types 0.0.0 → 5.19.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 (304) 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 +427 -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 +188 -0
  71. package/lib/src/managers/DatabaseManager.js +590 -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/sqliteBackup.d.ts +128 -0
  158. package/lib/src/providers/sqliteBackup.js +365 -0
  159. package/lib/src/providers/sqliteLocation.d.ts +17 -0
  160. package/lib/src/providers/sqliteLocation.js +55 -0
  161. package/lib/src/providers/sqliteMigrations.d.ts +48 -0
  162. package/lib/src/providers/sqliteMigrations.js +72 -0
  163. package/lib/src/rendering/githubAlerts.d.ts +22 -0
  164. package/lib/src/rendering/htmlPolicy.d.ts +76 -0
  165. package/lib/src/rendering/markdownConverter.d.ts +73 -0
  166. package/lib/src/security/PolicyDecisionPoint.d.ts +245 -0
  167. package/lib/src/security/PolicyInformationPoint.d.ts +448 -0
  168. package/lib/src/security/pageActions.d.ts +40 -0
  169. package/lib/src/security/permissions.generated.d.ts +78 -0
  170. package/lib/src/types/Asset.d.ts +414 -0
  171. package/lib/src/types/Catalog.d.ts +61 -0
  172. package/lib/src/types/Comment.d.ts +11 -0
  173. package/lib/src/types/Config.d.ts +388 -0
  174. package/lib/src/types/Organization.d.ts +78 -0
  175. package/lib/src/types/OrganizationProvider.d.ts +38 -0
  176. package/lib/src/types/Page.d.ts +220 -0
  177. package/lib/src/types/Person.d.ts +56 -0
  178. package/lib/src/types/PersonProvider.d.ts +25 -0
  179. package/lib/src/types/Policy.d.ts +139 -0
  180. package/lib/src/types/Policy.js +17 -0
  181. package/lib/src/types/Provider.d.ts +810 -0
  182. package/lib/src/types/Role.d.ts +84 -0
  183. package/lib/src/types/RoleProvider.d.ts +35 -0
  184. package/lib/src/types/Schema.d.ts +425 -0
  185. package/lib/src/types/Share.d.ts +172 -0
  186. package/lib/src/types/Share.js +81 -0
  187. package/lib/src/types/User.d.ts +304 -0
  188. package/lib/src/types/Version.d.ts +189 -0
  189. package/lib/src/types/WikiEngine.d.ts +128 -0
  190. package/lib/src/types/express.d.ts +120 -0
  191. package/lib/src/types/express.js +1 -0
  192. package/lib/src/types/guards.d.ts +78 -0
  193. package/lib/src/types/heic-decode.d.ts +16 -0
  194. package/lib/src/types/index.d.ts +19 -0
  195. package/lib/src/types/linkedom.d.ts +77 -0
  196. package/lib/src/types/markdown-it-plugins.d.ts +21 -0
  197. package/lib/src/utils/DeltaStorage.d.ts +118 -0
  198. package/lib/src/utils/LocaleUtils.d.ts +105 -0
  199. package/lib/src/utils/LocaleUtils.js +294 -0
  200. package/lib/src/utils/PageNameMatcher.d.ts +98 -0
  201. package/lib/src/utils/PathPreflight.d.ts +38 -0
  202. package/lib/src/utils/PathPreflight.js +50 -0
  203. package/lib/src/utils/SectionUtils.d.ts +40 -0
  204. package/lib/src/utils/addonConfigLayer.d.ts +144 -0
  205. package/lib/src/utils/addonConfigLayer.js +382 -0
  206. package/lib/src/utils/addonDatabaseRules.d.ts +25 -0
  207. package/lib/src/utils/addonDatabaseRules.js +57 -0
  208. package/lib/src/utils/addonHost.d.ts +51 -0
  209. package/lib/src/utils/addonHost.js +72 -0
  210. package/lib/src/utils/addonInstaller.d.ts +109 -0
  211. package/lib/src/utils/addonLock.d.ts +37 -0
  212. package/lib/src/utils/addonLock.js +48 -0
  213. package/lib/src/utils/addonPageSync.d.ts +45 -0
  214. package/lib/src/utils/addonProvenance.d.ts +48 -0
  215. package/lib/src/utils/addonTarball.d.ts +41 -0
  216. package/lib/src/utils/addonsPathResolver.d.ts +76 -0
  217. package/lib/src/utils/addonsPathResolver.js +129 -0
  218. package/lib/src/utils/assetMetadataTags.d.ts +66 -0
  219. package/lib/src/utils/atomicWrite.d.ts +28 -0
  220. package/lib/src/utils/auditConfigChange.d.ts +57 -0
  221. package/lib/src/utils/auditEventNames.d.ts +50 -0
  222. package/lib/src/utils/auditEventNames.generated.d.ts +169 -0
  223. package/lib/src/utils/auditEventNames.generated.js +174 -0
  224. package/lib/src/utils/auditEventNames.js +49 -0
  225. package/lib/src/utils/auditEvents.d.ts +265 -0
  226. package/lib/src/utils/auditEvents.js +309 -0
  227. package/lib/src/utils/auditRegistry.d.ts +102 -0
  228. package/lib/src/utils/auditRegistry.js +168 -0
  229. package/lib/src/utils/bip39English.d.ts +2 -0
  230. package/lib/src/utils/configEnvKeys.d.ts +68 -0
  231. package/lib/src/utils/configFiles.d.ts +74 -0
  232. package/lib/src/utils/configFiles.js +150 -0
  233. package/lib/src/utils/delegation.d.ts +48 -0
  234. package/lib/src/utils/deriveUsername.d.ts +21 -0
  235. package/lib/src/utils/explainMediaPath.d.ts +123 -0
  236. package/lib/src/utils/formerTitles.d.ts +69 -0
  237. package/lib/src/utils/frontmatterAccess.d.ts +54 -0
  238. package/lib/src/utils/headlessAdminPassword.d.ts +55 -0
  239. package/lib/src/utils/imageTransform.d.ts +52 -0
  240. package/lib/src/utils/instanceEnvSecret.d.ts +51 -0
  241. package/lib/src/utils/jobSlots.d.ts +43 -0
  242. package/lib/src/utils/keywordNormalizer.d.ts +127 -0
  243. package/lib/src/utils/logger.d.ts +70 -0
  244. package/lib/src/utils/logger.js +106 -0
  245. package/lib/src/utils/magicLinkDeviceState.d.ts +95 -0
  246. package/lib/src/utils/managerUtils.d.ts +40 -0
  247. package/lib/src/utils/migrateLegacyPrivateAttachments.d.ts +15 -0
  248. package/lib/src/utils/orgFilename.d.ts +22 -0
  249. package/lib/src/utils/pageFeature.d.ts +27 -0
  250. package/lib/src/utils/pageFrontmatter.d.ts +21 -0
  251. package/lib/src/utils/pageNotes.d.ts +150 -0
  252. package/lib/src/utils/pageTitleRule.d.ts +37 -0
  253. package/lib/src/utils/pageToArticle.d.ts +59 -0
  254. package/lib/src/utils/pageUrl.d.ts +18 -0
  255. package/lib/src/utils/passwordChange.d.ts +12 -0
  256. package/lib/src/utils/passwordHash.d.ts +60 -0
  257. package/lib/src/utils/permissionCatalog.d.ts +52 -0
  258. package/lib/src/utils/pluginFormatters.d.ts +452 -0
  259. package/lib/src/utils/pluginFormatters.js +714 -0
  260. package/lib/src/utils/privateLinkRewrite.d.ts +42 -0
  261. package/lib/src/utils/privateStoreAccess.d.ts +57 -0
  262. package/lib/src/utils/privateStoreAccess.js +65 -0
  263. package/lib/src/utils/privateStoreCatalogs.d.ts +40 -0
  264. package/lib/src/utils/privateStoreCrypto.d.ts +127 -0
  265. package/lib/src/utils/privateStoreDoor.d.ts +181 -0
  266. package/lib/src/utils/privateStoreExport.d.ts +72 -0
  267. package/lib/src/utils/privateStoreFiles.d.ts +120 -0
  268. package/lib/src/utils/privateStoreMeta.d.ts +64 -0
  269. package/lib/src/utils/privateStoreMigrations.d.ts +37 -0
  270. package/lib/src/utils/privateStorePath.d.ts +259 -0
  271. package/lib/src/utils/privateStorePath.js +436 -0
  272. package/lib/src/utils/privateStoreTakeout.d.ts +76 -0
  273. package/lib/src/utils/privateStoreUnlock.d.ts +175 -0
  274. package/lib/src/utils/proxyClaim.d.ts +59 -0
  275. package/lib/src/utils/proxyClaim.js +30 -0
  276. package/lib/src/utils/redactPrivateNames.d.ts +21 -0
  277. package/lib/src/utils/redactPrivateNames.js +89 -0
  278. package/lib/src/utils/redactSecrets.d.ts +58 -0
  279. package/lib/src/utils/redactSecrets.js +171 -0
  280. package/lib/src/utils/renameLinkRewrite.d.ts +112 -0
  281. package/lib/src/utils/roleGrants.d.ts +35 -0
  282. package/lib/src/utils/safeRedirect.d.ts +32 -0
  283. package/lib/src/utils/schedule.d.ts +54 -0
  284. package/lib/src/utils/secretFileMode.d.ts +17 -0
  285. package/lib/src/utils/seededShippedPages.d.ts +45 -0
  286. package/lib/src/utils/sensitiveValues.d.ts +59 -0
  287. package/lib/src/utils/sensitiveValues.js +106 -0
  288. package/lib/src/utils/sessionEnd.d.ts +12 -0
  289. package/lib/src/utils/sessionGeneration.d.ts +24 -0
  290. package/lib/src/utils/sessionIdle.d.ts +41 -0
  291. package/lib/src/utils/sessionLimits.d.ts +68 -0
  292. package/lib/src/utils/shareLockbox.d.ts +64 -0
  293. package/lib/src/utils/sigstoreTrustedRoot.d.ts +33 -0
  294. package/lib/src/utils/sniffMime.d.ts +21 -0
  295. package/lib/src/utils/storeSearchIndex.d.ts +75 -0
  296. package/lib/src/utils/subjectMayDo.d.ts +21 -0
  297. package/lib/src/utils/systemCategoryRules.d.ts +30 -0
  298. package/lib/src/utils/systemCategoryRules.js +41 -0
  299. package/lib/src/utils/userCreateError.d.ts +62 -0
  300. package/lib/src/utils/username.d.ts +53 -0
  301. package/lib/src/utils/vaultUrlRewrite.d.ts +27 -0
  302. package/lib/src/utils/version.d.ts +84 -0
  303. package/lib/src/utils/videoFrame.d.ts +21 -0
  304. package/package.json +54 -3
@@ -0,0 +1,1032 @@
1
+ import BaseManager, { BackupData, type ManagerStats } from './BaseManager.js';
2
+ import { type ActorContext } from '../context/ActorContext.js';
3
+ /**
4
+ * Marks an error as "the audit record could not be written", not "the action
5
+ * failed" (#1183). A caller refusing a destructive action needs to say which.
6
+ */
7
+ export declare const AUDIT_WRITE_FAILED = "EAUDITWRITE";
8
+ import type { WikiEngine } from '../types/WikiEngine.js';
9
+ import type { CatalogSource, CatalogQuery, CatalogPage, CreativeWork, SchemaType, RebuildOpts } from '../types/Schema.js';
10
+ import type { AssetQuery, AssetRecord } from '../types/Asset.js';
11
+ import type { StoreFileEntry, StoreFileLocation } from '../types/Provider.js';
12
+ /**
13
+ * Base attachment provider interface
14
+ */
15
+ interface BaseAttachmentProvider {
16
+ initialize(): Promise<void>;
17
+ storeAttachment(fileBuffer: Buffer, fileInfo: FileInfo, metadata: AttachmentMetadataInput, user: User | null): Promise<AttachmentMetadata>;
18
+ getAttachment(attachmentId: string): Promise<{
19
+ buffer: Buffer;
20
+ metadata: AttachmentMetadata;
21
+ } | null>;
22
+ getAttachmentMetadata(attachmentId: string): Promise<AttachmentMetadata | null>;
23
+ getAttachmentsForPage(pageName: string): Promise<AttachmentMetadata[]>;
24
+ getAttachmentByFilename(filename: string): Promise<AttachmentMetadata | null>;
25
+ getAllAttachments(): Promise<AttachmentMetadata[]>;
26
+ deleteAttachment(attachmentId: string): Promise<boolean>;
27
+ updateAttachmentMetadata(attachmentId: string, updates: Partial<AttachmentMetadata>): Promise<boolean>;
28
+ attachmentExists(attachmentId: string): Promise<boolean>;
29
+ refreshAttachmentList(): Promise<void>;
30
+ getThumbnail?(id: string, size: string): Promise<Buffer | null>;
31
+ backup(): Promise<unknown>;
32
+ restore(backupData: unknown): Promise<void>;
33
+ shutdown(): Promise<void>;
34
+ getProviderInfo(): {
35
+ features: string[];
36
+ };
37
+ storeFileInStore(location: StoreFileLocation, bytes: Buffer, file: {
38
+ originalName: string;
39
+ mimeType: string;
40
+ description: string;
41
+ author?: string;
42
+ pageName?: string;
43
+ }): Promise<StoreFileEntry>;
44
+ getFileInStore(location: StoreFileLocation, id: string): Promise<{
45
+ entry: StoreFileEntry;
46
+ bytes: Buffer;
47
+ } | null>;
48
+ listFilesInStore(location: StoreFileLocation): Promise<StoreFileEntry[]>;
49
+ filesInStoreForPage(location: StoreFileLocation, pageName: string): Promise<StoreFileEntry[]>;
50
+ setFileMentionInStore(location: StoreFileLocation, id: string, pageName: string, mentioned: boolean): Promise<boolean>;
51
+ deleteFileInStore(location: StoreFileLocation, id: string): Promise<StoreFileEntry | null>;
52
+ searchFilesInStore(location: StoreFileLocation, query: AssetQuery): Promise<AssetRecord[]>;
53
+ privateRecordsInSharedIndex(): Array<{
54
+ id: string;
55
+ owner: string | null;
56
+ store: string | null;
57
+ pages: string[];
58
+ }>;
59
+ adoptRecordIntoStore(location: StoreFileLocation, id: string): Promise<StoreFileEntry | null>;
60
+ copyRecordIntoStore(location: StoreFileLocation, id: string, pageName: string): Promise<StoreFileEntry | null>;
61
+ copyStoreFileToStore(from: StoreFileLocation, to: StoreFileLocation, id: string, pageName: string): Promise<StoreFileEntry | null>;
62
+ copyStoreFileToPool(from: StoreFileLocation, id: string, pageName: string): Promise<boolean>;
63
+ removeRecordFromPool(id: string): Promise<boolean>;
64
+ setPoolMentions(id: string, names: string[]): Promise<boolean>;
65
+ }
66
+ export interface VaultPagePoolFiles {
67
+ owner: string;
68
+ vault: string;
69
+ page: string | null;
70
+ files: number;
71
+ }
72
+ /**
73
+ * File information interface
74
+ */
75
+ export interface FileInfo {
76
+ originalName: string;
77
+ mimeType: string;
78
+ size: number;
79
+ }
80
+ /**
81
+ * Upload options interface
82
+ */
83
+ export interface UploadOptions {
84
+ pageName?: string;
85
+ description?: string;
86
+ /** WikiContext for the current request — audit IP fallback */
87
+ wikiContext?: import('../context/WikiContext.js').default;
88
+ /**
89
+ * Private-store destination (#1396): the upload dialog's checkbox. Decides
90
+ * only when `pageName` is not a private page — an upload onto a private page
91
+ * is always private, in that page's author's store (#1398). Absent or false
92
+ * otherwise keeps the public attachments pool.
93
+ */
94
+ private?: boolean;
95
+ /** Store id when private with no private page; default from ConfigurationManager defaultstoreid */
96
+ store?: string;
97
+ }
98
+ /**
99
+ * User object interface
100
+ */
101
+ export interface User {
102
+ name: string;
103
+ email?: string;
104
+ }
105
+ /**
106
+ * Mention object (WebPage reference)
107
+ */
108
+ export interface Mention {
109
+ '@type': string;
110
+ name: string;
111
+ url: string;
112
+ }
113
+ /**
114
+ * Attachment metadata interface
115
+ */
116
+ export interface AttachmentMetadata {
117
+ identifier: string;
118
+ name?: string;
119
+ url?: string;
120
+ encodingFormat?: string;
121
+ description?: string;
122
+ isFamilyFriendly?: boolean;
123
+ mentions?: Mention[];
124
+ editor?: {
125
+ '@type': string;
126
+ name: string;
127
+ email?: string;
128
+ };
129
+ documentTitle?: string;
130
+ documentAuthor?: string;
131
+ documentSubject?: string;
132
+ documentKeywords?: string[];
133
+ documentDateCreated?: string;
134
+ documentDateModified?: string;
135
+ inLanguage?: string;
136
+ [key: string]: unknown;
137
+ }
138
+ /**
139
+ * Attachment metadata input (for new uploads)
140
+ */
141
+ export interface AttachmentMetadataInput {
142
+ description: string;
143
+ isFamilyFriendly: boolean;
144
+ }
145
+ /**
146
+ * Attachment backup data
147
+ */
148
+ export interface AttachmentBackupData extends BackupData {
149
+ providerClass: string | null;
150
+ providerBackup?: unknown;
151
+ data?: null;
152
+ }
153
+ declare class AttachmentManager extends BaseManager implements CatalogSource {
154
+ /** CatalogSource identifier (Slice 5 of #755 / #759). */
155
+ readonly sourceId = "attachments";
156
+ /**
157
+ * Subtypes this source produces. Today only DigitalDocument (PDFs / docx /
158
+ * xlsx / pptx). Image and video attachments emit a `DigitalDocument` stub
159
+ * since the rich ImageObject / VideoObject mapper lives on the media path.
160
+ */
161
+ readonly types: readonly SchemaType[];
162
+ /**
163
+ * On-disk schema version for attachment-metadata.json (Decision 6).
164
+ * Bump when the persisted SchemaCreativeWork shape changes; current v1 is
165
+ * the post-Slice-5 (#759) shape including documentTitle / documentAuthor /
166
+ * documentSubject / documentKeywords / documentDateCreated /
167
+ * documentDateModified / inLanguage.
168
+ */
169
+ static readonly CURRENT_SCHEMA_VERSION = 1;
170
+ readonly currentSchemaVersion = 1;
171
+ private attachmentProvider;
172
+ private providerClass;
173
+ /** What the last check for vault pages using shared-pool files found, and the degraded reason it set (#1842). */
174
+ private poolFileFindings;
175
+ private poolFileReason;
176
+ private maxSize;
177
+ private allowedTypes;
178
+ /**
179
+ * Creates a new AttachmentManager instance
180
+ *
181
+ * @constructor
182
+ * @param {WikiEngine} engine - The wiki engine instance
183
+ */
184
+ constructor(engine: WikiEngine);
185
+ /** Return the active attachment provider for use by AssetManager. */
186
+ get provider(): BaseAttachmentProvider | null;
187
+ /**
188
+ * Initialize AttachmentManager and load the configured provider
189
+ *
190
+ * @async
191
+ * @param {Record<string, unknown>} [config={}] - Configuration object (unused, reads from ConfigurationManager)
192
+ * @returns {Promise<void>}
193
+ * @throws {Error} If ConfigurationManager is not available or provider fails to load
194
+ */
195
+ initialize(config?: Record<string, unknown>): Promise<void>;
196
+ /**
197
+ * CatalogSource.list — query attachments and emit CreativeWork shapes.
198
+ *
199
+ * Routes `query.text` through the provider's `getAttachmentsForPage` /
200
+ * `getAllAttachments` surface, applies the (DigitalDocument-restricted)
201
+ * `types` filter, and converts each match via the provider's
202
+ * `toCreativeWork()`. Cursor pagination not yet implemented (initial
203
+ * slice); `limit` caps page size.
204
+ */
205
+ list(query: CatalogQuery): Promise<CatalogPage>;
206
+ /**
207
+ * CatalogSource.get — fetch a single attachment by stable identifier.
208
+ * Returns null for not-found.
209
+ *
210
+ * Note: this does NOT enforce private-page ACL. CatalogManager callers
211
+ * should layer ACL on top (mirroring `getAttachment()` which goes through
212
+ * the request path with full WikiContext).
213
+ */
214
+ get(identifier: string): Promise<CreativeWork | null>;
215
+ /**
216
+ * CatalogSource.rebuild — re-extract embedded document metadata on every
217
+ * stored attachment. Walks the entire metadata store, for each
218
+ * doc-MIME attachment re-runs exiftool extraction on the stored file and
219
+ * backfills the seven Slice-5 fields (documentTitle / documentAuthor /
220
+ * documentSubject / documentKeywords / documentDateCreated /
221
+ * documentDateModified / inLanguage). Backfills pre-v3.27.0 records that
222
+ * never went through the Slice-5 extraction path at upload time.
223
+ *
224
+ * Per-file failures are non-fatal — logged and counted. Non-document
225
+ * MIMEs are skipped. Wired into the `attachments.rebuild` background job
226
+ * for operator-triggered runs from the admin dashboard. Slice 5b of #760
227
+ * (#763).
228
+ */
229
+ rebuild(opts?: RebuildOpts): Promise<void>;
230
+ /**
231
+ * Re-extract embedded document metadata across every stored attachment.
232
+ * Same operation as {@link rebuild} but returns the summary so the
233
+ * `attachments.rebuild` background job can produce a per-run report.
234
+ * Returns `{scanned, updated, skipped, errors}` zeros when the provider
235
+ * isn't initialised yet (caller can branch on this).
236
+ */
237
+ backfillDocMetadata(onProgress?: (processed: number, total: number) => void): Promise<{
238
+ scanned: number;
239
+ updated: number;
240
+ skipped: number;
241
+ errors: number;
242
+ }>;
243
+ /**
244
+ * Get current attachment provider
245
+ * @returns {BaseAttachmentProvider | null} Current provider instance
246
+ */
247
+ getCurrentAttachmentProvider(): BaseAttachmentProvider | null;
248
+ /**
249
+ * Check a registry permission for an attachment operation (#1059).
250
+ *
251
+ * Evaluates through the PDP (`PolicyDecisionPoint.permits`), the same
252
+ * path WikiContext.hasPermission takes. Until #1059 this was a stub that
253
+ * ignored its argument and granted any authenticated user, which made every
254
+ * permission passed to it decorative — asset-delete sat on the editor role
255
+ * while any logged-in account could delete any attachment.
256
+ *
257
+ * Fails closed when UserManager is unavailable: an attachment mutation with
258
+ * no policy engine to consult is denied, not waved through.
259
+ *
260
+ * @param {string} permission - Registry permission ({target}-{action}, e.g. 'asset-upload')
261
+ * @param userContext - The caller's context, forwarded (#1179)
262
+ * @returns {Promise<boolean>} True if allowed
263
+ * @private
264
+ */
265
+ private checkPermission;
266
+ /**
267
+ * Localize the remote images an NCM body embeds (#728 S5a-ii, #1486): each
268
+ * remote `<img>`/`![](url)` is fetched, checked (size, type, ad deny-list)
269
+ * and stored as an attachment of `pageName`, and the body is rewritten to
270
+ * point at it. With `dryRun` nothing is stored: the fetch and checks run,
271
+ * and the result reports what would be attached.
272
+ *
273
+ * Reached through PageManager.completeNcmConversion, the NCM door, never
274
+ * from a route.
275
+ *
276
+ * #1133: the URL comes from page content, so this fetch is a capability the
277
+ * editor does not otherwise have — making the server issue a request from
278
+ * inside the network. guardedFetch judges the address actually resolved, on
279
+ * every redirect hop.
280
+ */
281
+ localizeRemoteImages(content: string, pageName: string, ctx: ActorContext, dryRun: boolean): Promise<{
282
+ content: string;
283
+ warnings: string[];
284
+ }>;
285
+ /**
286
+ * Every attachment write goes through here (#1751): it writes, then bumps
287
+ * the attachment-data version, so cached renders that list or show
288
+ * attachments re-render.
289
+ */
290
+ private writeAttachments;
291
+ /**
292
+ * Upload an attachment
293
+ *
294
+ * @param {Buffer} fileBuffer - File data
295
+ * @param {FileInfo} fileInfo - { originalName, mimeType, size }
296
+ * @param {UploadOptions} options - Upload options
297
+ * @param {string} options.pageName - Page uploaded onto (optional). A private page forces the upload private, into its author's store (#1398)
298
+ * @param {string} options.description - File description
299
+ * @param {boolean} options.private - Private-store destination for an upload with no private page (#1396)
300
+ * @param {string} options.store - Store id when private with no private page; else ConfigurationManager defaultstoreid
301
+ * @param ctx - Who is uploading (#1179): the request's subject, or a JobContext for an in-engine caller. Mandatory and positional.
302
+ * @returns {Promise<AttachmentMetadata>} Attachment metadata
303
+ */
304
+ uploadAttachment(fileBuffer: Buffer, fileInfo: FileInfo, ctx: ActorContext, options?: UploadOptions): Promise<AttachmentMetadata>;
305
+ /** A file is added to a private page only by someone who may edit it: the page's own decision (#1398). */
306
+ private assertMayEditPage;
307
+ /**
308
+ * One vault as a provider location, opened through `ctx` (#1842). Throws as
309
+ * `storeFileIO` does: a locked vault, or a sealed kind's vault not yet opened.
310
+ */
311
+ private vaultLocation;
312
+ /**
313
+ * Attach an existing attachment to a page
314
+ *
315
+ * @param {string} attachmentId - Attachment identifier
316
+ * @param {string} pageName - Page name to attach to
317
+ * @param ctx - Whose mention this is (#1179). Mandatory and positional.
318
+ * @returns {Promise<boolean>} Success status
319
+ */
320
+ attachToPage(attachmentId: string, pageName: string, ctx: ActorContext): Promise<boolean>;
321
+ /**
322
+ * Detach an attachment from a page
323
+ *
324
+ * @param {string} attachmentId - Attachment identifier
325
+ * @param {string} pageName - Page name to detach from
326
+ * @param ctx - Whose mention this is (#1179). Mandatory and positional.
327
+ * @returns {Promise<boolean>} Success status
328
+ */
329
+ detachFromPage(attachmentId: string, pageName: string, ctx: ActorContext): Promise<boolean>;
330
+ /**
331
+ * Get an attachment by ID
332
+ *
333
+ * @param {string} attachmentId - Attachment identifier
334
+ * @returns {Promise<{buffer: Buffer, metadata: AttachmentMetadata}|null>}
335
+ */
336
+ getAttachment(attachmentId: string): Promise<{
337
+ buffer: Buffer;
338
+ metadata: AttachmentMetadata;
339
+ } | null>;
340
+ /**
341
+ * The requester's own private stores, as provider locations (#1460).
342
+ *
343
+ * The container rule first: a context that may not act in its own container
344
+ * — anonymous, or a share visitor, whose `viaShare` issuer is someone else
345
+ * — reaches no store at all. Then every store in that container, plain or
346
+ * sealed: `privateStoreIdsOf` answers from the folder, because which stores
347
+ * EXIST does not depend on keys. `storeFileIO` refuses an encrypted store
348
+ * this context holds no DEK for, and that store is skipped rather than read
349
+ * in the clear.
350
+ */
351
+ private ownPrivateStores;
352
+ private mayReach;
353
+ /**
354
+ * How a store file is shown to callers that expect attachment metadata.
355
+ * The legacy aliases (`id`, `filename`, `mimeType`, `size`, …) are here so a
356
+ * merged list renders through the same templates the shared pool does
357
+ * (#1460); `filePath` is not, because where a private file sits on disk is
358
+ * not something a listing carries.
359
+ */
360
+ private static storeFileMetadata;
361
+ /**
362
+ * The requester's own store that lists `attachmentId`, with its entry — or
363
+ * null when none of them does, or the PIP refuses (#1460). Metadata only:
364
+ * the bytes are read by the caller that needs them, so a listing, a delete
365
+ * and a mention change do not decrypt a file to look at its name.
366
+ */
367
+ private findOwnStoreFile;
368
+ /**
369
+ * May `ctx` do `permission` to `what` in `owner`'s vault `store` (#1539)?
370
+ * The container rule, then the capability asked with the vault, so
371
+ * `vault-owner` decides — the same rule as a vault page.
372
+ */
373
+ private mayInVault;
374
+ /** The requester's own store file and its entry, before the capability is asked — see {@link findOwnStoreFile}. */
375
+ private locateOwnStoreFile;
376
+ /**
377
+ * A file from the requester's own private stores — or null when none of the
378
+ * stores it can open lists it, or the PIP refuses. An encrypted store's
379
+ * bytes come back decrypted; a plain store's come back as they are, and in
380
+ * both cases the caller got here only by owning the container.
381
+ */
382
+ getPrivateStoreAttachment(attachmentId: string, ctx: ActorContext): Promise<{
383
+ buffer: Buffer;
384
+ metadata: AttachmentMetadata;
385
+ } | null>;
386
+ /**
387
+ * A file served through a vault link (#1388): from the one vault the link
388
+ * names, and only when a current page the link covers uses it. A file no
389
+ * covered page uses — including a copy nobody uses any more (#1517) — is
390
+ * not shared. `ctx` is the link's subject; the container rule and the share
391
+ * ceiling decide as for every other door.
392
+ */
393
+ getVaultShareAttachment(attachmentId: string, ctx: ActorContext): Promise<{
394
+ buffer: Buffer;
395
+ metadata: AttachmentMetadata;
396
+ } | null>;
397
+ /** The container rule for one vault, as the link's subject may enter it (#1388). */
398
+ private mayReachVault;
399
+ /**
400
+ * The files in the requester's own vaults that no page in that vault uses
401
+ * (#1517) — for their profile page, so a copy kept for a page that left the vault,
402
+ * or a file whose page was deleted, can be seen and removed.
403
+ *
404
+ * Only the requester's own vaults, through the container rule. "Used" is a
405
+ * current page of that vault in the file's mentions, which every save keeps
406
+ * in step. An encrypted vault this session cannot open is reported as
407
+ * locked rather than as empty.
408
+ *
409
+ * @returns One entry per vault with unused files, or locked; `canDelete` is
410
+ * whether this context may delete files there — the delete's own question
411
+ * (#1539), so the page offers the button exactly when the delete would work
412
+ */
413
+ listOwnUnusedVaultFiles(ctx: ActorContext): Promise<Array<{
414
+ vault: string;
415
+ locked: boolean;
416
+ canDelete: boolean;
417
+ files: Array<{
418
+ id: string;
419
+ name: string;
420
+ contentSize: number;
421
+ dateCreated: string;
422
+ }>;
423
+ }>>;
424
+ /**
425
+ * Is `attachmentId` a file in one of the requester's own private stores?
426
+ * An index read, no bytes — for a caller that has to treat a private file
427
+ * differently without reading it twice (#1460).
428
+ */
429
+ isOwnPrivateStoreFile(attachmentId: string, ctx: ActorContext): Promise<boolean>;
430
+ /** The requester's own private-store files uploaded onto `pageName`. */
431
+ getPrivateStoreAttachmentsForPage(pageName: string, ctx: ActorContext): Promise<AttachmentMetadata[]>;
432
+ /**
433
+ * Everything the requester's own private stores hold (#1460) — the half of
434
+ * a browse or a list that is in no shared index. Another user's stores, and
435
+ * an admin's view of anyone's, are not here: this reads `ctx`'s container
436
+ * and no other.
437
+ */
438
+ getPrivateStoreAttachments(ctx: ActorContext): Promise<AttachmentMetadata[]>;
439
+ /**
440
+ * The requester's own private-store files as asset-search results (#1460).
441
+ *
442
+ * AssetManager fans a search out over the provider registry, and no provider
443
+ * can see a store it was given no context for — so the store half is merged
444
+ * by the one caller that holds the requester's context. The matching rules
445
+ * are the provider's own, applied to the store's entries, so a private file
446
+ * is findable exactly as a public one is.
447
+ */
448
+ searchPrivateStoreAttachments(query: AssetQuery, ctx: ActorContext): Promise<AssetRecord[]>;
449
+ /**
450
+ * Move every unencrypted private file record out of the global
451
+ * `attachment-metadata.json` and into its store's own index, at start-up.
452
+ *
453
+ * Best-effort: a failure is logged and never blocks start-up, the shape
454
+ * `migratePrivateLinksAtBoot` uses.
455
+ */
456
+ migratePrivateFilesAtBoot(): Promise<void>;
457
+ /**
458
+ * Move the private file records still in the shared index into their stores.
459
+ *
460
+ * __Which files are private__ is decided from the record itself first — the
461
+ * `isPrivate` / `creator` / `store` fields #1398 writes — and, where that is
462
+ * not enough, from the page it is attached to: a mention naming
463
+ * `private/{owner}/{store}/{title}` says whose store the file belongs in,
464
+ * confirmed through `PageManager.getPrivatePageOwner`. A record that is
465
+ * neither is a public attachment and stays where it is.
466
+ *
467
+ * __What moves__: the bytes, into `{store}/attachments/`, KEEPING their
468
+ * existing file name — nothing on disk is renamed — and the record, into
469
+ * the store's own index under the id it already had, because that id is its
470
+ * `/attachments/{id}` URL on every page that references it.
471
+ *
472
+ * __No unlock split__, unlike #1457's link migration and #1458's search
473
+ * indexes. Those needed one because a page's TEXT is sealed; here an
474
+ * unencrypted store needs no key at all, so this boot job finishes the whole
475
+ * job for the stores it is about. A record pointing at an ENCRYPTED store is
476
+ * skipped, with a line saying so: #1400 already keeps those files in their
477
+ * store, and one predating it cannot be re-sealed without its owner's DEK.
478
+ *
479
+ * __Idempotent__: a second run finds nothing left in the shared index, and a
480
+ * record whose store already lists the id moves no bytes.
481
+ *
482
+ * @param ctx - Whose reading and writing this is (#1179). Mandatory and positional.
483
+ * @returns how many records moved
484
+ */
485
+ migratePrivateFilesIntoStores(ctx: ActorContext): Promise<number>;
486
+ /**
487
+ * Move the files a page uses when the page changes place — into a vault, out
488
+ * of one, or between two — so that every file a vault page uses is in that
489
+ * vault (operator, 2026-10-16). Called by the page door after the page moved.
490
+ *
491
+ * __Which files__: those whose mentions name the page where it was, and
492
+ * those its content references (`[{Image src='…'}]`, `[{ATTACH src='…'}]`,
493
+ * `/attachments/{id}`), resolved in the vault it left first, then the shared
494
+ * pool.
495
+ *
496
+ * __How__: each file is copied to the destination under the same id (its
497
+ * `/attachments/{id}` URL in the page), through both sides' store I/O —
498
+ * sealed going into a sealed vault, opened coming out. Then the source: a
499
+ * file no other page there uses is removed; one another page still uses is
500
+ * left for it, without this page's mention. A shared-pool file is removed
501
+ * from the pool only when no public page that exists now is among its
502
+ * mentions ({@link poolFileShare}): a file other public pages use is copied
503
+ * in, never taken from them, and a stale mention (a page renamed, made
504
+ * private or deleted, often this page's own former title) keeps nothing.
505
+ *
506
+ * __Refusal__: both sides' I/O is resolved before any file moves, so a locked
507
+ * vault, or a sealed kind's vault not yet opened, moves nothing — the same
508
+ * refusal the page's own save meets first.
509
+ *
510
+ * @param previousName - The page's name before: a public title, or `vaults/{owner}/{store}/{title}`
511
+ * @param name - Its name now
512
+ * @param content - Its content
513
+ * @param ctx - Whose move this is (#1179): the page door already let it move the page
514
+ * @returns how many files moved or were copied
515
+ */
516
+ movePageAttachments(previousName: string, name: string, content: string, ctx: ActorContext): Promise<number>;
517
+ /** The file names (with their basenames) and `/attachments/{id}` ids `content` references. */
518
+ private static contentRefs;
519
+ /**
520
+ * The shared-pool files page `pageName` uses: records whose mentions name it,
521
+ * and those `content` references that `held` (a vault's own files) does not
522
+ * answer.
523
+ */
524
+ private poolFilesOfPage;
525
+ /**
526
+ * Who else uses shared-pool file `id`, besides the page itself — known by
527
+ * `self.names` (its name now, and before a move) and `self.uuid` (#1842).
528
+ *
529
+ * Each mention is one of:
530
+ *
531
+ * - __the page itself__: dropped from the record
532
+ * - __a public page that exists now__ (asked of PageManager by exact title,
533
+ * slug or uuid, never by role): a sharer, for which the pool copy is kept
534
+ * - __another vault page__: kept until that page's own repair takes the
535
+ * file (the startup check names that vault meanwhile), so its bytes are
536
+ * never removed from under it
537
+ * - __stale__, a public name no page has any more (renamed, made private,
538
+ * deleted; often this page's own former public title): dropped, and it
539
+ * keeps nothing
540
+ *
541
+ * `alone` is true when the mentions name no one but the page and stale
542
+ * names: the pool copy should go. A record with no mentions at all, which
543
+ * only content references, is never `alone`, so it is never taken from a
544
+ * page whose mention was never recorded.
545
+ */
546
+ private poolFileShare;
547
+ /**
548
+ * Is `name` a public page that exists now, other than page `selfUuid`
549
+ * (#1842)? By exact title (any case), slug or uuid: a fuzzy match is not
550
+ * that page. Without a PageManager nothing can be told, so every name counts.
551
+ */
552
+ private isLivePublicPage;
553
+ /** The uuid of page `name` as `ctx` finds it; null when it can't be told. */
554
+ private pageUuidOf;
555
+ /**
556
+ * What taking shared-pool file `id` into a vault does (#1842): 'moved', the
557
+ * pool copy goes; 'copied', copied in with the pool copy left for its
558
+ * sharers; null, nothing, because the vault already holds it and public
559
+ * pages still use the pool copy.
560
+ */
561
+ private static poolPlan;
562
+ /**
563
+ * Take shared-pool file `id` into vault `to` for page `name`, under the same
564
+ * id, through the vault's I/O; then the pool copy: removed (record, bytes,
565
+ * thumbnails) when no public page uses it, otherwise left for those that do,
566
+ * without this page's mention or stale ones. Copy first, so a failure leaves
567
+ * two copies, never none. A vault that already holds the id (`held`: an
568
+ * earlier repair copied it) just gains the mention, so running the repair
569
+ * again removes a pool copy left behind.
570
+ *
571
+ * @returns 'moved' (no pool copy left), 'copied' (left for other pages), or null when nothing was copied
572
+ */
573
+ private takePoolFileIntoVault;
574
+ /**
575
+ * Bring the shared-pool files vault page `name` still uses into its vault
576
+ * (#1842's repair, for files a move before #1842 left in the pool): the
577
+ * files its mentions name and those `content` references that the vault
578
+ * doesn't hold, each by {@link movePageAttachments}'s rule — copied in under
579
+ * the same id, sealed when the vault is, and removed from the pool only
580
+ * when no public page that exists now uses it ({@link poolFileShare}).
581
+ * A file the vault already holds under the same id whose pool copy no
582
+ * public page uses loses that copy too, so running the repair again on a
583
+ * page whose files were copied in removes what was left behind.
584
+ *
585
+ * The vault's I/O is resolved first, so a locked vault, or a sealed kind's
586
+ * vault not yet opened, throws and nothing moves. Who may ask is the
587
+ * caller's (`PageManager.repairVaultPage`) to decide.
588
+ *
589
+ * @param name - The page's vault name, `vaults/{owner}/{store}/{title}`
590
+ * @param content - Its content; '' when only its mentions are to be followed
591
+ * @param ctx - Whose I/O this is: the owner's session for a sealed vault
592
+ * @param opts.dryRun - Count what would happen, and change nothing
593
+ * @returns how many files were (or would be) moved out of the pool, and copied with a pool copy left for other pages
594
+ */
595
+ movePoolFilesIntoVault(name: string, content: string, ctx: ActorContext, opts?: {
596
+ dryRun?: boolean;
597
+ }): Promise<{
598
+ moved: number;
599
+ copied: number;
600
+ }>;
601
+ /**
602
+ * The shared-pool files {@link movePoolFilesIntoVault} would bring into
603
+ * vault page `name`'s vault, by id with their file name and the URL that
604
+ * serves them today (#1842's repair list, for the owner to check what will
605
+ * move). Changes nothing and logs nothing. The vault's I/O is resolved as
606
+ * for the move, so a locked vault throws. Whether `ctx` may see these is the
607
+ * caller's (`PageManager.vaultRepairDetails`) to decide: names are shown to
608
+ * the page's reader only, never logged or recorded.
609
+ */
610
+ poolFilesOfVaultPage(name: string, content: string, ctx: ActorContext): Promise<Array<{
611
+ id: string;
612
+ name: string;
613
+ url: string;
614
+ }>>;
615
+ /**
616
+ * The vault page's location, and the shared-pool files it uses that the
617
+ * repair has work for (#1842), each with what the repair would do:
618
+ *
619
+ * - those its vault does not hold: its mentions name the page, or its
620
+ * content references them
621
+ * - those its vault already holds under the same id (an earlier repair, or
622
+ * a move, copied them in) and that still have a pool copy no public page
623
+ * uses, so a repair run again removes it
624
+ *
625
+ * A file the vault holds whose pool copy public pages still use is not
626
+ * listed: there is nothing to do.
627
+ */
628
+ private vaultPagePoolIds;
629
+ /**
630
+ * The vault page names in `owner`'s vault `store` that shared-pool records
631
+ * still mention (#1842), and, in a vault that is not sealed, those its own
632
+ * files name whose pool copy should be gone ({@link heldPoolLeftovers}):
633
+ * what the startup check reports as "pages named by shared records". Used
634
+ * by the repair; never logged.
635
+ */
636
+ poolMentionedVaultPages(owner: string, store: string): Promise<string[]>;
637
+ /**
638
+ * A vault's own files (`own`) that the shared pool still has under the same
639
+ * id with no public page using that copy (#1842): an earlier repair or move
640
+ * copied them in and the pool copy stayed, served to anyone with the id. By
641
+ * {@link poolFileShare}, with the vault pages each file names as the page
642
+ * itself. A pool copy a public page that exists now still names is not one.
643
+ */
644
+ private heldPoolLeftovers;
645
+ /**
646
+ * Vault pages that still use files in the shared pool (#1842): left by moves
647
+ * into a vault before #1842, when the page went and its files stayed. Such a
648
+ * file is served like any public attachment. Read only, and no key is used:
649
+ *
650
+ * - a shared record whose mentions name a vault page (`page: null`, so the
651
+ * title in that mention is never repeated)
652
+ * - in each vault that is not sealed, a page (`{uuid}.md`) whose content
653
+ * references a shared-pool file the vault does not hold itself
654
+ * - in each vault that is not sealed, a page using a file the vault holds
655
+ * whose pool copy under the same id no public page that exists now uses
656
+ * (its mentions are stale, or name only vault pages): the copy an earlier
657
+ * repair left behind, which a repair run again removes. Such a file no
658
+ * page's content or title claims is counted for the vault (`page: null`)
659
+ *
660
+ * A sealed vault's pages can't be read without their owner's key, so they are
661
+ * not checked here.
662
+ */
663
+ findVaultPagesUsingPoolFiles(): Promise<VaultPagePoolFiles[]>;
664
+ /**
665
+ * The startup report for {@link findVaultPagesUsingPoolFiles}, made the way
666
+ * the unsealed-vault and notes checks report (#1834, #1839): an error in the
667
+ * log naming each owner, vault and page uuid, the degraded state (the
668
+ * subsystem banner) and a system notification. Nothing is moved or deleted.
669
+ * A failing check is logged, never thrown. Run after the boot migration, so
670
+ * what it moved into plain stores is not reported.
671
+ */
672
+ reportVaultPagesUsingPoolFilesAtBoot(): Promise<void>;
673
+ /**
674
+ * Run that check again (#1842): after a repair, so the subsystem banner
675
+ * clears once nothing is left. No notification.
676
+ */
677
+ recheckVaultPagesUsingPoolFiles(): Promise<VaultPagePoolFiles[]>;
678
+ /** What the last check found (#1842): owner, vault, page uuid (null: pages named by shared records), file count. */
679
+ vaultPagesUsingPoolFiles(): VaultPagePoolFiles[];
680
+ private checkVaultPagesUsingPoolFiles;
681
+ /**
682
+ * Get attachment metadata only
683
+ *
684
+ * @param {string} attachmentId - Attachment identifier
685
+ * @returns {Promise<AttachmentMetadata|null>}
686
+ */
687
+ getAttachmentMetadata(attachmentId: string): Promise<AttachmentMetadata | null>;
688
+ /**
689
+ * Every file attached to a page that this requester may see: the shared
690
+ * pool's records, plus the requester's own private-store files that name
691
+ * the page (#1460). Another user's, and an admin's view of anyone's, are
692
+ * not merged — {@link ownPrivateStores} reads `ctx`'s container and no other.
693
+ *
694
+ * @param pageName - Page name
695
+ * @param ctx - Whose reading this is (#1179). Mandatory and positional.
696
+ */
697
+ getAttachmentsForPage(pageName: string, ctx: ActorContext): Promise<AttachmentMetadata[]>;
698
+ /**
699
+ * Find an attachment by its original filename.
700
+ *
701
+ * The shared pool first, then the requester's own stores (#1460): a public
702
+ * page's markup must resolve to the same file for everyone who can read it,
703
+ * so a private file of the reader's never shadows a public record of the
704
+ * same name. A private file uploaded ONTO a page is still found before
705
+ * either, by {@link resolveAttachmentSrc}, which asks the page's own files.
706
+ *
707
+ * @param filename - Original filename to search for
708
+ * @param ctx - Whose reading this is (#1179). Mandatory and positional.
709
+ */
710
+ getAttachmentByFilename(filename: string, ctx: ActorContext): Promise<AttachmentMetadata | null>;
711
+ /** #1006: how many attachments this instance holds. Count only, never metadata. */
712
+ getManagerStats(): Promise<ManagerStats>;
713
+ /**
714
+ * Every attachment this requester may see: the shared pool, plus their own
715
+ * private stores' files (#1460).
716
+ *
717
+ * @param ctx - Whose reading this is (#1179). Mandatory and positional.
718
+ */
719
+ getAllAttachments(ctx: ActorContext): Promise<AttachmentMetadata[]>;
720
+ /**
721
+ * The shared pool alone — what `attachment-metadata.json` holds (#1460).
722
+ *
723
+ * For the surfaces that have no requester to merge for: an instance count,
724
+ * and the CatalogSource fan-out, whose results are a shared catalogue. A
725
+ * surface that DOES have one asks {@link getAllAttachments} instead.
726
+ */
727
+ getSharedPoolAttachments(): Promise<AttachmentMetadata[]>;
728
+ /**
729
+ * The shared pool's record with this filename, with nothing merged (#1460).
730
+ *
731
+ * For `AssetManager.syncPageAssets`, which keeps a SHARED index of what each
732
+ * public page references: nothing private may enter it, so it must not be
733
+ * given the per-requester merge {@link getAttachmentByFilename} does.
734
+ */
735
+ getSharedPoolAttachmentByFilename(filename: string): Promise<AttachmentMetadata | null>;
736
+ /**
737
+ * Delete an attachment
738
+ *
739
+ * @param {string} attachmentId - Attachment identifier
740
+ * @param context - Who is acting (#1179): the request's subject, or a JobContext
741
+ * @returns {Promise<boolean>} Success status
742
+ */
743
+ deleteAttachment(attachmentId: string, context: ActorContext, wikiContext?: {
744
+ request?: {
745
+ ip?: string;
746
+ } | null;
747
+ }): Promise<boolean>;
748
+ /**
749
+ * Emit an attachment audit event from the manager that owns the resource.
750
+ *
751
+ * `docs/audit-posture.md` states the rule this implements: an action is
752
+ * "emitted through `recordAuditEvent` (or the manager door that calls it)".
753
+ * The door is here. Placing it at a route means every future caller has to
754
+ * remember, which is the thing #1120 exists to end — being audited must not
755
+ * depend on a producer recalling a method.
756
+ *
757
+ * `critical` decides whether a failure to record stops the action.
758
+ */
759
+ private recordAttachmentEvent;
760
+ /** #1204: an attachment's metadata changed; field NAMES only, at the door both edit paths pass through. */
761
+ private recordAssetEdit;
762
+ /**
763
+ * Update attachment metadata
764
+ *
765
+ * @param {string} attachmentId - Attachment identifier
766
+ * @param {Partial<AttachmentMetadata>} updates - Metadata updates
767
+ * @param context - Who is acting (#1179): the request's subject, or a JobContext
768
+ * @returns {Promise<boolean>} Success status
769
+ */
770
+ updateAttachmentMetadata(attachmentId: string, updates: Partial<AttachmentMetadata>, context: ActorContext): Promise<boolean>;
771
+ /**
772
+ * Edit an attachment's descriptive metadata (#999).
773
+ *
774
+ * Distinct from `updateAttachmentMetadata`, which takes an
775
+ * `AttachmentMetadata` shape and returns a boolean. This takes the same
776
+ * `AssetMetadataPatch` the media route uses — absent means keep, explicit
777
+ * `null` means clear — and returns the refreshed record.
778
+ *
779
+ * **Sidecar only for attachments.** Unlike the media equivalent, this does
780
+ * not write into the file: attachment IDs are content hashes, so an embedded
781
+ * write would break the id↔bytes invariant. See
782
+ * `BasicAttachmentProvider.updateMetadata` for the full reasoning.
783
+ *
784
+ * Gated on `asset-edit`, the same permission `PATCH /media/api/item/:id`
785
+ * uses — this is asset metadata editing, and it should not require a
786
+ * *different* right depending on whether the file happens to be a page
787
+ * attachment or a media-library item.
788
+ *
789
+ * Note the older `updateAttachmentMetadata` still gates on
790
+ * `asset-upload`. Two paths edit attachment metadata under two different
791
+ * permissions; that divergence predates this method and is left alone rather
792
+ * than changed as a side effect of adding a route.
793
+ *
794
+ * @param attachmentId - Attachment identifier
795
+ * @param patch - Fields to change; `null` clears, omission leaves alone
796
+ * @param context - Caller, for the permission check
797
+ * @returns The refreshed record, or null when the attachment is unknown
798
+ * @throws Error when the caller lacks `asset-edit`, or the provider cannot edit
799
+ */
800
+ updateAssetMetadata(attachmentId: string, patch: import('../types/Asset.js').AssetMetadataPatch, context: ActorContext): Promise<import('../types/Asset.js').AssetRecord | null>;
801
+ /**
802
+ * Check if an attachment exists
803
+ *
804
+ * @param {string} attachmentId - Attachment identifier
805
+ * @returns {Promise<boolean>}
806
+ */
807
+ attachmentExists(attachmentId: string): Promise<boolean>;
808
+ /**
809
+ * Get attachment URL
810
+ *
811
+ * @param {string} attachmentId - Attachment identifier
812
+ * @returns {string} URL path
813
+ */
814
+ getAttachmentUrl(attachmentId: string): string;
815
+ /**
816
+ * Resolve an attachment src value (from plugin syntax) to a serving URL and MIME type.
817
+ *
818
+ * This is the canonical resolution method used by all plugins (ImagePlugin,
819
+ * AttachPlugin, and future media plugins). Centralising here means Media
820
+ * Manager (#273), private folders (#122), and any other media source only
821
+ * need to be wired in once.
822
+ *
823
+ * Resolution order:
824
+ * 0. media:// URI — resolved via MediaManager.findByFilename(); never touches attachment store
825
+ * 1. External URL (starts with http:// or https://) — returned as-is, mimeType: ''
826
+ * 2. Absolute path (starts with /) — returned as-is, mimeType: ''
827
+ * 3. Filename lookup on the current page's attachments (exact name match)
828
+ * 4. Global filename search across all attachments
829
+ * 5. Returns null if unresolvable (caller decides how to render the error)
830
+ *
831
+ * @param {string} src - The raw src value from plugin syntax
832
+ * @param {string} pageName - Page name for step 3 context
833
+ * @returns {Promise<{ url: string; mimeType: string } | null>} Resolved result or null
834
+ */
835
+ resolveAttachmentSrc(src: string, pageName: string, ctx: ActorContext): Promise<{
836
+ url: string;
837
+ mimeType: string;
838
+ } | null>;
839
+ /**
840
+ * Page-scoped then global lookup for one exact name (#1051 extraction).
841
+ * Both call sites need the same two steps; nothing else changed.
842
+ */
843
+ private lookupAttachmentByName;
844
+ /**
845
+ * Final path segment of a reference, or '' when there is none (#1051).
846
+ *
847
+ * Returns '' for a trailing slash so callers can skip rather than searching
848
+ * for an empty filename, which `getAttachmentByFilename` would answer
849
+ * unpredictably.
850
+ */
851
+ static basenameOf(src: string): string;
852
+ /**
853
+ * Generate (or return cached) thumbnail for an image attachment.
854
+ *
855
+ * Delegates to the provider's getThumbnail() implementation.
856
+ * Returns null for non-image attachments or when the provider has no
857
+ * thumbnail capability.
858
+ *
859
+ * #1460: a file in one of the requester's own private stores has no record
860
+ * in the shared index and no bytes in the shared pool, so the provider's
861
+ * cache-on-disk path cannot make its thumbnail. It is rendered from the
862
+ * bytes in memory and deliberately NOT written to the shared `.thumbs`
863
+ * folder: a thumbnail of a private file is the private file, smaller, and
864
+ * putting one in a shared directory would undo the move this issue is.
865
+ *
866
+ * @param {string} attachmentId - Attachment identifier
867
+ * @param {string} size - Size string e.g. "150x150"
868
+ * @param ctx - Whose reading this is (#1179). Mandatory and positional.
869
+ * @returns {Promise<Buffer|null>}
870
+ */
871
+ getThumbnail(attachmentId: string, size: string, ctx: ActorContext): Promise<Buffer | null>;
872
+ /**
873
+ * Scan page content for local attachment references and synchronise mentions.
874
+ *
875
+ * Parses [{Image src='...'}] and [{ATTACH src='...'}] directives, resolves
876
+ * each filename to an attachment identifier, then diffs against the current
877
+ * mentions stored on each attachment:
878
+ * - newly referenced attachments gain a mention for pageName
879
+ * - previously referenced attachments that are no longer in content lose it
880
+ *
881
+ * Replaces the lazy attachToPage() side-effect in resolveAttachmentSrc() with
882
+ * a deterministic, save-time update. See #405 Phase 4 / #403.
883
+ *
884
+ * @param {string} pageName - Name of the page being saved
885
+ * @param {string} content - Raw wiki markup content
886
+ * @returns {Promise<void>}
887
+ */
888
+ /**
889
+ * Canonical local-attachment reference extraction — `[{Image src='…'}]` /
890
+ * `[{ATTACH src='…'}]` filenames, skipping media:// URIs, external URLs,
891
+ * and absolute paths. Shared by save-time mention sync, the batch
892
+ * reconciler (scripts/reconcile-attachment-mentions.ts mirrors it), and the
893
+ * #865 health report.
894
+ */
895
+ static extractLocalAttachmentRefs(content: string): Set<string>;
896
+ /**
897
+ * #865: identifier-URL references — `/attachments/<sha256>` anywhere in
898
+ * content (markdown images/links, raw URLs). Storybook-generated day pages
899
+ * embed route maps this way (`![Day 4 route](/attachments/<id>)`); these
900
+ * are real render-time references and count as mentions.
901
+ */
902
+ static extractAttachmentIdRefs(content: string): Set<string>;
903
+ /**
904
+ * @param ctx - Whose save this is (#1179). Mandatory and positional: the
905
+ * requester's own private-store files take part in this too (#1460) —
906
+ * a file uploaded into their store from a public page's editor is
907
+ * mentioned by that page, and its mentions live in its store's own index.
908
+ */
909
+ syncPageMentions(pageName: string, content: string, ctx: ActorContext): Promise<void>;
910
+ /**
911
+ * #865 Slice 2: attachment health report — computed fresh on demand
912
+ * (admin-triggered; walks every page's content, a few seconds on large
913
+ * instances). Read-only. Trustworthy only after mentions reconciliation
914
+ * (run `npm run reconcile:mentions` / rely on save-time sync).
915
+ *
916
+ * Sections:
917
+ * - orphans: records no page references (empty mentions)
918
+ * - recordlessFiles: disk files with no metadata record
919
+ * - missingFiles: records whose storage file is gone from disk
920
+ * - brokenRefs: page markup references naming no record (ref → pages)
921
+ * - looseTextRefs: record filenames appearing in content OUTSIDE
922
+ * canonical markup (never tracked as mentions)
923
+ *
924
+ * #1460: the requester's OWN private-store files are merged into the record
925
+ * set, so one of their files is not reported as a broken reference merely
926
+ * because it is in no shared index. `recordlessFiles` and `missingFiles`
927
+ * stay shared-pool questions — they compare the shared index against the
928
+ * shared storage folder, which a store's files are not in.
929
+ *
930
+ * @param ctx - Whose report this is (#1179). Mandatory and positional; an
931
+ * admin sees their own stores merged, never anyone else's.
932
+ */
933
+ getHealthReport(ctx: ActorContext): Promise<{
934
+ totals: {
935
+ records: number;
936
+ diskFiles: number;
937
+ pagesScanned: number;
938
+ };
939
+ orphans: Array<{
940
+ identifier: string;
941
+ name?: string;
942
+ contentSize?: number;
943
+ dateCreated?: string;
944
+ author?: string;
945
+ }>;
946
+ recordlessFiles: string[];
947
+ missingFiles: Array<{
948
+ identifier: string;
949
+ name?: string;
950
+ storageLocation?: string;
951
+ }>;
952
+ brokenRefs: Array<{
953
+ ref: string;
954
+ pages: string[];
955
+ }>;
956
+ looseTextRefs: string[];
957
+ }>;
958
+ /**
959
+ * #865 Slice 3: guarded orphan cleanup — quarantine, never hard-delete.
960
+ *
961
+ * Recomputes the health report FRESH (never trusts a client-supplied list),
962
+ * then moves verified orphan records (+ their files) and recordless disk
963
+ * files into `<storage>/quarantine/`. Removed records are appended to a
964
+ * per-run manifest in the quarantine dir so the operation is reversible.
965
+ * `dryRun: true` returns exactly what WOULD move, touching nothing.
966
+ *
967
+ * #1460: only the SHARED POOL's orphans are selected. The quarantine folder
968
+ * is a shared directory, so moving a private-store file into it would carry
969
+ * it out of its store and put its name back in shared storage — the exact
970
+ * move this issue undoes. A store's own files are its owner's to delete,
971
+ * through `deleteAttachment`.
972
+ *
973
+ * @param ctx - Whose run this is (#1179). Mandatory and positional.
974
+ */
975
+ quarantineOrphans(options: {
976
+ dryRun: boolean;
977
+ includeOrphans: boolean;
978
+ includeRecordless: boolean;
979
+ }, ctx: ActorContext): Promise<{
980
+ dryRun: boolean;
981
+ orphansSelected: Array<{
982
+ identifier: string;
983
+ name?: string;
984
+ contentSize?: number;
985
+ }>;
986
+ recordlessSelected: string[];
987
+ quarantined: number;
988
+ skipped: number;
989
+ manifestPath: string | null;
990
+ }>;
991
+ /**
992
+ * Refresh attachment list (rescan storage)
993
+ *
994
+ * @returns {Promise<void>}
995
+ */
996
+ refreshAttachmentList(): Promise<void>;
997
+ /**
998
+ * Backup manager data
999
+ * Delegates to provider's backup method
1000
+ *
1001
+ * @returns {Promise<AttachmentBackupData>}
1002
+ */
1003
+ backup(): Promise<AttachmentBackupData>;
1004
+ /**
1005
+ * Restore manager data from backup
1006
+ * Delegates to provider's restore method
1007
+ *
1008
+ * @param {AttachmentBackupData} backupData - Backup data from backup() method
1009
+ * @returns {Promise<void>}
1010
+ */
1011
+ restore(backupData: AttachmentBackupData): Promise<void>;
1012
+ /**
1013
+ * Shutdown the manager
1014
+ * @returns {Promise<void>}
1015
+ */
1016
+ shutdown(): Promise<void>;
1017
+ /**
1018
+ * Normalize provider name to PascalCase class name
1019
+ * @param {string} providerName - Lowercase provider name (e.g., 'basicattachmentprovider')
1020
+ * @returns {string} PascalCase class name (e.g., 'BasicAttachmentProvider')
1021
+ * @private
1022
+ */
1023
+ private normalizeProviderName;
1024
+ /**
1025
+ * Format byte size to human-readable string
1026
+ * @param {number} bytes - Size in bytes
1027
+ * @returns {string} Formatted size (e.g., "10 MB")
1028
+ * @private
1029
+ */
1030
+ private formatSize;
1031
+ }
1032
+ export default AttachmentManager;