@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.
- package/LICENSE +201 -0
- package/README.md +16 -2
- package/lib/packages/ngdpbase-types/index.d.ts +32 -0
- package/lib/packages/ngdpbase-types/testing.d.ts +43 -0
- package/lib/packages/ngdpbase-types/testing.js +53 -0
- package/lib/src/cache/CacheDependencies.d.ts +50 -0
- package/lib/src/cache/CacheDependencies.js +50 -0
- package/lib/src/cache/ICacheAdapter.d.ts +86 -0
- package/lib/src/cache/RegionCache.d.ts +171 -0
- package/lib/src/context/ActorContext.d.ts +48 -0
- package/lib/src/context/ActorContext.js +33 -0
- package/lib/src/context/ApiContext.d.ts +194 -0
- package/lib/src/context/ApiContext.js +273 -0
- package/lib/src/context/BaseContext.d.ts +110 -0
- package/lib/src/context/BaseContext.js +143 -0
- package/lib/src/context/JobContext.d.ts +153 -0
- package/lib/src/context/JobContext.js +144 -0
- package/lib/src/context/WikiContext.d.ts +404 -0
- package/lib/src/context/bootActions.d.ts +64 -0
- package/lib/src/context/bootActions.js +111 -0
- package/lib/src/converters/HtmlConverter.d.ts +70 -0
- package/lib/src/converters/IContentConverter.d.ts +94 -0
- package/lib/src/converters/JSPWikiConverter.d.ts +117 -0
- package/lib/src/converters/conversionWarning.d.ts +15 -0
- package/lib/src/converters/ncm/bridge.d.ts +22 -0
- package/lib/src/converters/ncm/existing.d.ts +23 -0
- package/lib/src/converters/ncm/fix/blocks.d.ts +89 -0
- package/lib/src/converters/ncm/fix/bulletMarkers.d.ts +21 -0
- package/lib/src/converters/ncm/fix/index.d.ts +36 -0
- package/lib/src/converters/ncm/fix/jspwikiBullets.d.ts +20 -0
- package/lib/src/converters/ncm/fix/jspwikiCodeMarkers.d.ts +38 -0
- package/lib/src/converters/ncm/fix/jspwikiHeadings.d.ts +25 -0
- package/lib/src/converters/ncm/fix/jspwikiIndent.d.ts +24 -0
- package/lib/src/converters/ncm/fix/jspwikiInsert.d.ts +21 -0
- package/lib/src/converters/ncm/fix/jspwikiItalic.d.ts +29 -0
- package/lib/src/converters/ncm/fix/jspwikiLinkLeftovers.d.ts +27 -0
- package/lib/src/converters/ncm/fix/moreInformationFooter.d.ts +25 -0
- package/lib/src/converters/ncm/fix/styleClosers.d.ts +25 -0
- package/lib/src/converters/ncm/fix/tightenLists.d.ts +30 -0
- package/lib/src/converters/ncm/fix/types.d.ts +33 -0
- package/lib/src/converters/ncm/footnotes.d.ts +39 -0
- package/lib/src/converters/ncm/images.d.ts +49 -0
- package/lib/src/converters/ncm/index.d.ts +20 -0
- package/lib/src/converters/ncm/links.d.ts +21 -0
- package/lib/src/converters/ncm/normalize.d.ts +39 -0
- package/lib/src/converters/ncm/placeholder.d.ts +25 -0
- package/lib/src/converters/ncm/tables.d.ts +36 -0
- package/lib/src/converters/ncm/types.d.ts +42 -0
- package/lib/src/http/egressPolicy.d.ts +52 -0
- package/lib/src/http/guardedFetch.d.ts +89 -0
- package/lib/src/http/guardedFetch.js +113 -0
- package/lib/src/http/guardedLookup.d.ts +48 -0
- package/lib/src/http/guardedLookup.js +73 -0
- package/lib/src/http/ssrf.d.ts +83 -0
- package/lib/src/http/ssrf.js +311 -0
- package/lib/src/mail/MailProvider.d.ts +36 -0
- package/lib/src/mail/NodemailerMailProvider.d.ts +26 -0
- package/lib/src/managers/AddonsManager.d.ts +691 -0
- package/lib/src/managers/AgentTokenManager.d.ts +269 -0
- package/lib/src/managers/AssetManager.d.ts +116 -0
- package/lib/src/managers/AttachmentManager.d.ts +1032 -0
- package/lib/src/managers/AuthManager.d.ts +1257 -0
- package/lib/src/managers/BackgroundJobManager.d.ts +434 -0
- package/lib/src/managers/BaseManager.d.ts +427 -0
- package/lib/src/managers/BaseManager.js +415 -0
- package/lib/src/managers/CacheManager.d.ts +159 -0
- package/lib/src/managers/CatalogManager.d.ts +235 -0
- package/lib/src/managers/CommentManager.d.ts +75 -0
- package/lib/src/managers/ConfigurationManager.d.ts +747 -0
- package/lib/src/managers/DatabaseManager.d.ts +188 -0
- package/lib/src/managers/DatabaseManager.js +590 -0
- package/lib/src/managers/EmailManager.d.ts +47 -0
- package/lib/src/managers/ExportManager.d.ts +129 -0
- package/lib/src/managers/ExportManager.js +420 -0
- package/lib/src/managers/FootnoteManager.d.ts +118 -0
- package/lib/src/managers/MediaManager.d.ts +279 -0
- package/lib/src/managers/MetricsManager.d.ts +89 -0
- package/lib/src/managers/NotificationManager.d.ts +165 -0
- package/lib/src/managers/OidcManager.d.ts +210 -0
- package/lib/src/managers/OrganizationManager.d.ts +107 -0
- package/lib/src/managers/PageManager.d.ts +1645 -0
- package/lib/src/managers/PersonManager.d.ts +48 -0
- package/lib/src/managers/PluginManager.d.ts +179 -0
- package/lib/src/managers/PluginManager.js +393 -0
- package/lib/src/managers/PolicyEvaluator.d.ts +213 -0
- package/lib/src/managers/RenderingManager.d.ts +358 -0
- package/lib/src/managers/RoleManager.d.ts +134 -0
- package/lib/src/managers/SearchManager.d.ts +402 -0
- package/lib/src/managers/ShareManager.d.ts +251 -0
- package/lib/src/managers/TemplateManager.d.ts +176 -0
- package/lib/src/managers/ThemeManager.d.ts +56 -0
- package/lib/src/managers/UserManager.d.ts +480 -0
- package/lib/src/managers/ValidationManager.d.ts +426 -0
- package/lib/src/managers/VariableManager.d.ts +145 -0
- package/lib/src/middleware/csrf.d.ts +3 -0
- package/lib/src/parsers/LinkParser.d.ts +457 -0
- package/lib/src/parsers/MarkupParser.d.ts +769 -0
- package/lib/src/parsers/context/ParseContext.d.ts +314 -0
- package/lib/src/parsers/data/emoji-map.d.ts +18 -0
- package/lib/src/parsers/dom/DOMBuilder.d.ts +210 -0
- package/lib/src/parsers/dom/DOMParser.d.ts +252 -0
- package/lib/src/parsers/dom/Tokenizer.d.ts +358 -0
- package/lib/src/parsers/dom/WikiDocument.d.ts +272 -0
- package/lib/src/parsers/dom/handlers/DOMLinkHandler.d.ts +260 -0
- package/lib/src/parsers/dom/handlers/DOMPluginHandler.d.ts +212 -0
- package/lib/src/parsers/dom/handlers/DOMVariableHandler.d.ts +171 -0
- package/lib/src/parsers/filters/BaseFilter.d.ts +269 -0
- package/lib/src/parsers/filters/FilterChain.d.ts +320 -0
- package/lib/src/parsers/handlers/BaseSyntaxHandler.d.ts +331 -0
- package/lib/src/parsers/handlers/HandlerRegistry.d.ts +225 -0
- package/lib/src/parsers/handlers/JSPWikiPreprocessor.d.ts +89 -0
- package/lib/src/parsers/handlers/LinkParserHandler.d.ts +80 -0
- package/lib/src/parsers/handlers/PluginSyntaxHandler.d.ts +78 -0
- package/lib/src/parsers/handlers/WikiFormHandler.d.ts +149 -0
- package/lib/src/parsers/handlers/WikiTagHandler.d.ts +125 -0
- package/lib/src/parsers/jspwikiTableRow.d.ts +39 -0
- package/lib/src/parsers/styleBlockSyntax.d.ts +14 -0
- package/lib/src/plugins/types.d.ts +79 -0
- package/lib/src/providers/AgentTokenAuthProvider.d.ts +40 -0
- package/lib/src/providers/AuthentikBearerAuthProvider.d.ts +75 -0
- package/lib/src/providers/BaseAttachmentProvider.d.ts +197 -0
- package/lib/src/providers/BaseAuthProvider.d.ts +220 -0
- package/lib/src/providers/BaseCacheProvider.d.ts +140 -0
- package/lib/src/providers/BaseCredentialsProvider.d.ts +84 -0
- package/lib/src/providers/BaseDatabaseProvider.d.ts +22 -0
- package/lib/src/providers/BaseDatabaseProvider.js +12 -0
- package/lib/src/providers/BaseLoggingProvider.d.ts +68 -0
- package/lib/src/providers/BaseLoggingProvider.js +37 -0
- package/lib/src/providers/BaseMediaProvider.d.ts +308 -0
- package/lib/src/providers/BasePageProvider.d.ts +337 -0
- package/lib/src/providers/BaseProvider.d.ts +98 -0
- package/lib/src/providers/BaseProvider.js +74 -0
- package/lib/src/providers/BaseSearchProvider.d.ts +362 -0
- package/lib/src/providers/BasicAttachmentProvider.d.ts +599 -0
- package/lib/src/providers/CloudflareAccessAuthProvider.d.ts +72 -0
- package/lib/src/providers/FileCredentialsProvider.d.ts +33 -0
- package/lib/src/providers/FileJobStateProvider.d.ts +58 -0
- package/lib/src/providers/FileLoggingProvider.d.ts +43 -0
- package/lib/src/providers/FileLoggingProvider.js +120 -0
- package/lib/src/providers/FileOidcAdapter.d.ts +25 -0
- package/lib/src/providers/FileSystemMediaProvider.d.ts +403 -0
- package/lib/src/providers/LunrSearchProvider.d.ts +280 -0
- package/lib/src/providers/MagicLinkAuthProvider.d.ts +125 -0
- package/lib/src/providers/NullCacheProvider.d.ts +72 -0
- package/lib/src/providers/OidcAuthProvider.d.ts +180 -0
- package/lib/src/providers/OidcBearerAuthProvider.d.ts +30 -0
- package/lib/src/providers/PasskeyAuthProvider.d.ts +58 -0
- package/lib/src/providers/PasswordAuthProvider.d.ts +20 -0
- package/lib/src/providers/SqliteDatabaseProvider.d.ts +55 -0
- package/lib/src/providers/SqliteDatabaseProvider.js +90 -0
- package/lib/src/providers/SqliteJobStateProvider.d.ts +41 -0
- package/lib/src/providers/databaseMigrations.d.ts +8 -0
- package/lib/src/providers/databaseMigrations.js +47 -0
- package/lib/src/providers/jobState.d.ts +99 -0
- package/lib/src/providers/lunrQueryToMiniSearch.d.ts +32 -0
- package/lib/src/providers/mediaFilenameDate.d.ts +22 -0
- package/lib/src/providers/sqliteBackup.d.ts +128 -0
- package/lib/src/providers/sqliteBackup.js +365 -0
- package/lib/src/providers/sqliteLocation.d.ts +17 -0
- package/lib/src/providers/sqliteLocation.js +55 -0
- package/lib/src/providers/sqliteMigrations.d.ts +48 -0
- package/lib/src/providers/sqliteMigrations.js +72 -0
- package/lib/src/rendering/githubAlerts.d.ts +22 -0
- package/lib/src/rendering/htmlPolicy.d.ts +76 -0
- package/lib/src/rendering/markdownConverter.d.ts +73 -0
- package/lib/src/security/PolicyDecisionPoint.d.ts +245 -0
- package/lib/src/security/PolicyInformationPoint.d.ts +448 -0
- package/lib/src/security/pageActions.d.ts +40 -0
- package/lib/src/security/permissions.generated.d.ts +78 -0
- package/lib/src/types/Asset.d.ts +414 -0
- package/lib/src/types/Catalog.d.ts +61 -0
- package/lib/src/types/Comment.d.ts +11 -0
- package/lib/src/types/Config.d.ts +388 -0
- package/lib/src/types/Organization.d.ts +78 -0
- package/lib/src/types/OrganizationProvider.d.ts +38 -0
- package/lib/src/types/Page.d.ts +220 -0
- package/lib/src/types/Person.d.ts +56 -0
- package/lib/src/types/PersonProvider.d.ts +25 -0
- package/lib/src/types/Policy.d.ts +139 -0
- package/lib/src/types/Policy.js +17 -0
- package/lib/src/types/Provider.d.ts +810 -0
- package/lib/src/types/Role.d.ts +84 -0
- package/lib/src/types/RoleProvider.d.ts +35 -0
- package/lib/src/types/Schema.d.ts +425 -0
- package/lib/src/types/Share.d.ts +172 -0
- package/lib/src/types/Share.js +81 -0
- package/lib/src/types/User.d.ts +304 -0
- package/lib/src/types/Version.d.ts +189 -0
- package/lib/src/types/WikiEngine.d.ts +128 -0
- package/lib/src/types/express.d.ts +120 -0
- package/lib/src/types/express.js +1 -0
- package/lib/src/types/guards.d.ts +78 -0
- package/lib/src/types/heic-decode.d.ts +16 -0
- package/lib/src/types/index.d.ts +19 -0
- package/lib/src/types/linkedom.d.ts +77 -0
- package/lib/src/types/markdown-it-plugins.d.ts +21 -0
- package/lib/src/utils/DeltaStorage.d.ts +118 -0
- package/lib/src/utils/LocaleUtils.d.ts +105 -0
- package/lib/src/utils/LocaleUtils.js +294 -0
- package/lib/src/utils/PageNameMatcher.d.ts +98 -0
- package/lib/src/utils/PathPreflight.d.ts +38 -0
- package/lib/src/utils/PathPreflight.js +50 -0
- package/lib/src/utils/SectionUtils.d.ts +40 -0
- package/lib/src/utils/addonConfigLayer.d.ts +144 -0
- package/lib/src/utils/addonConfigLayer.js +382 -0
- package/lib/src/utils/addonDatabaseRules.d.ts +25 -0
- package/lib/src/utils/addonDatabaseRules.js +57 -0
- package/lib/src/utils/addonHost.d.ts +51 -0
- package/lib/src/utils/addonHost.js +72 -0
- package/lib/src/utils/addonInstaller.d.ts +109 -0
- package/lib/src/utils/addonLock.d.ts +37 -0
- package/lib/src/utils/addonLock.js +48 -0
- package/lib/src/utils/addonPageSync.d.ts +45 -0
- package/lib/src/utils/addonProvenance.d.ts +48 -0
- package/lib/src/utils/addonTarball.d.ts +41 -0
- package/lib/src/utils/addonsPathResolver.d.ts +76 -0
- package/lib/src/utils/addonsPathResolver.js +129 -0
- package/lib/src/utils/assetMetadataTags.d.ts +66 -0
- package/lib/src/utils/atomicWrite.d.ts +28 -0
- package/lib/src/utils/auditConfigChange.d.ts +57 -0
- package/lib/src/utils/auditEventNames.d.ts +50 -0
- package/lib/src/utils/auditEventNames.generated.d.ts +169 -0
- package/lib/src/utils/auditEventNames.generated.js +174 -0
- package/lib/src/utils/auditEventNames.js +49 -0
- package/lib/src/utils/auditEvents.d.ts +265 -0
- package/lib/src/utils/auditEvents.js +309 -0
- package/lib/src/utils/auditRegistry.d.ts +102 -0
- package/lib/src/utils/auditRegistry.js +168 -0
- package/lib/src/utils/bip39English.d.ts +2 -0
- package/lib/src/utils/configEnvKeys.d.ts +68 -0
- package/lib/src/utils/configFiles.d.ts +74 -0
- package/lib/src/utils/configFiles.js +150 -0
- package/lib/src/utils/delegation.d.ts +48 -0
- package/lib/src/utils/deriveUsername.d.ts +21 -0
- package/lib/src/utils/explainMediaPath.d.ts +123 -0
- package/lib/src/utils/formerTitles.d.ts +69 -0
- package/lib/src/utils/frontmatterAccess.d.ts +54 -0
- package/lib/src/utils/headlessAdminPassword.d.ts +55 -0
- package/lib/src/utils/imageTransform.d.ts +52 -0
- package/lib/src/utils/instanceEnvSecret.d.ts +51 -0
- package/lib/src/utils/jobSlots.d.ts +43 -0
- package/lib/src/utils/keywordNormalizer.d.ts +127 -0
- package/lib/src/utils/logger.d.ts +70 -0
- package/lib/src/utils/logger.js +106 -0
- package/lib/src/utils/magicLinkDeviceState.d.ts +95 -0
- package/lib/src/utils/managerUtils.d.ts +40 -0
- package/lib/src/utils/migrateLegacyPrivateAttachments.d.ts +15 -0
- package/lib/src/utils/orgFilename.d.ts +22 -0
- package/lib/src/utils/pageFeature.d.ts +27 -0
- package/lib/src/utils/pageFrontmatter.d.ts +21 -0
- package/lib/src/utils/pageNotes.d.ts +150 -0
- package/lib/src/utils/pageTitleRule.d.ts +37 -0
- package/lib/src/utils/pageToArticle.d.ts +59 -0
- package/lib/src/utils/pageUrl.d.ts +18 -0
- package/lib/src/utils/passwordChange.d.ts +12 -0
- package/lib/src/utils/passwordHash.d.ts +60 -0
- package/lib/src/utils/permissionCatalog.d.ts +52 -0
- package/lib/src/utils/pluginFormatters.d.ts +452 -0
- package/lib/src/utils/pluginFormatters.js +714 -0
- package/lib/src/utils/privateLinkRewrite.d.ts +42 -0
- package/lib/src/utils/privateStoreAccess.d.ts +57 -0
- package/lib/src/utils/privateStoreAccess.js +65 -0
- package/lib/src/utils/privateStoreCatalogs.d.ts +40 -0
- package/lib/src/utils/privateStoreCrypto.d.ts +127 -0
- package/lib/src/utils/privateStoreDoor.d.ts +181 -0
- package/lib/src/utils/privateStoreExport.d.ts +72 -0
- package/lib/src/utils/privateStoreFiles.d.ts +120 -0
- package/lib/src/utils/privateStoreMeta.d.ts +64 -0
- package/lib/src/utils/privateStoreMigrations.d.ts +37 -0
- package/lib/src/utils/privateStorePath.d.ts +259 -0
- package/lib/src/utils/privateStorePath.js +436 -0
- package/lib/src/utils/privateStoreTakeout.d.ts +76 -0
- package/lib/src/utils/privateStoreUnlock.d.ts +175 -0
- package/lib/src/utils/proxyClaim.d.ts +59 -0
- package/lib/src/utils/proxyClaim.js +30 -0
- package/lib/src/utils/redactPrivateNames.d.ts +21 -0
- package/lib/src/utils/redactPrivateNames.js +89 -0
- package/lib/src/utils/redactSecrets.d.ts +58 -0
- package/lib/src/utils/redactSecrets.js +171 -0
- package/lib/src/utils/renameLinkRewrite.d.ts +112 -0
- package/lib/src/utils/roleGrants.d.ts +35 -0
- package/lib/src/utils/safeRedirect.d.ts +32 -0
- package/lib/src/utils/schedule.d.ts +54 -0
- package/lib/src/utils/secretFileMode.d.ts +17 -0
- package/lib/src/utils/seededShippedPages.d.ts +45 -0
- package/lib/src/utils/sensitiveValues.d.ts +59 -0
- package/lib/src/utils/sensitiveValues.js +106 -0
- package/lib/src/utils/sessionEnd.d.ts +12 -0
- package/lib/src/utils/sessionGeneration.d.ts +24 -0
- package/lib/src/utils/sessionIdle.d.ts +41 -0
- package/lib/src/utils/sessionLimits.d.ts +68 -0
- package/lib/src/utils/shareLockbox.d.ts +64 -0
- package/lib/src/utils/sigstoreTrustedRoot.d.ts +33 -0
- package/lib/src/utils/sniffMime.d.ts +21 -0
- package/lib/src/utils/storeSearchIndex.d.ts +75 -0
- package/lib/src/utils/subjectMayDo.d.ts +21 -0
- package/lib/src/utils/systemCategoryRules.d.ts +30 -0
- package/lib/src/utils/systemCategoryRules.js +41 -0
- package/lib/src/utils/userCreateError.d.ts +62 -0
- package/lib/src/utils/username.d.ts +53 -0
- package/lib/src/utils/vaultUrlRewrite.d.ts +27 -0
- package/lib/src/utils/version.d.ts +84 -0
- package/lib/src/utils/videoFrame.d.ts +21 -0
- 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>`/`` 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 (``); 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;
|