@flusys/nestjs-storage 1.0.0-beta → 1.1.0-beta

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/README.md CHANGED
@@ -412,6 +412,12 @@ export class StorageConfig extends Identity {
412
412
  @Column({ type: 'json' })
413
413
  config: Record<string, any>; // Provider-specific config
414
414
 
415
+ @Column({ default: true })
416
+ isActive: boolean; // Whether config is active and usable
417
+
418
+ @Column({ default: false })
419
+ isDefault: boolean; // Set as default configuration
420
+
415
421
  @Column({ nullable: true })
416
422
  companyId: string; // Company scope (when enabled)
417
423
  }
@@ -438,6 +444,8 @@ export class SetupService {
438
444
  accessKeyId: process.env.AWS_ACCESS_KEY,
439
445
  secretAccessKey: process.env.AWS_SECRET_KEY,
440
446
  },
447
+ isActive: true,
448
+ isDefault: true, // Set as default configuration
441
449
  },
442
450
  user,
443
451
  );
@@ -453,6 +461,8 @@ export class SetupService {
453
461
  privateKey: process.env.SFTP_PRIVATE_KEY,
454
462
  basePath: '/backups',
455
463
  },
464
+ isActive: true,
465
+ isDefault: false, // Not the default
456
466
  },
457
467
  user,
458
468
  );
