@memberjunction/archiving-engine 0.0.1 → 5.29.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.
@@ -0,0 +1,47 @@
1
+ import { BaseEntity, UserInfo } from '@memberjunction/core';
2
+ import { RestoreRecordResult } from './types.js';
3
+ /**
4
+ * Provides recovery operations for archived records, including listing
5
+ * archived versions and restoring specific versions.
6
+ */
7
+ export declare class ArchiveRecovery {
8
+ /**
9
+ * Retrieves all archived versions for a specific entity record.
10
+ * Queries the ArchiveRunDetail table for matching records.
11
+ *
12
+ * @param entityName - The name of the entity
13
+ * @param recordId - The primary key value of the record
14
+ * @param contextUser - User context for database access
15
+ * @returns Array of ArchiveRunDetail records, ordered by most recent first
16
+ */
17
+ GetArchivedVersions(entityName: string, recordId: string, contextUser: UserInfo): Promise<BaseEntity[]>;
18
+ /**
19
+ * Restores a specific archived version of a record.
20
+ * Loads the ArchiveRunDetail, initializes the storage driver,
21
+ * reads the archive document, and applies the values back to the record.
22
+ *
23
+ * @param archiveRunDetailId - ID of the ArchiveRunDetail record to restore
24
+ * @param contextUser - User context for database and storage access
25
+ * @returns Result indicating success/failure and which fields were restored
26
+ */
27
+ RestoreVersion(archiveRunDetailId: string, contextUser: UserInfo): Promise<RestoreRecordResult>;
28
+ /**
29
+ * Loads a single ArchiveRunDetail record by ID.
30
+ */
31
+ private LoadArchiveRunDetail;
32
+ /**
33
+ * Loads a single ArchiveRun record by ID.
34
+ */
35
+ private LoadArchiveRun;
36
+ /**
37
+ * Initializes a storage driver from the ArchiveRun's associated configuration.
38
+ */
39
+ private InitializeStorageDriver;
40
+ /**
41
+ * Returns the DefaultArchiveDriver for restore operations.
42
+ * ArchiveRunDetail does not store the driver class used during archiving;
43
+ * the default driver handles the standard JSON-based restore path.
44
+ */
45
+ private ResolveDriver;
46
+ }
47
+ //# sourceMappingURL=ArchiveRecovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArchiveRecovery.d.ts","sourceRoot":"","sources":["../src/ArchiveRecovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAwD,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAKlH,OAAO,EAAwB,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEpE;;;GAGG;AACH,qBAAa,eAAe;IACxB;;;;;;;;OAQG;IACU,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAiBpH;;;;;;;;OAQG;IACU,cAAc,CAAC,kBAAkB,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAmC5G;;OAEG;YACW,oBAAoB;IAOlC;;OAEG;YACW,cAAc;IAO5B;;OAEG;YACW,uBAAuB;IA4BrC;;;;OAIG;IACH,OAAO,CAAC,aAAa;CAGxB"}
@@ -0,0 +1,125 @@
1
+ import { CompositeKey, LogError, LogStatus, Metadata, RunView } from '@memberjunction/core';
2
+ import { FileStorageEngineBase } from '@memberjunction/core-entities';
3
+ import { initializeDriverWithAccountCredentials } from '@memberjunction/storage';
4
+ import { DefaultArchiveDriver } from './DefaultArchiveDriver.js';
5
+ /**
6
+ * Provides recovery operations for archived records, including listing
7
+ * archived versions and restoring specific versions.
8
+ */
9
+ export class ArchiveRecovery {
10
+ /**
11
+ * Retrieves all archived versions for a specific entity record.
12
+ * Queries the ArchiveRunDetail table for matching records.
13
+ *
14
+ * @param entityName - The name of the entity
15
+ * @param recordId - The primary key value of the record
16
+ * @param contextUser - User context for database access
17
+ * @returns Array of ArchiveRunDetail records, ordered by most recent first
18
+ */
19
+ async GetArchivedVersions(entityName, recordId, contextUser) {
20
+ const rv = new RunView();
21
+ const result = await rv.RunView({
22
+ EntityName: 'MJ: Archive Run Details',
23
+ ExtraFilter: `Entity='${entityName}' AND RecordID='${recordId}' AND Status='Success'`,
24
+ OrderBy: '__mj_CreatedAt DESC',
25
+ ResultType: 'entity_object',
26
+ }, contextUser);
27
+ if (!result.Success) {
28
+ LogError(`Failed to load archived versions for ${entityName}/${recordId}: ${result.ErrorMessage}`);
29
+ return [];
30
+ }
31
+ return result.Results;
32
+ }
33
+ /**
34
+ * Restores a specific archived version of a record.
35
+ * Loads the ArchiveRunDetail, initializes the storage driver,
36
+ * reads the archive document, and applies the values back to the record.
37
+ *
38
+ * @param archiveRunDetailId - ID of the ArchiveRunDetail record to restore
39
+ * @param contextUser - User context for database and storage access
40
+ * @returns Result indicating success/failure and which fields were restored
41
+ */
42
+ async RestoreVersion(archiveRunDetailId, contextUser) {
43
+ try {
44
+ const detail = await this.LoadArchiveRunDetail(archiveRunDetailId, contextUser);
45
+ if (!detail) {
46
+ return { Success: false, ErrorMessage: `ArchiveRunDetail not found: ${archiveRunDetailId}`, RestoredFields: [] };
47
+ }
48
+ const archiveRun = await this.LoadArchiveRun(detail.Get('ArchiveRunID'), contextUser);
49
+ if (!archiveRun) {
50
+ return { Success: false, ErrorMessage: 'Failed to load parent ArchiveRun', RestoredFields: [] };
51
+ }
52
+ const storageDriver = await this.InitializeStorageDriver(archiveRun, contextUser);
53
+ const driver = this.ResolveDriver();
54
+ const restoreContext = {
55
+ ArchiveRunDetail: detail,
56
+ StorageDriver: storageDriver,
57
+ ContextUser: contextUser,
58
+ };
59
+ const result = await driver.RestoreRecord(restoreContext);
60
+ LogStatus(`RestoreVersion completed for detail ${archiveRunDetailId}: success=${result.Success}`);
61
+ return result;
62
+ }
63
+ catch (error) {
64
+ const message = error instanceof Error ? error.message : String(error);
65
+ LogError(`RestoreVersion failed for detail ${archiveRunDetailId}: ${message}`);
66
+ return { Success: false, ErrorMessage: message, RestoredFields: [] };
67
+ }
68
+ }
69
+ // ========================================
70
+ // Private Helpers
71
+ // ========================================
72
+ /**
73
+ * Loads a single ArchiveRunDetail record by ID.
74
+ */
75
+ async LoadArchiveRunDetail(detailId, contextUser) {
76
+ const md = new Metadata();
77
+ const detail = await md.GetEntityObject('MJ: Archive Run Details', contextUser);
78
+ const loaded = await detail.InnerLoad(CompositeKey.FromKeyValuePair('ID', detailId));
79
+ return loaded ? detail : null;
80
+ }
81
+ /**
82
+ * Loads a single ArchiveRun record by ID.
83
+ */
84
+ async LoadArchiveRun(archiveRunId, contextUser) {
85
+ const md = new Metadata();
86
+ const run = await md.GetEntityObject('MJ: Archive Runs', contextUser);
87
+ const loaded = await run.InnerLoad(CompositeKey.FromKeyValuePair('ID', archiveRunId));
88
+ return loaded ? run : null;
89
+ }
90
+ /**
91
+ * Initializes a storage driver from the ArchiveRun's associated configuration.
92
+ */
93
+ async InitializeStorageDriver(archiveRun, contextUser) {
94
+ const configId = archiveRun.Get('ArchiveConfigurationID');
95
+ const md = new Metadata();
96
+ const config = await md.GetEntityObject('MJ: Archive Configurations', contextUser);
97
+ const loaded = await config.InnerLoad(CompositeKey.FromKeyValuePair('ID', configId));
98
+ if (!loaded) {
99
+ throw new Error(`ArchiveConfiguration not found: ${configId}`);
100
+ }
101
+ const storageAccountId = config.Get('StorageAccountID');
102
+ if (!storageAccountId) {
103
+ throw new Error(`No StorageAccountID configured on ArchiveConfiguration: ${configId}`);
104
+ }
105
+ await FileStorageEngineBase.Instance.Config(false, contextUser);
106
+ const accountWithProvider = FileStorageEngineBase.Instance.GetAccountWithProvider(storageAccountId);
107
+ if (!accountWithProvider) {
108
+ throw new Error(`File storage account not found or provider inactive for ID: ${storageAccountId}`);
109
+ }
110
+ return initializeDriverWithAccountCredentials({
111
+ accountEntity: accountWithProvider.account,
112
+ providerEntity: accountWithProvider.provider,
113
+ contextUser,
114
+ });
115
+ }
116
+ /**
117
+ * Returns the DefaultArchiveDriver for restore operations.
118
+ * ArchiveRunDetail does not store the driver class used during archiving;
119
+ * the default driver handles the standard JSON-based restore path.
120
+ */
121
+ ResolveDriver() {
122
+ return new DefaultArchiveDriver();
123
+ }
124
+ }
125
+ //# sourceMappingURL=ArchiveRecovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArchiveRecovery.js","sourceRoot":"","sources":["../src/ArchiveRecovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { UserInfo } from '@memberjunction/core';
2
+ import { FileStorageBase } from '@memberjunction/storage';
3
+ import { ArchiveDocument } from './types.js';
4
+ /**
5
+ * Manages the lifecycle of a storage driver for archive operations,
6
+ * including initialization from a FileStorageAccount and read/write
7
+ * of archive documents.
8
+ */
9
+ export declare class ArchiveStorageManager {
10
+ private _driver;
11
+ private _accountId;
12
+ /**
13
+ * Returns the initialized storage driver, or throws if not yet initialized.
14
+ */
15
+ get Driver(): FileStorageBase;
16
+ /**
17
+ * Initializes the storage driver for the given FileStorageAccount.
18
+ * Loads the account and provider from the FileStorageEngineBase cache,
19
+ * then creates and initializes the appropriate driver via ClassFactory.
20
+ *
21
+ * @param storageAccountId - ID of the MJ: File Storage Account to use
22
+ * @param contextUser - User context for credential resolution
23
+ */
24
+ Initialize(storageAccountId: string, contextUser: UserInfo): Promise<void>;
25
+ /**
26
+ * Serializes and writes an archive document to storage.
27
+ *
28
+ * @param basePath - Configured base path prefix
29
+ * @param entityName - Entity name for path building
30
+ * @param recordId - Record primary key value for path building
31
+ * @param versionStamp - Timestamp for this archive version
32
+ * @param document - The archive document to write
33
+ * @returns The storage path and bytes written
34
+ */
35
+ WriteArchiveDocument(basePath: string, entityName: string, recordId: string, versionStamp: Date, document: ArchiveDocument): Promise<{
36
+ storagePath: string;
37
+ bytesWritten: number;
38
+ }>;
39
+ /**
40
+ * Reads and parses an archive document from storage.
41
+ *
42
+ * @param storagePath - Full path to the archive document in storage
43
+ * @returns The parsed archive document
44
+ */
45
+ ReadArchiveDocument(storagePath: string): Promise<ArchiveDocument>;
46
+ /**
47
+ * Builds a storage path for an archive document.
48
+ * Format: `{basePath}/{SanitizedEntityName}/{RecordID}/{VersionStamp}.json`
49
+ */
50
+ BuildStoragePath(basePath: string, entityName: string, recordId: string, versionStamp: Date): string;
51
+ /**
52
+ * Replaces characters that are problematic in storage paths with underscores.
53
+ */
54
+ SanitizeEntityName(name: string): string;
55
+ /**
56
+ * Formats a Date as an ISO 8601 string safe for use in file paths.
57
+ */
58
+ FormatVersionStamp(date: Date): string;
59
+ }
60
+ //# sourceMappingURL=ArchiveStorageManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArchiveStorageManager.d.ts","sourceRoot":"","sources":["../src/ArchiveStorageManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAA0C,MAAM,yBAAyB,CAAC;AAElG,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C;;;;GAIG;AACH,qBAAa,qBAAqB;IAC9B,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,UAAU,CAAuB;IAEzC;;OAEG;IACH,IAAW,MAAM,IAAI,eAAe,CAKnC;IAED;;;;;;;OAOG;IACU,UAAU,CAAC,gBAAgB,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBvF;;;;;;;;;OASG;IACU,oBAAoB,CAC7B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,IAAI,EAClB,QAAQ,EAAE,eAAe,GAC1B,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAazD;;;;;OAKG;IACU,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAM/E;;;OAGG;IACI,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,GAAG,MAAM;IAQ3G;;OAEG;IACI,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI/C;;OAEG;IACI,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;CAGhD"}
@@ -0,0 +1,101 @@
1
+ import { LogStatus } from '@memberjunction/core';
2
+ import { initializeDriverWithAccountCredentials } from '@memberjunction/storage';
3
+ import { FileStorageEngineBase } from '@memberjunction/core-entities';
4
+ /**
5
+ * Manages the lifecycle of a storage driver for archive operations,
6
+ * including initialization from a FileStorageAccount and read/write
7
+ * of archive documents.
8
+ */
9
+ export class ArchiveStorageManager {
10
+ constructor() {
11
+ this._driver = null;
12
+ this._accountId = null;
13
+ }
14
+ /**
15
+ * Returns the initialized storage driver, or throws if not yet initialized.
16
+ */
17
+ get Driver() {
18
+ if (!this._driver) {
19
+ throw new Error('ArchiveStorageManager has not been initialized. Call Initialize() first.');
20
+ }
21
+ return this._driver;
22
+ }
23
+ /**
24
+ * Initializes the storage driver for the given FileStorageAccount.
25
+ * Loads the account and provider from the FileStorageEngineBase cache,
26
+ * then creates and initializes the appropriate driver via ClassFactory.
27
+ *
28
+ * @param storageAccountId - ID of the MJ: File Storage Account to use
29
+ * @param contextUser - User context for credential resolution
30
+ */
31
+ async Initialize(storageAccountId, contextUser) {
32
+ this._accountId = storageAccountId;
33
+ await FileStorageEngineBase.Instance.Config(false, contextUser);
34
+ const accountWithProvider = FileStorageEngineBase.Instance.GetAccountWithProvider(storageAccountId);
35
+ if (!accountWithProvider) {
36
+ throw new Error(`File storage account not found or provider inactive for ID: ${storageAccountId}`);
37
+ }
38
+ const { account, provider } = accountWithProvider;
39
+ LogStatus(`Initializing archive storage driver for account "${account.Name}" (provider: ${provider.Name})`);
40
+ this._driver = await initializeDriverWithAccountCredentials({
41
+ accountEntity: account,
42
+ providerEntity: provider,
43
+ contextUser,
44
+ });
45
+ }
46
+ /**
47
+ * Serializes and writes an archive document to storage.
48
+ *
49
+ * @param basePath - Configured base path prefix
50
+ * @param entityName - Entity name for path building
51
+ * @param recordId - Record primary key value for path building
52
+ * @param versionStamp - Timestamp for this archive version
53
+ * @param document - The archive document to write
54
+ * @returns The storage path and bytes written
55
+ */
56
+ async WriteArchiveDocument(basePath, entityName, recordId, versionStamp, document) {
57
+ const storagePath = this.BuildStoragePath(basePath, entityName, recordId, versionStamp);
58
+ const jsonContent = JSON.stringify(document, null, 2);
59
+ const buffer = Buffer.from(jsonContent, 'utf8');
60
+ const success = await this.Driver.PutObject(storagePath, buffer, 'application/json');
61
+ if (!success) {
62
+ throw new Error(`Failed to write archive document to storage: ${storagePath}`);
63
+ }
64
+ return { storagePath, bytesWritten: buffer.byteLength };
65
+ }
66
+ /**
67
+ * Reads and parses an archive document from storage.
68
+ *
69
+ * @param storagePath - Full path to the archive document in storage
70
+ * @returns The parsed archive document
71
+ */
72
+ async ReadArchiveDocument(storagePath) {
73
+ const buffer = await this.Driver.GetObject({ fullPath: storagePath });
74
+ const jsonContent = buffer.toString('utf8');
75
+ return JSON.parse(jsonContent);
76
+ }
77
+ /**
78
+ * Builds a storage path for an archive document.
79
+ * Format: `{basePath}/{SanitizedEntityName}/{RecordID}/{VersionStamp}.json`
80
+ */
81
+ BuildStoragePath(basePath, entityName, recordId, versionStamp) {
82
+ const sanitizedEntity = this.SanitizeEntityName(entityName);
83
+ const sanitizedRecordId = this.SanitizeEntityName(recordId);
84
+ const formattedStamp = this.FormatVersionStamp(versionStamp);
85
+ const prefix = basePath ? `${basePath}/` : '';
86
+ return `${prefix}${sanitizedEntity}/${sanitizedRecordId}/${formattedStamp}.json`;
87
+ }
88
+ /**
89
+ * Replaces characters that are problematic in storage paths with underscores.
90
+ */
91
+ SanitizeEntityName(name) {
92
+ return name.replace(/[\s:\/\\]/g, '_');
93
+ }
94
+ /**
95
+ * Formats a Date as an ISO 8601 string safe for use in file paths.
96
+ */
97
+ FormatVersionStamp(date) {
98
+ return date.toISOString().replace(/:/g, '_');
99
+ }
100
+ }
101
+ //# sourceMappingURL=ArchiveStorageManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArchiveStorageManager.js","sourceRoot":"","sources":["../src/ArchiveStorageManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import { BaseEntity } from '@memberjunction/core';
2
+ import { ArchiveRecordContext, ArchiveRecordResult, RestoreRecordContext, RestoreRecordResult, ArchiveDocument, ArchivePrimaryKeyField } from './types.js';
3
+ /**
4
+ * Abstract base class for archive drivers. Concrete implementations handle
5
+ * the specifics of how records are archived and restored.
6
+ *
7
+ * Use `@RegisterClass(BaseArchiveDriver, 'YourDriverName')` on concrete subclasses
8
+ * to make them discoverable via the MJ ClassFactory.
9
+ */
10
+ export declare abstract class BaseArchiveDriver {
11
+ /**
12
+ * Determines whether a given record should be archived based on its current field values.
13
+ * @param context - The archive context including record, field config, etc.
14
+ * @returns True if the record should be archived, false to skip it
15
+ */
16
+ abstract ShouldArchiveRecord(context: ArchiveRecordContext): boolean;
17
+ /**
18
+ * Archives a single record: writes the archive document to storage and
19
+ * optionally nullifies the archived fields on the source record.
20
+ * @param context - The archive context including record, storage driver, etc.
21
+ * @returns Result indicating success/failure and storage details
22
+ */
23
+ abstract ArchiveRecord(context: ArchiveRecordContext): Promise<ArchiveRecordResult>;
24
+ /**
25
+ * Restores a previously archived record by reading the archive document
26
+ * from storage and setting the field values back on the source record.
27
+ * @param context - The restore context including the ArchiveRunDetail record
28
+ * @returns Result indicating success/failure and which fields were restored
29
+ */
30
+ abstract RestoreRecord(context: RestoreRecordContext): Promise<RestoreRecordResult>;
31
+ /**
32
+ * Builds a storage path for an archive document.
33
+ * Format: `{basePath}/{SanitizedEntityName}/{RecordID}/{VersionStamp}.json`
34
+ * @param basePath - The configured base path prefix
35
+ * @param entityName - The entity name (will be sanitized)
36
+ * @param recordId - The primary key value of the record
37
+ * @param versionStamp - The timestamp for this archive version
38
+ * @returns The full storage path string
39
+ */
40
+ protected BuildStoragePath(basePath: string, entityName: string, recordId: string, versionStamp: Date): string;
41
+ /**
42
+ * Builds the ArchiveDocument JSON structure from a record context.
43
+ * @param context - The archive context
44
+ * @param versionStamp - The timestamp for this version
45
+ * @returns A fully populated ArchiveDocument
46
+ */
47
+ protected BuildArchiveDocument(context: ArchiveRecordContext, versionStamp: Date): ArchiveDocument;
48
+ /**
49
+ * Extracts the values of fields configured for archiving from the record.
50
+ */
51
+ protected ExtractArchivedFields(context: ArchiveRecordContext): Record<string, unknown>;
52
+ /**
53
+ * Extracts a full record snapshot if configured, otherwise returns null.
54
+ */
55
+ protected ExtractFullRecord(context: ArchiveRecordContext): Record<string, unknown> | null;
56
+ /**
57
+ * Extracts the primary key fields and values from a BaseEntity record.
58
+ */
59
+ protected ExtractPrimaryKey(record: BaseEntity): ArchivePrimaryKeyField[];
60
+ /**
61
+ * Sanitizes a string for use as a storage path segment by replacing
62
+ * spaces, colons, and other problematic characters with underscores.
63
+ */
64
+ protected SanitizePathSegment(value: string): string;
65
+ /**
66
+ * Formats a Date as an ISO 8601 string safe for use in file paths.
67
+ * Colons are replaced with underscores.
68
+ */
69
+ protected FormatVersionStamp(date: Date): string;
70
+ }
71
+ //# sourceMappingURL=BaseArchiveDriver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseArchiveDriver.d.ts","sourceRoot":"","sources":["../src/BaseArchiveDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EACH,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,sBAAsB,EACzB,MAAM,SAAS,CAAC;AAEjB;;;;;;GAMG;AACH,8BAAsB,iBAAiB;IACnC;;;;OAIG;aACa,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO;IAE3E;;;;;OAKG;aACa,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAE1F;;;;;OAKG;aACa,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAM1F;;;;;;;;OAQG;IACH,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,GAAG,MAAM;IAQ9G;;;;;OAKG;IACH,SAAS,CAAC,oBAAoB,CAAC,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,IAAI,GAAG,eAAe;IAsBlG;;OAEG;IACH,SAAS,CAAC,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAUvF;;OAEG;IACH,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAO1F;;OAEG;IACH,SAAS,CAAC,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,sBAAsB,EAAE;IAOzE;;;OAGG;IACH,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAIpD;;;OAGG;IACH,SAAS,CAAC,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;CAGnD"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Abstract base class for archive drivers. Concrete implementations handle
3
+ * the specifics of how records are archived and restored.
4
+ *
5
+ * Use `@RegisterClass(BaseArchiveDriver, 'YourDriverName')` on concrete subclasses
6
+ * to make them discoverable via the MJ ClassFactory.
7
+ */
8
+ export class BaseArchiveDriver {
9
+ // ========================================
10
+ // Protected Helpers
11
+ // ========================================
12
+ /**
13
+ * Builds a storage path for an archive document.
14
+ * Format: `{basePath}/{SanitizedEntityName}/{RecordID}/{VersionStamp}.json`
15
+ * @param basePath - The configured base path prefix
16
+ * @param entityName - The entity name (will be sanitized)
17
+ * @param recordId - The primary key value of the record
18
+ * @param versionStamp - The timestamp for this archive version
19
+ * @returns The full storage path string
20
+ */
21
+ BuildStoragePath(basePath, entityName, recordId, versionStamp) {
22
+ const sanitizedEntity = this.SanitizePathSegment(entityName);
23
+ const sanitizedRecordId = this.SanitizePathSegment(recordId);
24
+ const formattedStamp = this.FormatVersionStamp(versionStamp);
25
+ const prefix = basePath ? `${basePath}/` : '';
26
+ return `${prefix}${sanitizedEntity}/${sanitizedRecordId}/${formattedStamp}.json`;
27
+ }
28
+ /**
29
+ * Builds the ArchiveDocument JSON structure from a record context.
30
+ * @param context - The archive context
31
+ * @param versionStamp - The timestamp for this version
32
+ * @returns A fully populated ArchiveDocument
33
+ */
34
+ BuildArchiveDocument(context, versionStamp) {
35
+ const record = context.Record;
36
+ const archivedFields = this.ExtractArchivedFields(context);
37
+ const fullRecord = this.ExtractFullRecord(context);
38
+ const primaryKey = this.ExtractPrimaryKey(record);
39
+ return {
40
+ archiveVersion: 1,
41
+ entityName: record.EntityInfo.Name,
42
+ entityId: record.EntityInfo.ID,
43
+ recordId: primaryKey.length > 0 ? primaryKey[0].Value : '',
44
+ primaryKey,
45
+ versionStamp: versionStamp.toISOString(),
46
+ archivedAt: new Date().toISOString(),
47
+ archiveConfigurationEntityId: context.ConfigEntity.Get('ID'),
48
+ archiveConfigurationId: context.Config.Get('ID'),
49
+ mode: context.ConfigEntity.Get('Mode') ?? context.Config.Get('DefaultMode') ?? 'StripFields',
50
+ archivedFields,
51
+ fullRecord,
52
+ };
53
+ }
54
+ /**
55
+ * Extracts the values of fields configured for archiving from the record.
56
+ */
57
+ ExtractArchivedFields(context) {
58
+ const fields = {};
59
+ for (const fieldConfig of context.FieldConfig.Fields) {
60
+ if (fieldConfig.IsActive !== false) {
61
+ fields[fieldConfig.FieldName] = context.Record.Get(fieldConfig.FieldName);
62
+ }
63
+ }
64
+ return fields;
65
+ }
66
+ /**
67
+ * Extracts a full record snapshot if configured, otherwise returns null.
68
+ */
69
+ ExtractFullRecord(context) {
70
+ if (!context.FieldConfig.ArchiveFullRecord) {
71
+ return null;
72
+ }
73
+ return context.Record.GetAll();
74
+ }
75
+ /**
76
+ * Extracts the primary key fields and values from a BaseEntity record.
77
+ */
78
+ ExtractPrimaryKey(record) {
79
+ return record.PrimaryKey.KeyValuePairs.map(kvp => ({
80
+ FieldName: kvp.FieldName,
81
+ Value: String(kvp.Value),
82
+ }));
83
+ }
84
+ /**
85
+ * Sanitizes a string for use as a storage path segment by replacing
86
+ * spaces, colons, and other problematic characters with underscores.
87
+ */
88
+ SanitizePathSegment(value) {
89
+ return value.replace(/[\s:\/\\]/g, '_');
90
+ }
91
+ /**
92
+ * Formats a Date as an ISO 8601 string safe for use in file paths.
93
+ * Colons are replaced with underscores.
94
+ */
95
+ FormatVersionStamp(date) {
96
+ return date.toISOString().replace(/:/g, '_');
97
+ }
98
+ }
99
+ //# sourceMappingURL=BaseArchiveDriver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseArchiveDriver.js","sourceRoot":"","sources":["../src/BaseArchiveDriver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ import { BaseArchiveDriver } from './BaseArchiveDriver.js';
2
+ import { ArchiveRecordContext, ArchiveRecordResult, RestoreRecordContext, RestoreRecordResult } from './types.js';
3
+ /**
4
+ * Default archive driver implementation. Archives configured field values to
5
+ * external storage, applies the appropriate post-archive action based on mode
6
+ * (StripFields, HardDelete, ArchiveOnly), and supports restoring the original
7
+ * values from the stored archive document.
8
+ */
9
+ export declare class DefaultArchiveDriver extends BaseArchiveDriver {
10
+ /**
11
+ * Determines whether the record should be archived by checking if at least
12
+ * one of the configured fields (or SkipIfAllNullFields) has a non-null value.
13
+ * If no specific fields are configured but ArchiveFullRecord is true,
14
+ * always archives — the intent is a full record snapshot, not field stripping.
15
+ */
16
+ ShouldArchiveRecord(context: ArchiveRecordContext): boolean;
17
+ /**
18
+ * Archives a single record:
19
+ * 1. Builds the archive document with field values
20
+ * 2. Writes the document to external storage
21
+ * 3. Applies the post-archive action based on mode:
22
+ * - StripFields: nullifies configured fields on the source record
23
+ * - HardDelete: cascades to archive+delete dependent records, then deletes the source record
24
+ * - ArchiveOnly: no changes to the source record
25
+ */
26
+ ArchiveRecord(context: ArchiveRecordContext): Promise<ArchiveRecordResult>;
27
+ /**
28
+ * Restores a previously archived record by reading the archive document
29
+ * from storage and setting the field values back on the source record.
30
+ */
31
+ RestoreRecord(context: RestoreRecordContext): Promise<RestoreRecordResult>;
32
+ /**
33
+ * Determines which fields to check for the "should archive" decision.
34
+ * Uses SkipIfAllNullFields if configured, otherwise all active field names.
35
+ */
36
+ private GetFieldsToCheck;
37
+ /**
38
+ * Serializes the archive document and writes it to storage.
39
+ */
40
+ private WriteDocumentToStorage;
41
+ /**
42
+ * Resolves the effective archive mode from the entity config or parent config.
43
+ */
44
+ private ResolveMode;
45
+ /**
46
+ * Applies the appropriate post-archive action based on the resolved mode.
47
+ */
48
+ private ApplyPostArchiveAction;
49
+ /**
50
+ * Sets all configured archive fields to their empty value on the source record and saves it.
51
+ * Uses null for nullable columns and empty string for NOT NULL string columns.
52
+ */
53
+ private NullifyArchivedFields;
54
+ /**
55
+ * Returns the appropriate empty value for a field based on its nullability.
56
+ * NOT NULL string fields get empty string; nullable fields get null.
57
+ */
58
+ private GetEmptyValueForField;
59
+ /**
60
+ * Deletes the source record from the database after successful archival.
61
+ * Automatically cascades to dependent (child) records via FK relationships
62
+ * discovered from entity metadata, archiving each child to storage before deleting it.
63
+ */
64
+ private HardDeleteRecord;
65
+ /**
66
+ * Collects all dependent records depth-first, writes one batch archive file
67
+ * per entity to storage, then deletes all records leaf-first. This batched
68
+ * approach dramatically reduces storage API calls compared to per-record writes.
69
+ */
70
+ private ArchiveAndDeleteDependentRecords;
71
+ /**
72
+ * Recursively collects all dependent records depth-first. Leaves (deepest
73
+ * children) are added to the array first, so deleting in array order
74
+ * respects FK constraints. Uses a visited set to prevent infinite loops
75
+ * from circular references.
76
+ */
77
+ private CollectDependentsDepthFirst;
78
+ /**
79
+ * Groups collected records by entity name and writes one batch archive
80
+ * document per entity to storage. A batch document contains all records
81
+ * of that entity type in a single JSON array, dramatically reducing
82
+ * the number of storage API calls.
83
+ */
84
+ private BatchArchiveDependents;
85
+ /**
86
+ * Loads all records from a child entity that reference a parent record via a join field.
87
+ */
88
+ private LoadChildRecords;
89
+ /**
90
+ * Reads and parses an archive document from storage.
91
+ */
92
+ private ReadDocumentFromStorage;
93
+ /**
94
+ * Applies the archived field values from the document back onto the entity record and saves.
95
+ */
96
+ private ApplyArchivedFieldsToRecord;
97
+ }
98
+ //# sourceMappingURL=DefaultArchiveDriver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefaultArchiveDriver.d.ts","sourceRoot":"","sources":["../src/DefaultArchiveDriver.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACH,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EAEtB,MAAM,SAAS,CAAC;AAEjB;;;;;GAKG;AACH,qBACa,oBAAqB,SAAQ,iBAAiB;IACvD;;;;;OAKG;IACI,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO;IAelE;;;;;;;;OAQG;IACU,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAsCvF;;;OAGG;IACU,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA6BvF;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;OAEG;YACW,sBAAsB;IA0BpC;;OAEG;IACH,OAAO,CAAC,WAAW;IAMnB;;OAEG;YACW,sBAAsB;IA0BpC;;;OAGG;YACW,qBAAqB;IAuBnC;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAY7B;;;;OAIG;YACW,gBAAgB;IAqB9B;;;;OAIG;YACW,gCAAgC;IAmC9C;;;;;OAKG;YACW,2BAA2B;IAoCzC;;;;;OAKG;YACW,sBAAsB;IA2DpC;;OAEG;YACW,gBAAgB;IA0B9B;;OAEG;YACW,uBAAuB;IAMrC;;OAEG;YACW,2BAA2B;CA+B5C"}