dbdock 1.1.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 +21 -0
- package/README.md +596 -0
- package/dist/alerts/alert-templates.d.ts +3 -0
- package/dist/alerts/alert-templates.js +95 -0
- package/dist/alerts/alert-templates.js.map +1 -0
- package/dist/alerts/alert.module.d.ts +2 -0
- package/dist/alerts/alert.module.js +23 -0
- package/dist/alerts/alert.module.js.map +1 -0
- package/dist/alerts/alert.service.d.ts +23 -0
- package/dist/alerts/alert.service.js +210 -0
- package/dist/alerts/alert.service.js.map +1 -0
- package/dist/alerts/alert.types.d.ts +24 -0
- package/dist/alerts/alert.types.js +11 -0
- package/dist/alerts/alert.types.js.map +1 -0
- package/dist/app.module.d.ts +2 -0
- package/dist/app.module.js +34 -0
- package/dist/app.module.js.map +1 -0
- package/dist/backup/backup.module.d.ts +2 -0
- package/dist/backup/backup.module.js +26 -0
- package/dist/backup/backup.module.js.map +1 -0
- package/dist/backup/backup.service.d.ts +23 -0
- package/dist/backup/backup.service.js +303 -0
- package/dist/backup/backup.service.js.map +1 -0
- package/dist/backup/backup.types.d.ts +42 -0
- package/dist/backup/backup.types.js +16 -0
- package/dist/backup/backup.types.js.map +1 -0
- package/dist/backup/compression.service.d.ts +6 -0
- package/dist/backup/compression.service.js +30 -0
- package/dist/backup/compression.service.js.map +1 -0
- package/dist/cli/commands/backup.d.ts +8 -0
- package/dist/cli/commands/backup.js +198 -0
- package/dist/cli/commands/backup.js.map +1 -0
- package/dist/cli/commands/cleanup.d.ts +6 -0
- package/dist/cli/commands/cleanup.js +160 -0
- package/dist/cli/commands/cleanup.js.map +1 -0
- package/dist/cli/commands/delete.d.ts +6 -0
- package/dist/cli/commands/delete.js +252 -0
- package/dist/cli/commands/delete.js.map +1 -0
- package/dist/cli/commands/init.d.ts +1 -0
- package/dist/cli/commands/init.js +534 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/list.d.ts +8 -0
- package/dist/cli/commands/list.js +288 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/restore.d.ts +1 -0
- package/dist/cli/commands/restore.js +637 -0
- package/dist/cli/commands/restore.js.map +1 -0
- package/dist/cli/commands/schedule.d.ts +1 -0
- package/dist/cli/commands/schedule.js +197 -0
- package/dist/cli/commands/schedule.js.map +1 -0
- package/dist/cli/commands/start.d.ts +7 -0
- package/dist/cli/commands/start.js +267 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.d.ts +1 -0
- package/dist/cli/commands/status.js +46 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/test.d.ts +1 -0
- package/dist/cli/commands/test.js +212 -0
- package/dist/cli/commands/test.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +78 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/config.d.ts +80 -0
- package/dist/cli/utils/config.js +29 -0
- package/dist/cli/utils/config.js.map +1 -0
- package/dist/cli/utils/logger.d.ts +7 -0
- package/dist/cli/utils/logger.js +15 -0
- package/dist/cli/utils/logger.js.map +1 -0
- package/dist/cli/utils/progress.d.ts +21 -0
- package/dist/cli/utils/progress.js +130 -0
- package/dist/cli/utils/progress.js.map +1 -0
- package/dist/cli/utils/retention.d.ts +26 -0
- package/dist/cli/utils/retention.js +118 -0
- package/dist/cli/utils/retention.js.map +1 -0
- package/dist/config/config.module.d.ts +2 -0
- package/dist/config/config.module.js +29 -0
- package/dist/config/config.module.js.map +1 -0
- package/dist/config/config.schema.d.ts +56 -0
- package/dist/config/config.schema.js +219 -0
- package/dist/config/config.schema.js.map +1 -0
- package/dist/config/config.service.d.ts +13 -0
- package/dist/config/config.service.js +160 -0
- package/dist/config/config.service.js.map +1 -0
- package/dist/crypto/crypto.module.d.ts +2 -0
- package/dist/crypto/crypto.module.js +21 -0
- package/dist/crypto/crypto.module.js.map +1 -0
- package/dist/crypto/crypto.service.d.ts +22 -0
- package/dist/crypto/crypto.service.js +187 -0
- package/dist/crypto/crypto.service.js.map +1 -0
- package/dist/dbdock.d.ts +10 -0
- package/dist/dbdock.js +36 -0
- package/dist/dbdock.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +77 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +10 -0
- package/dist/main.js.map +1 -0
- package/dist/scheduler/schedule-manager.d.ts +22 -0
- package/dist/scheduler/schedule-manager.js +126 -0
- package/dist/scheduler/schedule-manager.js.map +1 -0
- package/dist/scheduler/scheduler.module.d.ts +2 -0
- package/dist/scheduler/scheduler.module.js +25 -0
- package/dist/scheduler/scheduler.module.js.map +1 -0
- package/dist/scheduler/scheduler.service.d.ts +28 -0
- package/dist/scheduler/scheduler.service.js +171 -0
- package/dist/scheduler/scheduler.service.js.map +1 -0
- package/dist/standalone/backup-standalone.d.ts +14 -0
- package/dist/standalone/backup-standalone.js +364 -0
- package/dist/standalone/backup-standalone.js.map +1 -0
- package/dist/storage/adapters/cloudinary.adapter.d.ts +23 -0
- package/dist/storage/adapters/cloudinary.adapter.js +215 -0
- package/dist/storage/adapters/cloudinary.adapter.js.map +1 -0
- package/dist/storage/adapters/local.adapter.d.ts +20 -0
- package/dist/storage/adapters/local.adapter.js +214 -0
- package/dist/storage/adapters/local.adapter.js.map +1 -0
- package/dist/storage/adapters/r2.adapter.d.ts +10 -0
- package/dist/storage/adapters/r2.adapter.js +33 -0
- package/dist/storage/adapters/r2.adapter.js.map +1 -0
- package/dist/storage/adapters/s3.adapter.d.ts +26 -0
- package/dist/storage/adapters/s3.adapter.js +199 -0
- package/dist/storage/adapters/s3.adapter.js.map +1 -0
- package/dist/storage/storage.interface.d.ts +38 -0
- package/dist/storage/storage.interface.js +3 -0
- package/dist/storage/storage.interface.js.map +1 -0
- package/dist/storage/storage.module.d.ts +2 -0
- package/dist/storage/storage.module.js +21 -0
- package/dist/storage/storage.module.js.map +1 -0
- package/dist/storage/storage.service.d.ts +10 -0
- package/dist/storage/storage.service.js +89 -0
- package/dist/storage/storage.service.js.map +1 -0
- package/dist/utils/logger.d.ts +12 -0
- package/dist/utils/logger.js +41 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/stream.pipe.d.ts +17 -0
- package/dist/utils/stream.pipe.js +54 -0
- package/dist/utils/stream.pipe.js.map +1 -0
- package/dist/wal/postgres-config.helper.d.ts +5 -0
- package/dist/wal/postgres-config.helper.js +117 -0
- package/dist/wal/postgres-config.helper.js.map +1 -0
- package/dist/wal/retention.service.d.ts +23 -0
- package/dist/wal/retention.service.js +158 -0
- package/dist/wal/retention.service.js.map +1 -0
- package/dist/wal/retention.types.d.ts +20 -0
- package/dist/wal/retention.types.js +3 -0
- package/dist/wal/retention.types.js.map +1 -0
- package/dist/wal/wal-archiver.service.d.ts +28 -0
- package/dist/wal/wal-archiver.service.js +263 -0
- package/dist/wal/wal-archiver.service.js.map +1 -0
- package/dist/wal/wal.module.d.ts +2 -0
- package/dist/wal/wal.module.js +26 -0
- package/dist/wal/wal.module.js.map +1 -0
- package/dist/wal/wal.types.d.ts +27 -0
- package/dist/wal/wal.types.js +11 -0
- package/dist/wal/wal.types.js.map +1 -0
- package/package.json +155 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var S3StorageAdapter_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.S3StorageAdapter = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
16
|
+
const lib_storage_1 = require("@aws-sdk/lib-storage");
|
|
17
|
+
const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
|
|
18
|
+
let S3StorageAdapter = S3StorageAdapter_1 = class S3StorageAdapter {
|
|
19
|
+
logger = new common_1.Logger(S3StorageAdapter_1.name);
|
|
20
|
+
client;
|
|
21
|
+
bucket;
|
|
22
|
+
constructor(config) {
|
|
23
|
+
this.bucket = config.bucket;
|
|
24
|
+
this.client = new client_s3_1.S3Client({
|
|
25
|
+
endpoint: config.endpoint,
|
|
26
|
+
region: config.region || 'us-east-1',
|
|
27
|
+
credentials: {
|
|
28
|
+
accessKeyId: config.accessKeyId,
|
|
29
|
+
secretAccessKey: config.secretAccessKey,
|
|
30
|
+
},
|
|
31
|
+
forcePathStyle: config.forcePathStyle ?? false,
|
|
32
|
+
});
|
|
33
|
+
this.logger.log(`S3 adapter initialized for bucket: ${this.bucket}`);
|
|
34
|
+
}
|
|
35
|
+
async uploadStream(stream, options) {
|
|
36
|
+
try {
|
|
37
|
+
const upload = new lib_storage_1.Upload({
|
|
38
|
+
client: this.client,
|
|
39
|
+
params: {
|
|
40
|
+
Bucket: this.bucket,
|
|
41
|
+
Key: options.key,
|
|
42
|
+
Body: stream,
|
|
43
|
+
ContentType: options.contentType,
|
|
44
|
+
Metadata: options.metadata,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
upload.on('httpUploadProgress', (progress) => {
|
|
48
|
+
if (progress.loaded && progress.total) {
|
|
49
|
+
const percent = ((progress.loaded / progress.total) * 100).toFixed(2);
|
|
50
|
+
this.logger.log(`Upload progress for ${options.key}: ${percent}%`);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
const result = await upload.done();
|
|
54
|
+
this.logger.log(`Uploaded ${options.key} to S3`);
|
|
55
|
+
return {
|
|
56
|
+
key: options.key,
|
|
57
|
+
etag: result.ETag,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const friendlyMessage = this.getFriendlyError(error);
|
|
62
|
+
this.logger.error(`Failed to upload ${options.key}: ${friendlyMessage}`);
|
|
63
|
+
const cleanError = new Error(friendlyMessage);
|
|
64
|
+
cleanError.name = 'StorageConfigurationError';
|
|
65
|
+
throw cleanError;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async downloadStream(options) {
|
|
69
|
+
try {
|
|
70
|
+
const command = new client_s3_1.GetObjectCommand({
|
|
71
|
+
Bucket: this.bucket,
|
|
72
|
+
Key: options.key,
|
|
73
|
+
});
|
|
74
|
+
const response = await this.client.send(command);
|
|
75
|
+
if (!response.Body) {
|
|
76
|
+
throw new Error(`No body in response for ${options.key}`);
|
|
77
|
+
}
|
|
78
|
+
return response.Body;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
const friendlyMessage = this.getFriendlyError(error);
|
|
82
|
+
this.logger.error(`Failed to download ${options.key}: ${friendlyMessage}`);
|
|
83
|
+
const cleanError = new Error(friendlyMessage);
|
|
84
|
+
cleanError.name = 'StorageConfigurationError';
|
|
85
|
+
throw cleanError;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async listObjects(options) {
|
|
89
|
+
try {
|
|
90
|
+
const command = new client_s3_1.ListObjectsV2Command({
|
|
91
|
+
Bucket: this.bucket,
|
|
92
|
+
Prefix: options?.prefix,
|
|
93
|
+
MaxKeys: options?.maxKeys || 1000,
|
|
94
|
+
StartAfter: options?.startAfter,
|
|
95
|
+
});
|
|
96
|
+
const response = await this.client.send(command);
|
|
97
|
+
if (!response.Contents) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
return response.Contents.map((obj) => ({
|
|
101
|
+
key: obj.Key,
|
|
102
|
+
size: obj.Size || 0,
|
|
103
|
+
lastModified: obj.LastModified || new Date(),
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
const friendlyMessage = this.getFriendlyError(error);
|
|
108
|
+
this.logger.error(`Failed to list objects: ${friendlyMessage}`);
|
|
109
|
+
const cleanError = new Error(friendlyMessage);
|
|
110
|
+
cleanError.name = 'StorageConfigurationError';
|
|
111
|
+
throw cleanError;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async deleteObject(options) {
|
|
115
|
+
try {
|
|
116
|
+
const command = new client_s3_1.DeleteObjectCommand({
|
|
117
|
+
Bucket: this.bucket,
|
|
118
|
+
Key: options.key,
|
|
119
|
+
});
|
|
120
|
+
await this.client.send(command);
|
|
121
|
+
this.logger.log(`Deleted ${options.key} from S3`);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const friendlyMessage = this.getFriendlyError(error);
|
|
125
|
+
this.logger.error(`Failed to delete ${options.key}: ${friendlyMessage}`);
|
|
126
|
+
const cleanError = new Error(friendlyMessage);
|
|
127
|
+
cleanError.name = 'StorageConfigurationError';
|
|
128
|
+
throw cleanError;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async generatePresignedUrl(options) {
|
|
132
|
+
try {
|
|
133
|
+
const command = new client_s3_1.GetObjectCommand({
|
|
134
|
+
Bucket: this.bucket,
|
|
135
|
+
Key: options.key,
|
|
136
|
+
});
|
|
137
|
+
const url = await (0, s3_request_presigner_1.getSignedUrl)(this.client, command, {
|
|
138
|
+
expiresIn: options.expiresIn || 3600,
|
|
139
|
+
});
|
|
140
|
+
return url;
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
const friendlyMessage = this.getFriendlyError(error);
|
|
144
|
+
this.logger.error(`Failed to generate presigned URL for ${options.key}: ${friendlyMessage}`);
|
|
145
|
+
const cleanError = new Error(friendlyMessage);
|
|
146
|
+
cleanError.name = 'StorageConfigurationError';
|
|
147
|
+
throw cleanError;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async objectExists(key) {
|
|
151
|
+
try {
|
|
152
|
+
const command = new client_s3_1.HeadObjectCommand({
|
|
153
|
+
Bucket: this.bucket,
|
|
154
|
+
Key: key,
|
|
155
|
+
});
|
|
156
|
+
await this.client.send(command);
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
if (error.name === 'NotFound') {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
getFriendlyError(error) {
|
|
167
|
+
const err = error;
|
|
168
|
+
const code = err?.code;
|
|
169
|
+
const message = err?.message || '';
|
|
170
|
+
if (code === 'EPROTO' || message.includes('SSL') || message.includes('TLS')) {
|
|
171
|
+
return 'Invalid storage configuration: SSL/TLS handshake failed. Please verify your endpoint URL, access key ID, and secret access key are correct.';
|
|
172
|
+
}
|
|
173
|
+
if (code === 'ENOTFOUND' || message.includes('getaddrinfo')) {
|
|
174
|
+
return 'Invalid storage configuration: Could not resolve endpoint hostname. Please verify your endpoint URL is correct.';
|
|
175
|
+
}
|
|
176
|
+
if (code === 'SignatureDoesNotMatch' || message.includes('signature')) {
|
|
177
|
+
return 'Invalid storage configuration: Authentication failed. Please verify your access key ID and secret access key are correct.';
|
|
178
|
+
}
|
|
179
|
+
if (code === 'InvalidAccessKeyId') {
|
|
180
|
+
return 'Invalid storage configuration: Access key ID not found. Please verify your access key ID is correct.';
|
|
181
|
+
}
|
|
182
|
+
if (code === 'NoSuchBucket') {
|
|
183
|
+
return `Invalid storage configuration: Bucket "${this.bucket}" does not exist. Please verify your bucket name is correct.`;
|
|
184
|
+
}
|
|
185
|
+
if (code === 'AccessDenied' || code === 'Forbidden') {
|
|
186
|
+
return 'Invalid storage configuration: Access denied. Please verify your credentials have the necessary permissions for this bucket.';
|
|
187
|
+
}
|
|
188
|
+
if (code === 'ETIMEDOUT' || code === 'ECONNREFUSED') {
|
|
189
|
+
return 'Invalid storage configuration: Connection failed. Please verify your endpoint URL and network connectivity.';
|
|
190
|
+
}
|
|
191
|
+
return message || 'Unknown storage error occurred';
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
exports.S3StorageAdapter = S3StorageAdapter;
|
|
195
|
+
exports.S3StorageAdapter = S3StorageAdapter = S3StorageAdapter_1 = __decorate([
|
|
196
|
+
(0, common_1.Injectable)(),
|
|
197
|
+
__metadata("design:paramtypes", [Object])
|
|
198
|
+
], S3StorageAdapter);
|
|
199
|
+
//# sourceMappingURL=s3.adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.adapter.js","sourceRoot":"","sources":["../../../src/storage/adapters/s3.adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Readable } from 'stream';
|
|
2
|
+
export interface UploadOptions {
|
|
3
|
+
key: string;
|
|
4
|
+
metadata?: Record<string, string>;
|
|
5
|
+
contentType?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DownloadOptions {
|
|
8
|
+
key: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ListOptions {
|
|
11
|
+
prefix?: string;
|
|
12
|
+
maxKeys?: number;
|
|
13
|
+
startAfter?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface StorageObject {
|
|
16
|
+
key: string;
|
|
17
|
+
size: number;
|
|
18
|
+
lastModified: Date;
|
|
19
|
+
metadata?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
export interface DeleteOptions {
|
|
22
|
+
key: string;
|
|
23
|
+
}
|
|
24
|
+
export interface PresignedUrlOptions {
|
|
25
|
+
key: string;
|
|
26
|
+
expiresIn?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface IStorageAdapter {
|
|
29
|
+
uploadStream(stream: Readable, options: UploadOptions): Promise<{
|
|
30
|
+
key: string;
|
|
31
|
+
etag?: string;
|
|
32
|
+
}>;
|
|
33
|
+
downloadStream(options: DownloadOptions): Promise<Readable>;
|
|
34
|
+
listObjects(options?: ListOptions): Promise<StorageObject[]>;
|
|
35
|
+
deleteObject(options: DeleteOptions): Promise<void>;
|
|
36
|
+
generatePresignedUrl(options: PresignedUrlOptions): Promise<string>;
|
|
37
|
+
objectExists(key: string): Promise<boolean>;
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.interface.js","sourceRoot":"","sources":["../../src/storage/storage.interface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.StorageModule = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const storage_service_1 = require("./storage.service");
|
|
12
|
+
let StorageModule = class StorageModule {
|
|
13
|
+
};
|
|
14
|
+
exports.StorageModule = StorageModule;
|
|
15
|
+
exports.StorageModule = StorageModule = __decorate([
|
|
16
|
+
(0, common_1.Module)({
|
|
17
|
+
providers: [storage_service_1.StorageService],
|
|
18
|
+
exports: [storage_service_1.StorageService],
|
|
19
|
+
})
|
|
20
|
+
], StorageModule);
|
|
21
|
+
//# sourceMappingURL=storage.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.module.js","sourceRoot":"","sources":["../../src/storage/storage.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,uDAAmD;AAM5C,IAAM,aAAa,GAAnB,MAAM,aAAa;CAAG,CAAA;AAAhB,sCAAa;wBAAb,aAAa;IAJzB,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,gCAAc,CAAC;QAC3B,OAAO,EAAE,CAAC,gCAAc,CAAC;KAC1B,CAAC;GACW,aAAa,CAAG"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DBDockConfigService } from '../config/config.service';
|
|
2
|
+
import { IStorageAdapter } from './storage.interface';
|
|
3
|
+
export declare class StorageService {
|
|
4
|
+
private configService;
|
|
5
|
+
private readonly logger;
|
|
6
|
+
private adapter;
|
|
7
|
+
constructor(configService: DBDockConfigService);
|
|
8
|
+
private initializeAdapter;
|
|
9
|
+
getAdapter(): IStorageAdapter;
|
|
10
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var StorageService_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.StorageService = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const config_service_1 = require("../config/config.service");
|
|
16
|
+
const local_adapter_1 = require("./adapters/local.adapter");
|
|
17
|
+
const s3_adapter_1 = require("./adapters/s3.adapter");
|
|
18
|
+
const r2_adapter_1 = require("./adapters/r2.adapter");
|
|
19
|
+
const cloudinary_adapter_1 = require("./adapters/cloudinary.adapter");
|
|
20
|
+
const config_schema_1 = require("../config/config.schema");
|
|
21
|
+
let StorageService = StorageService_1 = class StorageService {
|
|
22
|
+
configService;
|
|
23
|
+
logger = new common_1.Logger(StorageService_1.name);
|
|
24
|
+
adapter;
|
|
25
|
+
constructor(configService) {
|
|
26
|
+
this.configService = configService;
|
|
27
|
+
this.initializeAdapter();
|
|
28
|
+
}
|
|
29
|
+
initializeAdapter() {
|
|
30
|
+
const storageConfig = this.configService.get('storage');
|
|
31
|
+
switch (storageConfig.provider) {
|
|
32
|
+
case config_schema_1.StorageProvider.LOCAL:
|
|
33
|
+
this.adapter = new local_adapter_1.LocalStorageAdapter(storageConfig.localPath || './backups');
|
|
34
|
+
this.logger.log('Initialized local storage adapter');
|
|
35
|
+
break;
|
|
36
|
+
case config_schema_1.StorageProvider.S3:
|
|
37
|
+
if (!storageConfig.accessKeyId || !storageConfig.secretAccessKey) {
|
|
38
|
+
throw new Error('S3 credentials are required');
|
|
39
|
+
}
|
|
40
|
+
this.adapter = new s3_adapter_1.S3StorageAdapter({
|
|
41
|
+
endpoint: storageConfig.endpoint,
|
|
42
|
+
bucket: storageConfig.bucket,
|
|
43
|
+
accessKeyId: storageConfig.accessKeyId,
|
|
44
|
+
secretAccessKey: storageConfig.secretAccessKey,
|
|
45
|
+
});
|
|
46
|
+
this.logger.log('Initialized S3 storage adapter');
|
|
47
|
+
break;
|
|
48
|
+
case config_schema_1.StorageProvider.R2:
|
|
49
|
+
if (!storageConfig.accessKeyId || !storageConfig.secretAccessKey) {
|
|
50
|
+
throw new Error('R2 credentials are required');
|
|
51
|
+
}
|
|
52
|
+
if (!storageConfig.endpoint) {
|
|
53
|
+
throw new Error('R2 account ID is required in endpoint');
|
|
54
|
+
}
|
|
55
|
+
const accountId = storageConfig.endpoint.split('.')[0];
|
|
56
|
+
this.adapter = new r2_adapter_1.R2StorageAdapter({
|
|
57
|
+
accountId,
|
|
58
|
+
bucket: storageConfig.bucket,
|
|
59
|
+
accessKeyId: storageConfig.accessKeyId,
|
|
60
|
+
secretAccessKey: storageConfig.secretAccessKey,
|
|
61
|
+
});
|
|
62
|
+
this.logger.log('Initialized R2 storage adapter');
|
|
63
|
+
break;
|
|
64
|
+
case config_schema_1.StorageProvider.CLOUDINARY:
|
|
65
|
+
if (!storageConfig.accessKeyId || !storageConfig.secretAccessKey) {
|
|
66
|
+
throw new Error('Cloudinary credentials are required');
|
|
67
|
+
}
|
|
68
|
+
this.adapter = new cloudinary_adapter_1.CloudinaryStorageAdapter({
|
|
69
|
+
cloudName: storageConfig.bucket,
|
|
70
|
+
apiKey: storageConfig.accessKeyId,
|
|
71
|
+
apiSecret: storageConfig.secretAccessKey,
|
|
72
|
+
folder: storageConfig.endpoint,
|
|
73
|
+
});
|
|
74
|
+
this.logger.log('Initialized Cloudinary storage adapter');
|
|
75
|
+
break;
|
|
76
|
+
default:
|
|
77
|
+
throw new Error(`Unknown storage provider: ${storageConfig.provider}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
getAdapter() {
|
|
81
|
+
return this.adapter;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
exports.StorageService = StorageService;
|
|
85
|
+
exports.StorageService = StorageService = StorageService_1 = __decorate([
|
|
86
|
+
(0, common_1.Injectable)(),
|
|
87
|
+
__metadata("design:paramtypes", [config_service_1.DBDockConfigService])
|
|
88
|
+
], StorageService);
|
|
89
|
+
//# sourceMappingURL=storage.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.service.js","sourceRoot":"","sources":["../../src/storage/storage.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Logger as NestLogger } from '@nestjs/common';
|
|
2
|
+
export declare class DBDockLogger extends NestLogger {
|
|
3
|
+
logBackupStart(backupId: string, type: string): void;
|
|
4
|
+
logBackupComplete(backupId: string, duration: number, size: number): void;
|
|
5
|
+
logBackupError(backupId: string, error: Error): void;
|
|
6
|
+
logRestoreStart(backupId: string, targetTime?: string): void;
|
|
7
|
+
logRestoreComplete(backupId: string, duration: number): void;
|
|
8
|
+
logRestoreError(backupId: string, error: Error): void;
|
|
9
|
+
logWalArchive(walFile: string): void;
|
|
10
|
+
logWalArchiveError(walFile: string, error: Error): void;
|
|
11
|
+
private formatBytes;
|
|
12
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DBDockLogger = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
class DBDockLogger extends common_1.Logger {
|
|
6
|
+
logBackupStart(backupId, type) {
|
|
7
|
+
this.log(`Backup started: ${backupId} (type: ${type})`);
|
|
8
|
+
}
|
|
9
|
+
logBackupComplete(backupId, duration, size) {
|
|
10
|
+
this.log(`Backup completed: ${backupId} (duration: ${duration}ms, size: ${this.formatBytes(size)})`);
|
|
11
|
+
}
|
|
12
|
+
logBackupError(backupId, error) {
|
|
13
|
+
this.error(`Backup failed: ${backupId} - ${error.message}`, error.stack);
|
|
14
|
+
}
|
|
15
|
+
logRestoreStart(backupId, targetTime) {
|
|
16
|
+
const timeInfo = targetTime ? ` to time: ${targetTime}` : '';
|
|
17
|
+
this.log(`Restore started: ${backupId}${timeInfo}`);
|
|
18
|
+
}
|
|
19
|
+
logRestoreComplete(backupId, duration) {
|
|
20
|
+
this.log(`Restore completed: ${backupId} (duration: ${duration}ms)`);
|
|
21
|
+
}
|
|
22
|
+
logRestoreError(backupId, error) {
|
|
23
|
+
this.error(`Restore failed: ${backupId} - ${error.message}`, error.stack);
|
|
24
|
+
}
|
|
25
|
+
logWalArchive(walFile) {
|
|
26
|
+
this.log(`WAL archived: ${walFile}`);
|
|
27
|
+
}
|
|
28
|
+
logWalArchiveError(walFile, error) {
|
|
29
|
+
this.error(`WAL archive failed: ${walFile} - ${error.message}`);
|
|
30
|
+
}
|
|
31
|
+
formatBytes(bytes) {
|
|
32
|
+
if (bytes === 0)
|
|
33
|
+
return '0 B';
|
|
34
|
+
const k = 1024;
|
|
35
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
36
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
37
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.DBDockLogger = DBDockLogger;
|
|
41
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":";;;AAAA,2CAAsD;AAEtD,MAAa,YAAa,SAAQ,eAAU;IAC1C,cAAc,CAAC,QAAgB,EAAE,IAAY;QAC3C,IAAI,CAAC,GAAG,CAAC,mBAAmB,QAAQ,WAAW,IAAI,GAAG,CAAC,CAAC;IAC1D,CAAC;IAED,iBAAiB,CAAC,QAAgB,EAAE,QAAgB,EAAE,IAAY;QAChE,IAAI,CAAC,GAAG,CACN,qBAAqB,QAAQ,eAAe,QAAQ,aAAa,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAC3F,CAAC;IACJ,CAAC;IAED,cAAc,CAAC,QAAgB,EAAE,KAAY;QAC3C,IAAI,CAAC,KAAK,CAAC,kBAAkB,QAAQ,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3E,CAAC;IAED,eAAe,CAAC,QAAgB,EAAE,UAAmB;QACnD,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,aAAa,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,IAAI,CAAC,GAAG,CAAC,oBAAoB,QAAQ,GAAG,QAAQ,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,kBAAkB,CAAC,QAAgB,EAAE,QAAgB;QACnD,IAAI,CAAC,GAAG,CAAC,sBAAsB,QAAQ,eAAe,QAAQ,KAAK,CAAC,CAAC;IACvE,CAAC;IAED,eAAe,CAAC,QAAgB,EAAE,KAAY;QAC5C,IAAI,CAAC,KAAK,CAAC,mBAAmB,QAAQ,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC5E,CAAC;IAED,aAAa,CAAC,OAAe;QAC3B,IAAI,CAAC,GAAG,CAAC,iBAAiB,OAAO,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,kBAAkB,CAAC,OAAe,EAAE,KAAY;QAC9C,IAAI,CAAC,KAAK,CAAC,uBAAuB,OAAO,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAClE,CAAC;IAEO,WAAW,CAAC,KAAa;QAC/B,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAE9B,MAAM,CAAC,GAAG,IAAI,CAAC;QACf,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAEpD,OAAO,GAAG,UAAU,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,CAAC;CACF;AA7CD,oCA6CC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Transform, TransformCallback } from 'stream';
|
|
2
|
+
export declare class CounterStream extends Transform {
|
|
3
|
+
private bytesProcessed;
|
|
4
|
+
_transform(chunk: unknown, encoding: BufferEncoding, callback: TransformCallback): void;
|
|
5
|
+
_flush(callback: TransformCallback): void;
|
|
6
|
+
getBytesProcessed(): number;
|
|
7
|
+
}
|
|
8
|
+
export declare class ProgressStream extends Transform {
|
|
9
|
+
private bytesProcessed;
|
|
10
|
+
private lastReportedProgress;
|
|
11
|
+
private readonly reportInterval;
|
|
12
|
+
private readonly onProgress?;
|
|
13
|
+
constructor(reportIntervalBytes?: number, onProgress?: (bytes: number) => void);
|
|
14
|
+
_transform(chunk: unknown, encoding: BufferEncoding, callback: TransformCallback): void;
|
|
15
|
+
_flush(callback: TransformCallback): void;
|
|
16
|
+
getBytesProcessed(): number;
|
|
17
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProgressStream = exports.CounterStream = void 0;
|
|
4
|
+
const stream_1 = require("stream");
|
|
5
|
+
class CounterStream extends stream_1.Transform {
|
|
6
|
+
bytesProcessed = 0;
|
|
7
|
+
_transform(chunk, encoding, callback) {
|
|
8
|
+
this.bytesProcessed += chunk.length;
|
|
9
|
+
this.push(chunk);
|
|
10
|
+
callback();
|
|
11
|
+
}
|
|
12
|
+
_flush(callback) {
|
|
13
|
+
callback();
|
|
14
|
+
}
|
|
15
|
+
getBytesProcessed() {
|
|
16
|
+
return this.bytesProcessed;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.CounterStream = CounterStream;
|
|
20
|
+
class ProgressStream extends stream_1.Transform {
|
|
21
|
+
bytesProcessed = 0;
|
|
22
|
+
lastReportedProgress = 0;
|
|
23
|
+
reportInterval;
|
|
24
|
+
onProgress;
|
|
25
|
+
constructor(reportIntervalBytes = 1024 * 1024, onProgress) {
|
|
26
|
+
super();
|
|
27
|
+
this.reportInterval = reportIntervalBytes;
|
|
28
|
+
this.onProgress = onProgress;
|
|
29
|
+
}
|
|
30
|
+
_transform(chunk, encoding, callback) {
|
|
31
|
+
const buffer = chunk;
|
|
32
|
+
this.bytesProcessed += buffer.length;
|
|
33
|
+
if (this.bytesProcessed - this.lastReportedProgress >=
|
|
34
|
+
this.reportInterval) {
|
|
35
|
+
this.lastReportedProgress = this.bytesProcessed;
|
|
36
|
+
if (this.onProgress) {
|
|
37
|
+
this.onProgress(this.bytesProcessed);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
this.push(chunk);
|
|
41
|
+
callback();
|
|
42
|
+
}
|
|
43
|
+
_flush(callback) {
|
|
44
|
+
if (this.onProgress && this.bytesProcessed > this.lastReportedProgress) {
|
|
45
|
+
this.onProgress(this.bytesProcessed);
|
|
46
|
+
}
|
|
47
|
+
callback();
|
|
48
|
+
}
|
|
49
|
+
getBytesProcessed() {
|
|
50
|
+
return this.bytesProcessed;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.ProgressStream = ProgressStream;
|
|
54
|
+
//# sourceMappingURL=stream.pipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.pipe.js","sourceRoot":"","sources":["../../src/utils/stream.pipe.ts"],"names":[],"mappings":";;;AAAA,mCAAsD;AAEtD,MAAa,aAAc,SAAQ,kBAAS;IAClC,cAAc,GAAG,CAAC,CAAC;IAE3B,UAAU,CACR,KAAc,EACd,QAAwB,EACxB,QAA2B;QAE3B,IAAI,CAAC,cAAc,IAAK,KAAgB,CAAC,MAAM,CAAC;QAChD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,MAAM,CAAC,QAA2B;QAChC,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;CACF;AApBD,sCAoBC;AAED,MAAa,cAAe,SAAQ,kBAAS;IACnC,cAAc,GAAG,CAAC,CAAC;IACnB,oBAAoB,GAAG,CAAC,CAAC;IAChB,cAAc,CAAS;IACvB,UAAU,CAA2B;IAEtD,YACE,mBAAmB,GAAG,IAAI,GAAG,IAAI,EACjC,UAAoC;QAEpC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,cAAc,GAAG,mBAAmB,CAAC;QAC1C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,UAAU,CACR,KAAc,EACd,QAAwB,EACxB,QAA2B;QAE3B,MAAM,MAAM,GAAG,KAAe,CAAC;QAC/B,IAAI,CAAC,cAAc,IAAI,MAAM,CAAC,MAAM,CAAC;QAErC,IACE,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,oBAAoB;YAC/C,IAAI,CAAC,cAAc,EACnB,CAAC;YACD,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,cAAc,CAAC;YAChD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACpB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjB,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,MAAM,CAAC,QAA2B;QAChC,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;YACvE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACvC,CAAC;QACD,QAAQ,EAAE,CAAC;IACb,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;CACF;AA/CD,wCA+CC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PostgresConfigHelper = void 0;
|
|
4
|
+
class PostgresConfigHelper {
|
|
5
|
+
static getArchiveCommandScript(archivePath) {
|
|
6
|
+
return `
|
|
7
|
+
#!/bin/bash
|
|
8
|
+
# PostgreSQL WAL Archive Command Script
|
|
9
|
+
# Generated by DBDock
|
|
10
|
+
|
|
11
|
+
WAL_FILE="$1"
|
|
12
|
+
WAL_PATH="$2"
|
|
13
|
+
ARCHIVE_PATH="${archivePath}"
|
|
14
|
+
|
|
15
|
+
# Create archive directory if it doesn't exist
|
|
16
|
+
mkdir -p "$ARCHIVE_PATH"
|
|
17
|
+
|
|
18
|
+
# Copy WAL file to archive location
|
|
19
|
+
cp "$WAL_PATH" "$ARCHIVE_PATH/$WAL_FILE"
|
|
20
|
+
|
|
21
|
+
# Signal DBDock to process this WAL file
|
|
22
|
+
# You can integrate this with DBDock's WAL archiver
|
|
23
|
+
# For now, we just copy it to the archive location
|
|
24
|
+
|
|
25
|
+
exit 0
|
|
26
|
+
`.trim();
|
|
27
|
+
}
|
|
28
|
+
static getPostgresqlConfSettings(archivePath) {
|
|
29
|
+
return `
|
|
30
|
+
# PostgreSQL Configuration for DBDock WAL Archiving
|
|
31
|
+
# Add these settings to postgresql.conf
|
|
32
|
+
|
|
33
|
+
# Enable WAL archiving
|
|
34
|
+
wal_level = replica
|
|
35
|
+
archive_mode = on
|
|
36
|
+
archive_command = 'test ! -f ${archivePath}/%f && cp %p ${archivePath}/%f'
|
|
37
|
+
|
|
38
|
+
# Archive timeout (optional - archives WAL every 5 minutes even if not full)
|
|
39
|
+
archive_timeout = 300
|
|
40
|
+
|
|
41
|
+
# WAL segment size (default is 16MB)
|
|
42
|
+
# Note: This is a compile-time setting and cannot be changed in postgresql.conf
|
|
43
|
+
|
|
44
|
+
# For better PITR recovery
|
|
45
|
+
full_page_writes = on
|
|
46
|
+
`.trim();
|
|
47
|
+
}
|
|
48
|
+
static getSetupInstructions() {
|
|
49
|
+
return `
|
|
50
|
+
# DBDock WAL Archiving Setup Instructions
|
|
51
|
+
|
|
52
|
+
## 1. Configure PostgreSQL
|
|
53
|
+
|
|
54
|
+
Add the following to your postgresql.conf:
|
|
55
|
+
|
|
56
|
+
\`\`\`
|
|
57
|
+
wal_level = replica
|
|
58
|
+
archive_mode = on
|
|
59
|
+
archive_command = 'test ! -f /path/to/archive/%f && cp %p /path/to/archive/%f'
|
|
60
|
+
archive_timeout = 300
|
|
61
|
+
\`\`\`
|
|
62
|
+
|
|
63
|
+
## 2. Create Archive Directory
|
|
64
|
+
|
|
65
|
+
\`\`\`bash
|
|
66
|
+
mkdir -p /path/to/archive
|
|
67
|
+
chown postgres:postgres /path/to/archive
|
|
68
|
+
chmod 700 /path/to/archive
|
|
69
|
+
\`\`\`
|
|
70
|
+
|
|
71
|
+
## 3. Restart PostgreSQL
|
|
72
|
+
|
|
73
|
+
\`\`\`bash
|
|
74
|
+
sudo systemctl restart postgresql
|
|
75
|
+
\`\`\`
|
|
76
|
+
|
|
77
|
+
## 4. Verify Configuration
|
|
78
|
+
|
|
79
|
+
\`\`\`sql
|
|
80
|
+
SELECT name, setting FROM pg_settings WHERE name IN ('wal_level', 'archive_mode', 'archive_command');
|
|
81
|
+
\`\`\`
|
|
82
|
+
|
|
83
|
+
## 5. Monitor WAL Archiving
|
|
84
|
+
|
|
85
|
+
\`\`\`sql
|
|
86
|
+
SELECT * FROM pg_stat_archiver;
|
|
87
|
+
\`\`\`
|
|
88
|
+
|
|
89
|
+
## 6. Configure DBDock
|
|
90
|
+
|
|
91
|
+
Enable PITR in your dbdock.config.json:
|
|
92
|
+
|
|
93
|
+
\`\`\`json
|
|
94
|
+
{
|
|
95
|
+
"pitr": {
|
|
96
|
+
"enabled": true,
|
|
97
|
+
"walIntervalSeconds": 300,
|
|
98
|
+
"retentionDays": 30
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
\`\`\`
|
|
102
|
+
|
|
103
|
+
## 7. Archive WAL Files with DBDock
|
|
104
|
+
|
|
105
|
+
You can manually archive WAL files or set up a cron job:
|
|
106
|
+
|
|
107
|
+
\`\`\`bash
|
|
108
|
+
# Archive all WAL files in the archive directory
|
|
109
|
+
for wal in /path/to/archive/*; do
|
|
110
|
+
dbdock wal:archive --file "$wal"
|
|
111
|
+
done
|
|
112
|
+
\`\`\`
|
|
113
|
+
`.trim();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.PostgresConfigHelper = PostgresConfigHelper;
|
|
117
|
+
//# sourceMappingURL=postgres-config.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-config.helper.js","sourceRoot":"","sources":["../../src/wal/postgres-config.helper.ts"],"names":[],"mappings":";;;AAAA,MAAa,oBAAoB;IAC/B,MAAM,CAAC,uBAAuB,CAAC,WAAmB;QAChD,OAAO;;;;;;;gBAOK,WAAW;;;;;;;;;;;;;CAa1B,CAAC,IAAI,EAAE,CAAC;IACP,CAAC;IAED,MAAM,CAAC,yBAAyB,CAAC,WAAmB;QAClD,OAAO;;;;;;;+BAOoB,WAAW,gBAAgB,WAAW;;;;;;;;;;CAUpE,CAAC,IAAI,EAAE,CAAC;IACP,CAAC;IAED,MAAM,CAAC,oBAAoB;QACzB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgEV,CAAC,IAAI,EAAE,CAAC;IACP,CAAC;CACF;AAjHD,oDAiHC"}
|