@forge/storage-data-recovery 2.0.0-next.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.txt +7 -0
- package/README.md +59 -0
- package/out/__test__/global-data-recovery.test.d.ts +2 -0
- package/out/__test__/global-data-recovery.test.d.ts.map +1 -0
- package/out/__test__/global-data-recovery.test.js +98 -0
- package/out/data-recovery.d.ts +23 -0
- package/out/data-recovery.d.ts.map +1 -0
- package/out/data-recovery.js +51 -0
- package/out/errors.d.ts +11 -0
- package/out/errors.d.ts.map +1 -0
- package/out/errors.js +26 -0
- package/out/index.d.ts +7 -0
- package/out/index.d.ts.map +1 -0
- package/out/index.js +48 -0
- package/out/storage-client.d.ts +9 -0
- package/out/storage-client.d.ts.map +1 -0
- package/out/storage-client.js +39 -0
- package/out/types.d.ts +40 -0
- package/out/types.d.ts.map +1 -0
- package/out/types.js +6 -0
- package/package.json +27 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright (c) 2025 Atlassian
|
|
2
|
+
Permission is hereby granted to use this software in accordance with the terms
|
|
3
|
+
and conditions outlined in the Atlassian Developer Terms, which can be found
|
|
4
|
+
at the following URL:
|
|
5
|
+
https://developer.atlassian.com/platform/marketplace/atlassian-developer-terms/
|
|
6
|
+
By using this software, you agree to comply with these terms and conditions.
|
|
7
|
+
If you do not agree with these terms, you are not permitted to use this software.
|
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Forge Storage Data Recovery
|
|
2
|
+
|
|
3
|
+
Standalone Library for Forge Storage Data Recovery operations.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { WhereConditions } from '@forge/kvs';
|
|
9
|
+
import { dataRecovery, StorageType, SnapshotNotFoundError } from '@forge/storage-data-recovery';
|
|
10
|
+
|
|
11
|
+
// Query data from a storage snapshot
|
|
12
|
+
const results = await dataRecovery('hot117987', 'kvs') // StorageType: 'kvs' | 'secret' | 'custom_entity'
|
|
13
|
+
.query()
|
|
14
|
+
.where('key', WhereConditions.beginsWith('value'))
|
|
15
|
+
.limit(10)
|
|
16
|
+
.cursor('...')
|
|
17
|
+
.getMany();
|
|
18
|
+
|
|
19
|
+
// Results structure
|
|
20
|
+
console.log(results.results); // Array of { key: string, value: T }
|
|
21
|
+
console.log(results.nextCursor); // Optional cursor for pagination
|
|
22
|
+
|
|
23
|
+
// Error handling
|
|
24
|
+
try {
|
|
25
|
+
const data = await dataRecovery('nonexistent-snapshot', 'kvs')
|
|
26
|
+
.query()
|
|
27
|
+
.getMany();
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (error instanceof SnapshotNotFoundError) {
|
|
30
|
+
console.log('Snapshot not found');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## API
|
|
36
|
+
|
|
37
|
+
### `dataRecovery(snapshotName: string, storageType: StorageType)`
|
|
38
|
+
|
|
39
|
+
Creates a recovery instance for the specified snapshot and storage type.
|
|
40
|
+
|
|
41
|
+
**Parameters:**
|
|
42
|
+
- `snapshotName`: Name of the storage snapshot (e.g., 'hot117987')
|
|
43
|
+
- `storageType`: Type of storage - `'kvs' | 'secret' | 'custom_entity'`
|
|
44
|
+
|
|
45
|
+
**Returns:** `DataRecoveryImpl` instance with query capabilities
|
|
46
|
+
|
|
47
|
+
### Query Methods
|
|
48
|
+
|
|
49
|
+
- `.query()`: Start building a query
|
|
50
|
+
- `.where(property, condition)`: Filter by key conditions (supports WhereConditions from @forge/kvs)
|
|
51
|
+
- `.limit(number)`: Limit number of results
|
|
52
|
+
- `.cursor(string)`: Set pagination cursor
|
|
53
|
+
- `.getMany<T>()`: Execute query and return results
|
|
54
|
+
|
|
55
|
+
### Error Types
|
|
56
|
+
|
|
57
|
+
- `RecoveryException`: Base recovery error
|
|
58
|
+
- `SnapshotNotFoundError`: Thrown when snapshot doesn't exist
|
|
59
|
+
- `InvalidStorageTypeError`: Thrown for invalid storage types
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"global-data-recovery.test.d.ts","sourceRoot":"","sources":["../../src/__test__/global-data-recovery.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const kvs_1 = require("@forge/kvs");
|
|
4
|
+
const index_1 = require("../index");
|
|
5
|
+
const storage_client_1 = require("../storage-client");
|
|
6
|
+
const data_recovery_1 = require("../data-recovery");
|
|
7
|
+
const types_1 = require("../types");
|
|
8
|
+
function prepare(response, snapshotName, storageType) {
|
|
9
|
+
const apiClient = jest.fn().mockResolvedValueOnce(response);
|
|
10
|
+
const storageClient = new storage_client_1.StorageClient(apiClient);
|
|
11
|
+
const sut = new data_recovery_1.DataRecoveryImpl(storageClient, snapshotName, storageType);
|
|
12
|
+
return {
|
|
13
|
+
apiClient,
|
|
14
|
+
storageClient,
|
|
15
|
+
sut
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
describe('dataRecovery', () => {
|
|
19
|
+
const snapshotName = 'test-snapshot';
|
|
20
|
+
const traceId = 'trace-id';
|
|
21
|
+
it('should be defined', () => {
|
|
22
|
+
expect(index_1.dataRecovery).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
it('should return a data recovery instance', () => {
|
|
25
|
+
const dataRecoveryInstance = (0, index_1.dataRecovery)(snapshotName, types_1.StorageTypeKVS);
|
|
26
|
+
expect(dataRecoveryInstance).toBeDefined();
|
|
27
|
+
});
|
|
28
|
+
it('should throw an error if the storage type is invalid', () => {
|
|
29
|
+
expect(() => (0, index_1.dataRecovery)(snapshotName, 'invalid')).toThrow(index_1.InvalidStorageTypeError);
|
|
30
|
+
});
|
|
31
|
+
it('should return a data recovery instance with the correct storage type', () => {
|
|
32
|
+
const dataRecoveryInstance = (0, index_1.dataRecovery)(snapshotName, types_1.StorageTypeKVS);
|
|
33
|
+
expect(dataRecoveryInstance.query).toBeDefined();
|
|
34
|
+
expect(dataRecoveryInstance.query().where('key', kvs_1.WhereConditions.beginsWith('test')).getMany).toBeDefined();
|
|
35
|
+
expect(dataRecoveryInstance.query().cursor('test').getMany).toBeDefined();
|
|
36
|
+
expect(dataRecoveryInstance.query().limit(10).getMany).toBeDefined();
|
|
37
|
+
});
|
|
38
|
+
it('should make a REST call to the data recovery API', async () => {
|
|
39
|
+
const response = new Response(JSON.stringify({
|
|
40
|
+
cursor: 'third-page',
|
|
41
|
+
data: [
|
|
42
|
+
{
|
|
43
|
+
key: 'foo',
|
|
44
|
+
value: { foo: 'bar' },
|
|
45
|
+
entityName: 'example',
|
|
46
|
+
provider: 'custom_entity',
|
|
47
|
+
createdAt: 1753852892506,
|
|
48
|
+
updatedAt: 1753852902502
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}), {
|
|
52
|
+
status: 200,
|
|
53
|
+
headers: { 'x-trace-id': traceId }
|
|
54
|
+
});
|
|
55
|
+
const { sut, apiClient } = prepare(response, snapshotName, types_1.StorageTypeCustomEntity);
|
|
56
|
+
const rs = await sut
|
|
57
|
+
.query()
|
|
58
|
+
.cursor('second-page')
|
|
59
|
+
.limit(1)
|
|
60
|
+
.where('key', kvs_1.WhereConditions.beginsWith('fo'))
|
|
61
|
+
.getMany();
|
|
62
|
+
expect(rs).toEqual({
|
|
63
|
+
results: [
|
|
64
|
+
{
|
|
65
|
+
key: 'foo',
|
|
66
|
+
value: { foo: 'bar' },
|
|
67
|
+
entityName: 'example',
|
|
68
|
+
provider: 'custom_entity',
|
|
69
|
+
createdAt: 1753852892506,
|
|
70
|
+
updatedAt: 1753852902502
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
nextCursor: 'third-page'
|
|
74
|
+
});
|
|
75
|
+
expect(apiClient).toHaveBeenCalledWith('/api/v1/data-recovery/query', {
|
|
76
|
+
body: JSON.stringify({
|
|
77
|
+
snapshotName: snapshotName,
|
|
78
|
+
provider: types_1.StorageTypeCustomEntity,
|
|
79
|
+
limit: 1,
|
|
80
|
+
after: 'second-page',
|
|
81
|
+
where: [{ property: 'key', condition: 'BEGINS_WITH', values: ['fo'] }]
|
|
82
|
+
}),
|
|
83
|
+
headers: {
|
|
84
|
+
'content-type': 'application/json'
|
|
85
|
+
},
|
|
86
|
+
method: 'POST'
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
it('should throw a SnapshotNotFoundError if the snapshot is not found', async () => {
|
|
90
|
+
const response = new Response('not found', {
|
|
91
|
+
status: 404,
|
|
92
|
+
headers: { 'x-trace-id': traceId }
|
|
93
|
+
});
|
|
94
|
+
const { sut } = prepare(response, snapshotName, types_1.StorageTypeCustomEntity);
|
|
95
|
+
const query = sut.query().cursor('second-page').limit(1).where('key', kvs_1.WhereConditions.beginsWith('fo'));
|
|
96
|
+
await expect(query.getMany()).rejects.toMatchObject(new index_1.SnapshotNotFoundError(snapshotName));
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { WhereConditions } from '@forge/kvs';
|
|
2
|
+
import { StorageClient } from './storage-client';
|
|
3
|
+
import { ListResult, RecoveryQueryBuilder, StorageType } from './types';
|
|
4
|
+
import { QueryOptions } from '@forge/kvs/out/interfaces/query';
|
|
5
|
+
export declare class RecoveryQueryBuilderImpl implements RecoveryQueryBuilder {
|
|
6
|
+
private storageClient;
|
|
7
|
+
private snapshotName;
|
|
8
|
+
private storageType;
|
|
9
|
+
private options;
|
|
10
|
+
constructor(storageClient: StorageClient, snapshotName: string, storageType: StorageType, options?: QueryOptions);
|
|
11
|
+
where(property: 'key', condition: ReturnType<typeof WhereConditions.beginsWith>): this;
|
|
12
|
+
cursor(cursor: string): this;
|
|
13
|
+
limit(limit: number): this;
|
|
14
|
+
getMany<T>(): Promise<ListResult<T>>;
|
|
15
|
+
}
|
|
16
|
+
export declare class DataRecoveryImpl {
|
|
17
|
+
private storageClient;
|
|
18
|
+
private snapshotName;
|
|
19
|
+
private storageType;
|
|
20
|
+
constructor(storageClient: StorageClient, snapshotName: string, storageType: StorageType);
|
|
21
|
+
query(): RecoveryQueryBuilder;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=data-recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-recovery.d.ts","sourceRoot":"","sources":["../src/data-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAE/D,qBAAa,wBAAyB,YAAW,oBAAoB;IAEjE,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,OAAO;gBAHP,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,WAAW,EACxB,OAAO,GAAE,YAAiB;IAGpC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,UAAU,CAAC,GAAG,IAAI;IAKtF,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAK5B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKpB,OAAO,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;CAS3C;AAED,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,WAAW;gBAFX,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,WAAW;IAGlC,KAAK,IAAI,oBAAoB;CAG9B"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataRecoveryImpl = exports.RecoveryQueryBuilderImpl = void 0;
|
|
4
|
+
class RecoveryQueryBuilderImpl {
|
|
5
|
+
storageClient;
|
|
6
|
+
snapshotName;
|
|
7
|
+
storageType;
|
|
8
|
+
options;
|
|
9
|
+
constructor(storageClient, snapshotName, storageType, options = {}) {
|
|
10
|
+
this.storageClient = storageClient;
|
|
11
|
+
this.snapshotName = snapshotName;
|
|
12
|
+
this.storageType = storageType;
|
|
13
|
+
this.options = options;
|
|
14
|
+
}
|
|
15
|
+
where(property, condition) {
|
|
16
|
+
this.options.where = [{ property, ...condition }];
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
cursor(cursor) {
|
|
20
|
+
this.options.cursor = cursor;
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
limit(limit) {
|
|
24
|
+
this.options.limit = limit;
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
async getMany() {
|
|
28
|
+
return await this.storageClient.query({
|
|
29
|
+
snapshotName: this.snapshotName,
|
|
30
|
+
provider: this.storageType,
|
|
31
|
+
limit: this.options.limit,
|
|
32
|
+
after: this.options.cursor,
|
|
33
|
+
where: this.options.where
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.RecoveryQueryBuilderImpl = RecoveryQueryBuilderImpl;
|
|
38
|
+
class DataRecoveryImpl {
|
|
39
|
+
storageClient;
|
|
40
|
+
snapshotName;
|
|
41
|
+
storageType;
|
|
42
|
+
constructor(storageClient, snapshotName, storageType) {
|
|
43
|
+
this.storageClient = storageClient;
|
|
44
|
+
this.snapshotName = snapshotName;
|
|
45
|
+
this.storageType = storageType;
|
|
46
|
+
}
|
|
47
|
+
query() {
|
|
48
|
+
return new RecoveryQueryBuilderImpl(this.storageClient, this.snapshotName, this.storageType);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.DataRecoveryImpl = DataRecoveryImpl;
|
package/out/errors.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class RecoveryException extends Error {
|
|
2
|
+
readonly code?: string | undefined;
|
|
3
|
+
constructor(message: string, code?: string | undefined);
|
|
4
|
+
}
|
|
5
|
+
export declare class SnapshotNotFoundError extends RecoveryException {
|
|
6
|
+
constructor(snapshotName: string);
|
|
7
|
+
}
|
|
8
|
+
export declare class InvalidStorageTypeError extends RecoveryException {
|
|
9
|
+
constructor(storageType: string);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,iBAAkB,SAAQ,KAAK;aAGxB,IAAI,CAAC;gBADrB,OAAO,EAAE,MAAM,EACC,IAAI,CAAC,oBAAQ;CAKhC;AAED,qBAAa,qBAAsB,SAAQ,iBAAiB;gBAC9C,YAAY,EAAE,MAAM;CAIjC;AAED,qBAAa,uBAAwB,SAAQ,iBAAiB;gBAChD,WAAW,EAAE,MAAM;CAIhC"}
|
package/out/errors.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InvalidStorageTypeError = exports.SnapshotNotFoundError = exports.RecoveryException = void 0;
|
|
4
|
+
class RecoveryException extends Error {
|
|
5
|
+
code;
|
|
6
|
+
constructor(message, code) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.name = 'RecoveryException';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.RecoveryException = RecoveryException;
|
|
13
|
+
class SnapshotNotFoundError extends RecoveryException {
|
|
14
|
+
constructor(snapshotName) {
|
|
15
|
+
super(`Snapshot '${snapshotName}' not found`, 'SNAPSHOT_NOT_FOUND');
|
|
16
|
+
this.name = 'SnapshotNotFoundError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.SnapshotNotFoundError = SnapshotNotFoundError;
|
|
20
|
+
class InvalidStorageTypeError extends RecoveryException {
|
|
21
|
+
constructor(storageType) {
|
|
22
|
+
super(`Invalid storage type '${storageType}'`, 'INVALID_STORAGE_TYPE');
|
|
23
|
+
this.name = 'InvalidStorageTypeError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.InvalidStorageTypeError = InvalidStorageTypeError;
|
package/out/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DataRecoveryImpl } from './data-recovery';
|
|
2
|
+
import { StorageType } from './types';
|
|
3
|
+
declare function dataRecovery(snapshotName: string, storageType: StorageType): DataRecoveryImpl;
|
|
4
|
+
export * from './errors';
|
|
5
|
+
export * from './types';
|
|
6
|
+
export { dataRecovery };
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGnD,OAAO,EAAE,WAAW,EAA8D,MAAM,SAAS,CAAC;AA6ClG,iBAAS,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,oBAMnE;AAED,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
package/out/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dataRecovery = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const data_recovery_1 = require("./data-recovery");
|
|
6
|
+
const errors_1 = require("./errors");
|
|
7
|
+
const storage_client_1 = require("./storage-client");
|
|
8
|
+
const types_1 = require("./types");
|
|
9
|
+
async function fetchDirectlyToKVS(path, options) {
|
|
10
|
+
const runtime = global.__forge_runtime__;
|
|
11
|
+
if (!runtime) {
|
|
12
|
+
throw new Error('Forge runtime not found');
|
|
13
|
+
}
|
|
14
|
+
const { proxy, kvs, tracing } = runtime;
|
|
15
|
+
return await global.__forge_fetch__({ type: 'kvs' }, path, {
|
|
16
|
+
...options,
|
|
17
|
+
headers: {
|
|
18
|
+
...options?.headers,
|
|
19
|
+
Authorization: `Bearer ${proxy.token}`,
|
|
20
|
+
Host: kvs?.host,
|
|
21
|
+
'x-b3-traceid': tracing.traceId,
|
|
22
|
+
'x-b3-spanid': tracing.spanId
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
async function fetchViaFPP(path, options) {
|
|
27
|
+
return await global.__forge_fetch__({
|
|
28
|
+
type: 'kvs',
|
|
29
|
+
provider: 'app',
|
|
30
|
+
remote: 'kvs'
|
|
31
|
+
}, path, options);
|
|
32
|
+
}
|
|
33
|
+
function buildFetchClient() {
|
|
34
|
+
const runtime = global.__forge_runtime__;
|
|
35
|
+
if (runtime?.kvs?.url && runtime?.kvs?.host) {
|
|
36
|
+
return fetchDirectlyToKVS;
|
|
37
|
+
}
|
|
38
|
+
return fetchViaFPP;
|
|
39
|
+
}
|
|
40
|
+
function dataRecovery(snapshotName, storageType) {
|
|
41
|
+
if (![types_1.StorageTypeKVS, types_1.StorageTypeSecret, types_1.StorageTypeCustomEntity].includes(storageType)) {
|
|
42
|
+
throw new errors_1.InvalidStorageTypeError(storageType);
|
|
43
|
+
}
|
|
44
|
+
return new data_recovery_1.DataRecoveryImpl(new storage_client_1.StorageClient(buildFetchClient()), snapshotName, storageType);
|
|
45
|
+
}
|
|
46
|
+
exports.dataRecovery = dataRecovery;
|
|
47
|
+
tslib_1.__exportStar(require("./errors"), exports);
|
|
48
|
+
tslib_1.__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FetchMethod } from '@forge/api';
|
|
2
|
+
import { ListResult, QueryRequest } from './types';
|
|
3
|
+
export declare class StorageClient {
|
|
4
|
+
private apiClient;
|
|
5
|
+
constructor(apiClient: FetchMethod);
|
|
6
|
+
query<T>(body: QueryRequest): Promise<ListResult<T>>;
|
|
7
|
+
private request;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=storage-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-client.d.ts","sourceRoot":"","sources":["../src/storage-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAiB,MAAM,SAAS,CAAC;AAGlE,qBAAa,aAAa;IACZ,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,WAAW;IAEpC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAQ5C,OAAO;CAsBtB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StorageClient = void 0;
|
|
4
|
+
const kvs_1 = require("@forge/kvs");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
class StorageClient {
|
|
7
|
+
apiClient;
|
|
8
|
+
constructor(apiClient) {
|
|
9
|
+
this.apiClient = apiClient;
|
|
10
|
+
}
|
|
11
|
+
async query(body) {
|
|
12
|
+
const rs = await this.request(`/api/v1/data-recovery/query`, body);
|
|
13
|
+
return {
|
|
14
|
+
results: rs.data,
|
|
15
|
+
nextCursor: rs.cursor
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
async request(path, body) {
|
|
19
|
+
const requestBody = {
|
|
20
|
+
method: 'POST',
|
|
21
|
+
body: JSON.stringify(body),
|
|
22
|
+
headers: {
|
|
23
|
+
'content-type': 'application/json'
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const response = await this.apiClient(path, requestBody);
|
|
27
|
+
const responseText = await response.text();
|
|
28
|
+
if (response.status === 404) {
|
|
29
|
+
throw new errors_1.SnapshotNotFoundError(body.snapshotName);
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
return JSON.parse(responseText);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
throw new kvs_1.ForgeKvsError(`Unexpected error. Response was not valid JSON: ${responseText}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.StorageClient = StorageClient;
|
package/out/types.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { WhereConditions } from '@forge/kvs';
|
|
2
|
+
export declare type QueryWhere = {
|
|
3
|
+
condition: 'BEGINS_WITH';
|
|
4
|
+
property: 'key';
|
|
5
|
+
values: Array<unknown>;
|
|
6
|
+
};
|
|
7
|
+
export declare type QueryRequest = {
|
|
8
|
+
snapshotName: string;
|
|
9
|
+
provider: StorageType;
|
|
10
|
+
limit?: number;
|
|
11
|
+
after?: string;
|
|
12
|
+
where?: Array<QueryWhere>;
|
|
13
|
+
};
|
|
14
|
+
export declare type QueryResponse<T> = {
|
|
15
|
+
data: Array<DataRecoverySchema<T>>;
|
|
16
|
+
cursor?: string;
|
|
17
|
+
};
|
|
18
|
+
export declare type DataRecoverySchema<T> = {
|
|
19
|
+
key: string;
|
|
20
|
+
value: T;
|
|
21
|
+
entityName?: string;
|
|
22
|
+
provider: 'kvs' | 'secret' | 'custom_entity';
|
|
23
|
+
createdAt: number;
|
|
24
|
+
updatedAt: number;
|
|
25
|
+
};
|
|
26
|
+
export declare const StorageTypeKVS = "kvs";
|
|
27
|
+
export declare const StorageTypeSecret = "secret";
|
|
28
|
+
export declare const StorageTypeCustomEntity = "custom_entity";
|
|
29
|
+
export declare type StorageType = 'kvs' | 'secret' | 'custom_entity';
|
|
30
|
+
export interface ListResult<T> {
|
|
31
|
+
results: DataRecoverySchema<T>[];
|
|
32
|
+
nextCursor?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface RecoveryQueryBuilder {
|
|
35
|
+
where(property: 'key', condition: ReturnType<typeof WhereConditions.beginsWith>): RecoveryQueryBuilder;
|
|
36
|
+
cursor(cursor: string): RecoveryQueryBuilder;
|
|
37
|
+
limit(limit: number): RecoveryQueryBuilder;
|
|
38
|
+
getMany<T>(): Promise<ListResult<T>>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,oBAAY,UAAU,GAAG;IACvB,SAAS,EAAE,aAAa,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC;IAChB,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CACxB,CAAC;AAEF,oBAAY,YAAY,GAAG;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,WAAW,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;CAC3B,CAAC;AAEF,oBAAY,aAAa,CAAC,CAAC,IAAI;IAC7B,IAAI,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,oBAAY,kBAAkB,CAAC,CAAC,IAAI;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,CAAC,CAAC;IACT,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,eAAe,CAAC;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,cAAc,QAAQ,CAAC;AACpC,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD,oBAAY,WAAW,GAAG,KAAK,GAAG,QAAQ,GAAG,eAAe,CAAC;AAE7D,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,UAAU,CAAC,GAAG,oBAAoB,CAAC;IACvG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CAAC;IAC7C,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,oBAAoB,CAAC;IAC3C,OAAO,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;CACtC"}
|
package/out/types.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StorageTypeCustomEntity = exports.StorageTypeSecret = exports.StorageTypeKVS = void 0;
|
|
4
|
+
exports.StorageTypeKVS = 'kvs';
|
|
5
|
+
exports.StorageTypeSecret = 'secret';
|
|
6
|
+
exports.StorageTypeCustomEntity = 'custom_entity';
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@forge/storage-data-recovery",
|
|
3
|
+
"version": "2.0.0-next.0",
|
|
4
|
+
"description": "Forge Storage Data Recovery SDK",
|
|
5
|
+
"author": "Atlassian",
|
|
6
|
+
"license": "SEE LICENSE IN LICENSE.txt",
|
|
7
|
+
"main": "out/index.js",
|
|
8
|
+
"types": "out/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"out"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "yarn run clean && yarn run compile",
|
|
14
|
+
"clean": "rm -rf ./out && rm -f tsconfig.tsbuildinfo",
|
|
15
|
+
"compile": "tsc -b -v"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "20.19.1"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@forge/api": "6.1.5-next.1",
|
|
22
|
+
"@forge/kvs": "1.0.9-next.0"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"registry": "https://packages.atlassian.com/api/npm/npm-public/"
|
|
26
|
+
}
|
|
27
|
+
}
|