@@ -462,25 +472,34 @@ export class SetupService {
462
472
 
463
473
  ### Default Configuration Resolution
464
474
 
475
+ When `storageConfigId` is not provided for uploads, the system automatically resolves the default config:
476
+
477
+ 1. **Priority 1:** Find config with `isDefault: true` and `isActive: true`
478
+ 2. **Priority 2:** Fall back to oldest active config
479
+
465
480
  ```typescript
466
481
  // StorageProviderConfigService
467
482
  async getDefaultConfig(user?: ILoggedUserInfo): Promise<StorageConfigBase | null> {
483
+ await this.ensureRepositoryInitialized();
484
+
485
+ const baseWhere: any = { isActive: true };
486
+
468
487
  // Filter by company if enabled
469
- const where: any = {};
470
- if (this.isCompanyFeatureEnabled() && user?.companyId) {
471
- where.companyId = user.companyId;
488
+ if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
489
+ baseWhere.companyId = user.companyId;
472
490
  }
473
491
 
474
- // First try 'default' named config
492
+ // First try to find config marked as default
475
493
  const defaultConfig = await this.repository.findOne({
476
- where: { ...where, name: 'default' },
494
+ where: { ...baseWhere, isDefault: true },
495
+ order: { createdAt: 'ASC' },
477
496
  });
478
497
 
479
498
  if (defaultConfig) return defaultConfig;
480
499
 
481
- // Fall back to any available config
500
+ // Fall back to oldest active config
482
501
  return await this.repository.findOne({
483
- where,
502
+ where: baseWhere,
484
503
  order: { createdAt: 'ASC' },
485
504
  });
486
505
  }
@@ -50,6 +50,8 @@ let CreateStorageConfigDto = class CreateStorageConfigDto {
50
50
  _define_property(this, "name", void 0);
51
51
  _define_property(this, "storage", void 0);
52
52
  _define_property(this, "config", void 0);
53
+ _define_property(this, "isActive", void 0);
54
+ _define_property(this, "isDefault", void 0);
53
55
  }
54
56
  };
55
57
  _ts_decorate([
@@ -97,12 +99,32 @@ _ts_decorate([
97
99
  (0, _classvalidator.IsNotEmpty)(),
98
100
  _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
99
101
  ], CreateStorageConfigDto.prototype, "config", void 0);
102
+ _ts_decorate([
103
+ (0, _swagger.ApiPropertyOptional)({
104
+ example: true,
105
+ description: 'Whether storage configuration is active'
106
+ }),
107
+ (0, _classvalidator.IsBoolean)(),
108
+ (0, _classvalidator.IsOptional)(),
109
+ _ts_metadata("design:type", Boolean)
110
+ ], CreateStorageConfigDto.prototype, "isActive", void 0);
111
+ _ts_decorate([
112
+ (0, _swagger.ApiPropertyOptional)({
113
+ example: false,
114
+ description: 'Set as default storage configuration'
115
+ }),
116
+ (0, _classvalidator.IsBoolean)(),
117
+ (0, _classvalidator.IsOptional)(),
118
+ _ts_metadata("design:type", Boolean)
119
+ ], CreateStorageConfigDto.prototype, "isDefault", void 0);
100
120
  let UpdateStorageConfigDto = class UpdateStorageConfigDto {
101
121
  constructor(){
102
122
  _define_property(this, "id", void 0);
103
123
  _define_property(this, "name", void 0);
104
124
  _define_property(this, "storage", void 0);
105
125
  _define_property(this, "config", void 0);
126
+ _define_property(this, "isActive", void 0);
127
+ _define_property(this, "isDefault", void 0);
106
128
  }
107
129
  };
108
130
  _ts_decorate([
@@ -157,8 +179,26 @@ _ts_decorate([
157
179
  (0, _classvalidator.IsOptional)(),
158
180
  _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
159
181
  ], UpdateStorageConfigDto.prototype, "config", void 0);
182
+ _ts_decorate([
183
+ (0, _swagger.ApiPropertyOptional)({
184
+ example: true,
185
+ description: 'Whether storage configuration is active'
186
+ }),
187
+ (0, _classvalidator.IsBoolean)(),
188
+ (0, _classvalidator.IsOptional)(),
189
+ _ts_metadata("design:type", Boolean)
190
+ ], UpdateStorageConfigDto.prototype, "isActive", void 0);
191
+ _ts_decorate([
192
+ (0, _swagger.ApiPropertyOptional)({
193
+ example: false,
194
+ description: 'Set as default storage configuration'
195
+ }),
196
+ (0, _classvalidator.IsBoolean)(),
197
+ (0, _classvalidator.IsOptional)(),
198
+ _ts_metadata("design:type", Boolean)
199
+ ], UpdateStorageConfigDto.prototype, "isDefault", void 0);
160
200
  let StorageConfigResponseDto = class StorageConfigResponseDto extends _dtos.IdentityResponseDto {
161
201
  constructor(...args){
162
- super(...args), _define_property(this, "name", void 0), _define_property(this, "storage", void 0), _define_property(this, "config", void 0);
202
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "storage", void 0), _define_property(this, "config", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isDefault", void 0);
163
203
  }
164
204
  };
@@ -35,8 +35,7 @@ function _ts_metadata(k, v) {
35
35
  }
36
36
  let StorageConfigBase = class StorageConfigBase extends _entities.Identity {
37
37
  constructor(...args){
38
- super(...args), _define_property(this, "name", void 0), _define_property(this, "storage", void 0), // add config for storage
39
- _define_property(this, "config", void 0);
38
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "storage", void 0), _define_property(this, "config", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isDefault", void 0);
40
39
  }
41
40
  };
42
41
  _ts_decorate([
@@ -62,3 +61,33 @@ _ts_decorate([
62
61
  }),
63
62
  _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
64
63
  ], StorageConfigBase.prototype, "config", void 0);
64
+ _ts_decorate([
65
+ (0, _typeorm.Column)({
66
+ type: 'boolean',
67
+ default: true,
68
+ name: 'is_active'
69
+ }),
70
+ _ts_metadata("design:type", Boolean)
71
+ ], StorageConfigBase.prototype, "isActive", void 0);
72
+ _ts_decorate([
73
+ (0, _typeorm.Column)({
74
+ type: 'boolean',
75
+ default: false,
76
+ name: 'is_default'
77
+ }),
78
+ _ts_metadata("design:type", Boolean)
79
+ ], StorageConfigBase.prototype, "isDefault", void 0);
80
+ StorageConfigBase = _ts_decorate([
81
+ (0, _typeorm.Index)([
82
+ 'name'
83
+ ]),
84
+ (0, _typeorm.Index)([
85
+ 'storage'
86
+ ]),
87
+ (0, _typeorm.Index)([
88
+ 'isActive'
89
+ ]),
90
+ (0, _typeorm.Index)([
91
+ 'isDefault'
92
+ ])
93
+ ], StorageConfigBase);
@@ -65,6 +65,8 @@ let StorageProviderConfigService = class StorageProviderConfigService extends _c
65
65
  'name',
66
66
  'storage',
67
67
  'config',
68
+ 'isActive',
69
+ 'isDefault',
68
70
  'createdAt',
69
71
  'updatedAt'
70
72
  ];
@@ -102,19 +104,21 @@ let StorageProviderConfigService = class StorageProviderConfigService extends _c
102
104
  }
103
105
  /**
104
106
  * Get default storage configuration (scoped to user's company if enabled)
105
- * Falls back to any available config if 'default' not found
107
+ * Priority: isDefault=true > any active config (oldest first)
106
108
  */ async getDefaultConfig(user) {
107
109
  await this.ensureRepositoryInitialized();
108
- const baseWhere = {};
110
+ const baseWhere = {
111
+ isActive: true
112
+ };
109
113
  // Filter by company only if company feature is enabled and user is provided
110
114
  if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
111
115
  baseWhere.companyId = user.companyId;
112
116
  }
113
- // First try to find config named 'default'
117
+ // First try to find config marked as default
114
118
  const defaultConfig = await this.repository.findOne({
115
119
  where: {
116
120
  ...baseWhere,
117
- name: 'default'
121
+ isDefault: true
118
122
  },
119
123
  order: {
120
124
  createdAt: 'ASC'
@@ -123,7 +127,7 @@ let StorageProviderConfigService = class StorageProviderConfigService extends _c
123
127
  if (defaultConfig) {
124
128
  return defaultConfig;
125
129
  }
126
- // Fall back to any available config for this company/user
130
+ // Fall back to any available active config (oldest first for consistency)
127
131
  return await this.repository.findOne({
128
132
  where: baseWhere,
129
133
  order: {
@@ -136,7 +140,8 @@ let StorageProviderConfigService = class StorageProviderConfigService extends _c
136
140
  */ async getConfigByType(storage, user) {
137
141
  await this.ensureRepositoryInitialized();
138
142
  const where = {
139
- storage
143
+ storage,
144
+ isActive: true
140
145
  };
141
146
  // Filter by company only if company feature is enabled and user is provided
142
147
  if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
@@ -5,6 +5,8 @@ export declare class CreateStorageConfigDto implements Record<string, unknown> {
5
5
  name: string;
6
6
  storage: FileLocationEnum;
7
7
  config: Record<string, any>;
8
+ isActive?: boolean;
9
+ isDefault?: boolean;
8
10
  }
9
11
  export declare class UpdateStorageConfigDto implements Record<string, unknown> {
10
12
  [key: string]: unknown;
@@ -12,10 +14,14 @@ export declare class UpdateStorageConfigDto implements Record<string, unknown> {
12
14
  name?: string;
13
15
  storage?: FileLocationEnum;
14
16
  config?: Record<string, any>;
17
+ isActive?: boolean;
18
+ isDefault?: boolean;
15
19
  }
16
20
  export declare class StorageConfigResponseDto extends IdentityResponseDto implements Record<string, unknown> {
17
21
  [key: string]: unknown;
18
22
  name: string;
19
23
  storage: FileLocationEnum;
20
24
  config: Record<string, any>;
25
+ isActive: boolean;
26
+ isDefault: boolean;
21
27
  }
@@ -4,4 +4,6 @@ export declare abstract class StorageConfigBase extends Identity {
4
4
  name: string;
5
5
  storage: FileLocationEnum;
6
6
  config: Record<string, any>;
7
+ isActive: boolean;
8
+ isDefault: boolean;
7
9
  }
@@ -23,7 +23,7 @@ function _ts_metadata(k, v) {
23
23
  import { IdentityResponseDto } from '@flusys/nestjs-shared/dtos';
24
24
  import { FileLocationEnum } from '../enums';
25
25
  import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
26
- import { IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, MaxLength } from 'class-validator';
26
+ import { IsBoolean, IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, MaxLength } from 'class-validator';
27
27
  /**
28
28
  * DTO for creating storage configuration
29
29
  */ export class CreateStorageConfigDto {
@@ -31,6 +31,8 @@ import { IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, MaxLength } from 'c
31
31
  _define_property(this, "name", void 0);
32
32
  _define_property(this, "storage", void 0);
33
33
  _define_property(this, "config", void 0);
34
+ _define_property(this, "isActive", void 0);
35
+ _define_property(this, "isDefault", void 0);
34
36
  }
35
37
  }
36
38
  _ts_decorate([
@@ -78,6 +80,24 @@ _ts_decorate([
78
80
  IsNotEmpty(),
79
81
  _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
80
82
  ], CreateStorageConfigDto.prototype, "config", void 0);
83
+ _ts_decorate([
84
+ ApiPropertyOptional({
85
+ example: true,
86
+ description: 'Whether storage configuration is active'
87
+ }),
88
+ IsBoolean(),
89
+ IsOptional(),
90
+ _ts_metadata("design:type", Boolean)
91
+ ], CreateStorageConfigDto.prototype, "isActive", void 0);
92
+ _ts_decorate([
93
+ ApiPropertyOptional({
94
+ example: false,
95
+ description: 'Set as default storage configuration'
96
+ }),
97
+ IsBoolean(),
98
+ IsOptional(),
99
+ _ts_metadata("design:type", Boolean)
100
+ ], CreateStorageConfigDto.prototype, "isDefault", void 0);
81
101
  /**
82
102
  * DTO for updating storage configuration
83
103
  */ export class UpdateStorageConfigDto {
@@ -86,6 +106,8 @@ _ts_decorate([
86
106
  _define_property(this, "name", void 0);
87
107
  _define_property(this, "storage", void 0);
88
108
  _define_property(this, "config", void 0);
109
+ _define_property(this, "isActive", void 0);
110
+ _define_property(this, "isDefault", void 0);
89
111
  }
90
112
  }
91
113
  _ts_decorate([
@@ -140,10 +162,28 @@ _ts_decorate([
140
162
  IsOptional(),
141
163
  _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
142
164
  ], UpdateStorageConfigDto.prototype, "config", void 0);
165
+ _ts_decorate([
166
+ ApiPropertyOptional({
167
+ example: true,
168
+ description: 'Whether storage configuration is active'
169
+ }),
170
+ IsBoolean(),
171
+ IsOptional(),
172
+ _ts_metadata("design:type", Boolean)
173
+ ], UpdateStorageConfigDto.prototype, "isActive", void 0);
174
+ _ts_decorate([
175
+ ApiPropertyOptional({
176
+ example: false,
177
+ description: 'Set as default storage configuration'
178
+ }),
179
+ IsBoolean(),
180
+ IsOptional(),
181
+ _ts_metadata("design:type", Boolean)
182
+ ], UpdateStorageConfigDto.prototype, "isDefault", void 0);
143
183
  /**
144
184
  * Response DTO for storage configuration
145
185
  */ export class StorageConfigResponseDto extends IdentityResponseDto {
146
186
  constructor(...args){
147
- super(...args), _define_property(this, "name", void 0), _define_property(this, "storage", void 0), _define_property(this, "config", void 0);
187
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "storage", void 0), _define_property(this, "config", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isDefault", void 0);
148
188
  }
149
189
  }
@@ -22,14 +22,10 @@ function _ts_metadata(k, v) {
22
22
  }
23
23
  import { Identity } from '@flusys/nestjs-shared/entities';
24
24
  import { FileLocationEnum } from '../enums';
25
- import { Column } from 'typeorm';
26
- /**
27
- * Base StorageConfig Entity
28
- * Contains common fields shared by both StorageConfig and StorageConfigWithCompany
29
- */ export class StorageConfigBase extends Identity {
25
+ import { Column, Index } from 'typeorm';
26
+ export class StorageConfigBase extends Identity {
30
27
  constructor(...args){
31
- super(...args), _define_property(this, "name", void 0), _define_property(this, "storage", void 0), // add config for storage
32
- _define_property(this, "config", void 0);
28
+ super(...args), _define_property(this, "name", void 0), _define_property(this, "storage", void 0), _define_property(this, "config", void 0), _define_property(this, "isActive", void 0), _define_property(this, "isDefault", void 0);
33
29
  }
34
30
  }
35
31
  _ts_decorate([
@@ -55,3 +51,33 @@ _ts_decorate([
55
51
  }),
56
52
  _ts_metadata("design:type", typeof Record === "undefined" ? Object : Record)
57
53
  ], StorageConfigBase.prototype, "config", void 0);
54
+ _ts_decorate([
55
+ Column({
56
+ type: 'boolean',
57
+ default: true,
58
+ name: 'is_active'
59
+ }),
60
+ _ts_metadata("design:type", Boolean)
61
+ ], StorageConfigBase.prototype, "isActive", void 0);
62
+ _ts_decorate([
63
+ Column({
64
+ type: 'boolean',
65
+ default: false,
66
+ name: 'is_default'
67
+ }),
68
+ _ts_metadata("design:type", Boolean)
69
+ ], StorageConfigBase.prototype, "isDefault", void 0);
70
+ StorageConfigBase = _ts_decorate([
71
+ Index([
72
+ 'name'
73
+ ]),
74
+ Index([
75
+ 'storage'
76
+ ]),
77
+ Index([
78
+ 'isActive'
79
+ ]),
80
+ Index([
81
+ 'isDefault'
82
+ ])
83
+ ], StorageConfigBase);
@@ -55,6 +55,8 @@ export class StorageProviderConfigService extends RequestScopedApiService {
55
55
  'name',
56
56
  'storage',
57
57
  'config',
58
+ 'isActive',
59
+ 'isDefault',
58
60
  'createdAt',
59
61
  'updatedAt'
60
62
  ];
@@ -92,19 +94,21 @@ export class StorageProviderConfigService extends RequestScopedApiService {
92
94
  }
93
95
  /**
94
96
  * Get default storage configuration (scoped to user's company if enabled)
95
- * Falls back to any available config if 'default' not found
97
+ * Priority: isDefault=true > any active config (oldest first)
96
98
  */ async getDefaultConfig(user) {
97
99
  await this.ensureRepositoryInitialized();
98
- const baseWhere = {};
100
+ const baseWhere = {
101
+ isActive: true
102
+ };
99
103
  // Filter by company only if company feature is enabled and user is provided
100
104
  if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
101
105
  baseWhere.companyId = user.companyId;
102
106
  }
103
- // First try to find config named 'default'
107
+ // First try to find config marked as default
104
108
  const defaultConfig = await this.repository.findOne({
105
109
  where: {
106
110
  ...baseWhere,
107
- name: 'default'
111
+ isDefault: true
108
112
  },
109
113
  order: {
110
114
  createdAt: 'ASC'
@@ -113,7 +117,7 @@ export class StorageProviderConfigService extends RequestScopedApiService {
113
117
  if (defaultConfig) {
114
118
  return defaultConfig;
115
119
  }
116
- // Fall back to any available config for this company/user
120
+ // Fall back to any available active config (oldest first for consistency)
117
121
  return await this.repository.findOne({
118
122
  where: baseWhere,
119
123
  order: {
@@ -126,7 +130,8 @@ export class StorageProviderConfigService extends RequestScopedApiService {
126
130
  */ async getConfigByType(storage, user) {
127
131
  await this.ensureRepositoryInitialized();
128
132
  const where = {
129
- storage
133
+ storage,
134
+ isActive: true
130
135
  };
131
136
  // Filter by company only if company feature is enabled and user is provided
132
137
  if (this.storageConfig.isCompanyFeatureEnabled() && user?.companyId) {
@@ -4,6 +4,8 @@ export interface IStorageConfig extends IIdentity {
4
4
  name: string;
5
5
  storage: FileLocationEnum;
6
6
  config: Record<string, any>;
7
+ isActive: boolean;
8
+ isDefault: boolean;
7
9
  companyId?: string | null;
8
10
  }
9
11
  export interface IAwsS3Config {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flusys/nestjs-storage",
3
- "version": "1.0.0-beta",
3
+ "version": "1.1.0-beta",
4
4
  "description": "Modular storage package with optional AWS S3, Azure Blob, and SFTP providers",
5
5
  "main": "cjs/index.js",
6
6
  "module": "fesm/index.js",
@@ -128,7 +128,7 @@
128
128
  }
129
129
  },
130
130
  "dependencies": {
131
- "@flusys/nestjs-core": "1.0.0-beta",
132
- "@flusys/nestjs-shared": "1.0.0-beta"
131
+ "@flusys/nestjs-core": "1.1.0-beta",
132
+ "@flusys/nestjs-shared": "1.1.0-beta"
133
133
  }
134
134
  }