@infrascan/s3-connector 0.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/README.md +42 -0
- package/dist/index.d.mts +47 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +153 -0
- package/dist/index.mjs +136 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @infrascan/s3-connector
|
|
2
|
+
|
|
3
|
+
Infrascan connectors act as the plumbing between the Infrascan SDK and wherever you persist your scan state.
|
|
4
|
+
|
|
5
|
+
The S3 connector uses an AWS S3 Bucket to store its state. This connector library exposes an S3Connector class as the default export, which wraps an cache internally to reduce the overhead of S3 reads.
|
|
6
|
+
|
|
7
|
+
All state files are written into the bucket in the format: /service-function/account/region.json.
|
|
8
|
+
This is to support both searching state globally and reading state by function call per region.
|
|
9
|
+
|
|
10
|
+
## Quickstart
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
import { fromIni } from "@aws-sdk/credential-providers";
|
|
14
|
+
import { S3Client } from "@aws-sdk/s3-client";
|
|
15
|
+
import Infrascan from "@infrascan/sdk";
|
|
16
|
+
import S3Connector from "@infrascan/s3-connector";
|
|
17
|
+
import { registerAwsScanners } from "@infrascan/aws";
|
|
18
|
+
|
|
19
|
+
const credentials = fromIni({ profile: "dev" });
|
|
20
|
+
const s3Client = new S3Client({ credentials });
|
|
21
|
+
const connector = new S3Connector({
|
|
22
|
+
S3: s3Client,
|
|
23
|
+
prefix: 'my-scan-tenant',
|
|
24
|
+
bucket: 'my-scan-output-bucket'
|
|
25
|
+
});
|
|
26
|
+
const infrascan = registerAwsScanners(new Infrascan());
|
|
27
|
+
|
|
28
|
+
infrascan.performScan(
|
|
29
|
+
credentials,
|
|
30
|
+
connector
|
|
31
|
+
).then(function (scanMetadata) {
|
|
32
|
+
console.log("Scan Complete!", scanMetadata);
|
|
33
|
+
return infrascan.generateGraph(
|
|
34
|
+
scanMetadata,
|
|
35
|
+
connector
|
|
36
|
+
);
|
|
37
|
+
}).then(function (graphData) {
|
|
38
|
+
console.log("Graph generated!", graphData);
|
|
39
|
+
}).catch(function (err) {
|
|
40
|
+
console.error("Failed to scan", err);
|
|
41
|
+
});
|
|
42
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { S3Client, PutObjectCommandOutput } from '@aws-sdk/client-s3';
|
|
2
|
+
|
|
3
|
+
declare class Cache<T> {
|
|
4
|
+
sizeLimit: number;
|
|
5
|
+
size: number;
|
|
6
|
+
state: Record<string, T>;
|
|
7
|
+
keyOrders: Array<string>;
|
|
8
|
+
constructor(maxSize: number);
|
|
9
|
+
set(key: string, val: T): void;
|
|
10
|
+
get(key: string): T | undefined;
|
|
11
|
+
has(key: string): boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ConstructorArgs {
|
|
15
|
+
S3: S3Client;
|
|
16
|
+
prefix: string;
|
|
17
|
+
bucket: string;
|
|
18
|
+
cacheLimit?: number;
|
|
19
|
+
}
|
|
20
|
+
declare class S3Connector {
|
|
21
|
+
S3: S3Client;
|
|
22
|
+
prefix: string;
|
|
23
|
+
bucket: string;
|
|
24
|
+
cache: Cache<any>;
|
|
25
|
+
constructor({ S3, prefix, bucket, cacheLimit }: ConstructorArgs);
|
|
26
|
+
recordServiceCall(filePath: string, state: any): Promise<PutObjectCommandOutput>;
|
|
27
|
+
readStateForCall(filePath: string): Promise<any>;
|
|
28
|
+
/**
|
|
29
|
+
* Format for file paths is somewhat unintuitive — the account and region are put at the end of the path
|
|
30
|
+
* This makes it easier for retrieving global state by service and function call where only list by prefix is supported (e.g. S3)
|
|
31
|
+
* Example:
|
|
32
|
+
* - /1234567890/us-east-1/Lambda/listFunctions.json cannot be globally listed by prefix, only by account and region
|
|
33
|
+
* - /Lambda-listFunctions/1234567890/us-east-1.json can be listed by function which allows for cross account resolution
|
|
34
|
+
*/
|
|
35
|
+
buildFilePathForServiceCall(account: string, region: string, service: string, functionName: string): string;
|
|
36
|
+
onServiceScanCompleteCallback(account: string, region: string, service: string, functionName: string, functionState: any): Promise<PutObjectCommandOutput>;
|
|
37
|
+
resolveStateForServiceFunction(account: string, region: string, service: string, functionCall: string): Promise<any>;
|
|
38
|
+
listObjectsForService(service: string, functionCall: string): Promise<Array<string>>;
|
|
39
|
+
getGlobalStateForServiceFunction(service: string, functionCall: string): Promise<Array<any | undefined>>;
|
|
40
|
+
getMetadataPath(): string;
|
|
41
|
+
writeMetadata(metadata: any): Promise<PutObjectCommandOutput>;
|
|
42
|
+
readMetadata(): Promise<any>;
|
|
43
|
+
getGraphPath(): string;
|
|
44
|
+
writeGraphData(graphBlob: any): Promise<PutObjectCommandOutput>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { ConstructorArgs, S3Connector as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { S3Client, PutObjectCommandOutput } from '@aws-sdk/client-s3';
|
|
2
|
+
|
|
3
|
+
declare class Cache<T> {
|
|
4
|
+
sizeLimit: number;
|
|
5
|
+
size: number;
|
|
6
|
+
state: Record<string, T>;
|
|
7
|
+
keyOrders: Array<string>;
|
|
8
|
+
constructor(maxSize: number);
|
|
9
|
+
set(key: string, val: T): void;
|
|
10
|
+
get(key: string): T | undefined;
|
|
11
|
+
has(key: string): boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ConstructorArgs {
|
|
15
|
+
S3: S3Client;
|
|
16
|
+
prefix: string;
|
|
17
|
+
bucket: string;
|
|
18
|
+
cacheLimit?: number;
|
|
19
|
+
}
|
|
20
|
+
declare class S3Connector {
|
|
21
|
+
S3: S3Client;
|
|
22
|
+
prefix: string;
|
|
23
|
+
bucket: string;
|
|
24
|
+
cache: Cache<any>;
|
|
25
|
+
constructor({ S3, prefix, bucket, cacheLimit }: ConstructorArgs);
|
|
26
|
+
recordServiceCall(filePath: string, state: any): Promise<PutObjectCommandOutput>;
|
|
27
|
+
readStateForCall(filePath: string): Promise<any>;
|
|
28
|
+
/**
|
|
29
|
+
* Format for file paths is somewhat unintuitive — the account and region are put at the end of the path
|
|
30
|
+
* This makes it easier for retrieving global state by service and function call where only list by prefix is supported (e.g. S3)
|
|
31
|
+
* Example:
|
|
32
|
+
* - /1234567890/us-east-1/Lambda/listFunctions.json cannot be globally listed by prefix, only by account and region
|
|
33
|
+
* - /Lambda-listFunctions/1234567890/us-east-1.json can be listed by function which allows for cross account resolution
|
|
34
|
+
*/
|
|
35
|
+
buildFilePathForServiceCall(account: string, region: string, service: string, functionName: string): string;
|
|
36
|
+
onServiceScanCompleteCallback(account: string, region: string, service: string, functionName: string, functionState: any): Promise<PutObjectCommandOutput>;
|
|
37
|
+
resolveStateForServiceFunction(account: string, region: string, service: string, functionCall: string): Promise<any>;
|
|
38
|
+
listObjectsForService(service: string, functionCall: string): Promise<Array<string>>;
|
|
39
|
+
getGlobalStateForServiceFunction(service: string, functionCall: string): Promise<Array<any | undefined>>;
|
|
40
|
+
getMetadataPath(): string;
|
|
41
|
+
writeMetadata(metadata: any): Promise<PutObjectCommandOutput>;
|
|
42
|
+
readMetadata(): Promise<any>;
|
|
43
|
+
getGraphPath(): string;
|
|
44
|
+
writeGraphData(graphBlob: any): Promise<PutObjectCommandOutput>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { ConstructorArgs, S3Connector as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
default: () => S3Connector
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(src_exports);
|
|
26
|
+
var import_client_s3 = require("@aws-sdk/client-s3");
|
|
27
|
+
|
|
28
|
+
// src/cache.ts
|
|
29
|
+
var Cache = class {
|
|
30
|
+
constructor(maxSize) {
|
|
31
|
+
if (maxSize < 1) {
|
|
32
|
+
throw new Error("Cannot create a cache with a size less than 1");
|
|
33
|
+
}
|
|
34
|
+
this.sizeLimit = maxSize;
|
|
35
|
+
this.size = 0;
|
|
36
|
+
this.state = {};
|
|
37
|
+
this.keyOrders = [];
|
|
38
|
+
}
|
|
39
|
+
set(key, val) {
|
|
40
|
+
if (this.size === this.sizeLimit) {
|
|
41
|
+
const keyToRemove = this.keyOrders.shift();
|
|
42
|
+
delete this.state[keyToRemove];
|
|
43
|
+
this.size -= 1;
|
|
44
|
+
}
|
|
45
|
+
this.keyOrders.push(key);
|
|
46
|
+
this.state[key] = val;
|
|
47
|
+
this.size += 1;
|
|
48
|
+
}
|
|
49
|
+
get(key) {
|
|
50
|
+
return this.state[key];
|
|
51
|
+
}
|
|
52
|
+
has(key) {
|
|
53
|
+
return this.state[key] != null;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// src/index.ts
|
|
58
|
+
var isNotNull = (value) => value != null;
|
|
59
|
+
var S3Connector = class {
|
|
60
|
+
constructor({ S3, prefix, bucket, cacheLimit }) {
|
|
61
|
+
this.S3 = S3;
|
|
62
|
+
this.prefix = prefix;
|
|
63
|
+
this.bucket = bucket;
|
|
64
|
+
this.cache = new Cache(cacheLimit ?? 10);
|
|
65
|
+
}
|
|
66
|
+
async recordServiceCall(filePath, state) {
|
|
67
|
+
const putObjectCmd = new import_client_s3.PutObjectCommand({
|
|
68
|
+
Bucket: this.bucket,
|
|
69
|
+
Key: filePath,
|
|
70
|
+
Body: JSON.stringify(state)
|
|
71
|
+
});
|
|
72
|
+
const putObjectResponse = await this.S3.send(putObjectCmd);
|
|
73
|
+
this.cache.set(filePath, state);
|
|
74
|
+
return putObjectResponse;
|
|
75
|
+
}
|
|
76
|
+
async readStateForCall(filePath) {
|
|
77
|
+
if (this.cache.has(filePath)) {
|
|
78
|
+
return this.cache.get(filePath);
|
|
79
|
+
}
|
|
80
|
+
const getStateCommand = new import_client_s3.GetObjectCommand({
|
|
81
|
+
Bucket: this.bucket,
|
|
82
|
+
Key: filePath
|
|
83
|
+
});
|
|
84
|
+
const rawState = await this.S3.send(getStateCommand);
|
|
85
|
+
const state = await rawState?.Body?.transformToString("utf8");
|
|
86
|
+
return state ? JSON.parse(state) : void 0;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Format for file paths is somewhat unintuitive — the account and region are put at the end of the path
|
|
90
|
+
* This makes it easier for retrieving global state by service and function call where only list by prefix is supported (e.g. S3)
|
|
91
|
+
* Example:
|
|
92
|
+
* - /1234567890/us-east-1/Lambda/listFunctions.json cannot be globally listed by prefix, only by account and region
|
|
93
|
+
* - /Lambda-listFunctions/1234567890/us-east-1.json can be listed by function which allows for cross account resolution
|
|
94
|
+
*/
|
|
95
|
+
buildFilePathForServiceCall(account, region, service, functionName) {
|
|
96
|
+
return `${this.prefix}/${service}-${functionName}/${account}/${region}.json`;
|
|
97
|
+
}
|
|
98
|
+
onServiceScanCompleteCallback(account, region, service, functionName, functionState) {
|
|
99
|
+
const filePath = this.buildFilePathForServiceCall(
|
|
100
|
+
account,
|
|
101
|
+
region,
|
|
102
|
+
service,
|
|
103
|
+
functionName
|
|
104
|
+
);
|
|
105
|
+
return this.recordServiceCall(filePath, functionState);
|
|
106
|
+
}
|
|
107
|
+
resolveStateForServiceFunction(account, region, service, functionCall) {
|
|
108
|
+
const filePath = this.buildFilePathForServiceCall(
|
|
109
|
+
account,
|
|
110
|
+
region,
|
|
111
|
+
service,
|
|
112
|
+
functionCall
|
|
113
|
+
);
|
|
114
|
+
return this.readStateForCall(filePath);
|
|
115
|
+
}
|
|
116
|
+
async listObjectsForService(service, functionCall) {
|
|
117
|
+
const servicePrefix = `${this.prefix}/${service}-${functionCall}`;
|
|
118
|
+
const listObjectCommand = new import_client_s3.ListObjectsV2Command({
|
|
119
|
+
Bucket: this.bucket,
|
|
120
|
+
Prefix: servicePrefix
|
|
121
|
+
});
|
|
122
|
+
const response = await this.S3.send(listObjectCommand);
|
|
123
|
+
return response?.Contents?.map(({ Key }) => Key).filter(isNotNull) ?? [];
|
|
124
|
+
}
|
|
125
|
+
async getGlobalStateForServiceFunction(service, functionCall) {
|
|
126
|
+
const allKeys = await this.listObjectsForService(service, functionCall);
|
|
127
|
+
let globalState = [];
|
|
128
|
+
for (let idx = 0; idx < allKeys.length; idx += 1) {
|
|
129
|
+
const serviceState = await this.readStateForCall(allKeys[idx]);
|
|
130
|
+
if (serviceState != null) {
|
|
131
|
+
globalState = globalState.concat(serviceState);
|
|
132
|
+
} else {
|
|
133
|
+
console.log("No state returned for", allKeys[idx]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return globalState;
|
|
137
|
+
}
|
|
138
|
+
getMetadataPath() {
|
|
139
|
+
return `${this.prefix}/metadata.json`;
|
|
140
|
+
}
|
|
141
|
+
writeMetadata(metadata) {
|
|
142
|
+
return this.recordServiceCall(this.getMetadataPath(), metadata);
|
|
143
|
+
}
|
|
144
|
+
readMetadata() {
|
|
145
|
+
return this.readStateForCall(this.getMetadataPath());
|
|
146
|
+
}
|
|
147
|
+
getGraphPath() {
|
|
148
|
+
return `${this.prefix}/graph.json`;
|
|
149
|
+
}
|
|
150
|
+
writeGraphData(graphBlob) {
|
|
151
|
+
return this.recordServiceCall(this.getGraphPath(), graphBlob);
|
|
152
|
+
}
|
|
153
|
+
};
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
PutObjectCommand,
|
|
4
|
+
GetObjectCommand,
|
|
5
|
+
ListObjectsV2Command
|
|
6
|
+
} from "@aws-sdk/client-s3";
|
|
7
|
+
|
|
8
|
+
// src/cache.ts
|
|
9
|
+
var Cache = class {
|
|
10
|
+
constructor(maxSize) {
|
|
11
|
+
if (maxSize < 1) {
|
|
12
|
+
throw new Error("Cannot create a cache with a size less than 1");
|
|
13
|
+
}
|
|
14
|
+
this.sizeLimit = maxSize;
|
|
15
|
+
this.size = 0;
|
|
16
|
+
this.state = {};
|
|
17
|
+
this.keyOrders = [];
|
|
18
|
+
}
|
|
19
|
+
set(key, val) {
|
|
20
|
+
if (this.size === this.sizeLimit) {
|
|
21
|
+
const keyToRemove = this.keyOrders.shift();
|
|
22
|
+
delete this.state[keyToRemove];
|
|
23
|
+
this.size -= 1;
|
|
24
|
+
}
|
|
25
|
+
this.keyOrders.push(key);
|
|
26
|
+
this.state[key] = val;
|
|
27
|
+
this.size += 1;
|
|
28
|
+
}
|
|
29
|
+
get(key) {
|
|
30
|
+
return this.state[key];
|
|
31
|
+
}
|
|
32
|
+
has(key) {
|
|
33
|
+
return this.state[key] != null;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// src/index.ts
|
|
38
|
+
var isNotNull = (value) => value != null;
|
|
39
|
+
var S3Connector = class {
|
|
40
|
+
constructor({ S3, prefix, bucket, cacheLimit }) {
|
|
41
|
+
this.S3 = S3;
|
|
42
|
+
this.prefix = prefix;
|
|
43
|
+
this.bucket = bucket;
|
|
44
|
+
this.cache = new Cache(cacheLimit ?? 10);
|
|
45
|
+
}
|
|
46
|
+
async recordServiceCall(filePath, state) {
|
|
47
|
+
const putObjectCmd = new PutObjectCommand({
|
|
48
|
+
Bucket: this.bucket,
|
|
49
|
+
Key: filePath,
|
|
50
|
+
Body: JSON.stringify(state)
|
|
51
|
+
});
|
|
52
|
+
const putObjectResponse = await this.S3.send(putObjectCmd);
|
|
53
|
+
this.cache.set(filePath, state);
|
|
54
|
+
return putObjectResponse;
|
|
55
|
+
}
|
|
56
|
+
async readStateForCall(filePath) {
|
|
57
|
+
if (this.cache.has(filePath)) {
|
|
58
|
+
return this.cache.get(filePath);
|
|
59
|
+
}
|
|
60
|
+
const getStateCommand = new GetObjectCommand({
|
|
61
|
+
Bucket: this.bucket,
|
|
62
|
+
Key: filePath
|
|
63
|
+
});
|
|
64
|
+
const rawState = await this.S3.send(getStateCommand);
|
|
65
|
+
const state = await rawState?.Body?.transformToString("utf8");
|
|
66
|
+
return state ? JSON.parse(state) : void 0;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Format for file paths is somewhat unintuitive — the account and region are put at the end of the path
|
|
70
|
+
* This makes it easier for retrieving global state by service and function call where only list by prefix is supported (e.g. S3)
|
|
71
|
+
* Example:
|
|
72
|
+
* - /1234567890/us-east-1/Lambda/listFunctions.json cannot be globally listed by prefix, only by account and region
|
|
73
|
+
* - /Lambda-listFunctions/1234567890/us-east-1.json can be listed by function which allows for cross account resolution
|
|
74
|
+
*/
|
|
75
|
+
buildFilePathForServiceCall(account, region, service, functionName) {
|
|
76
|
+
return `${this.prefix}/${service}-${functionName}/${account}/${region}.json`;
|
|
77
|
+
}
|
|
78
|
+
onServiceScanCompleteCallback(account, region, service, functionName, functionState) {
|
|
79
|
+
const filePath = this.buildFilePathForServiceCall(
|
|
80
|
+
account,
|
|
81
|
+
region,
|
|
82
|
+
service,
|
|
83
|
+
functionName
|
|
84
|
+
);
|
|
85
|
+
return this.recordServiceCall(filePath, functionState);
|
|
86
|
+
}
|
|
87
|
+
resolveStateForServiceFunction(account, region, service, functionCall) {
|
|
88
|
+
const filePath = this.buildFilePathForServiceCall(
|
|
89
|
+
account,
|
|
90
|
+
region,
|
|
91
|
+
service,
|
|
92
|
+
functionCall
|
|
93
|
+
);
|
|
94
|
+
return this.readStateForCall(filePath);
|
|
95
|
+
}
|
|
96
|
+
async listObjectsForService(service, functionCall) {
|
|
97
|
+
const servicePrefix = `${this.prefix}/${service}-${functionCall}`;
|
|
98
|
+
const listObjectCommand = new ListObjectsV2Command({
|
|
99
|
+
Bucket: this.bucket,
|
|
100
|
+
Prefix: servicePrefix
|
|
101
|
+
});
|
|
102
|
+
const response = await this.S3.send(listObjectCommand);
|
|
103
|
+
return response?.Contents?.map(({ Key }) => Key).filter(isNotNull) ?? [];
|
|
104
|
+
}
|
|
105
|
+
async getGlobalStateForServiceFunction(service, functionCall) {
|
|
106
|
+
const allKeys = await this.listObjectsForService(service, functionCall);
|
|
107
|
+
let globalState = [];
|
|
108
|
+
for (let idx = 0; idx < allKeys.length; idx += 1) {
|
|
109
|
+
const serviceState = await this.readStateForCall(allKeys[idx]);
|
|
110
|
+
if (serviceState != null) {
|
|
111
|
+
globalState = globalState.concat(serviceState);
|
|
112
|
+
} else {
|
|
113
|
+
console.log("No state returned for", allKeys[idx]);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return globalState;
|
|
117
|
+
}
|
|
118
|
+
getMetadataPath() {
|
|
119
|
+
return `${this.prefix}/metadata.json`;
|
|
120
|
+
}
|
|
121
|
+
writeMetadata(metadata) {
|
|
122
|
+
return this.recordServiceCall(this.getMetadataPath(), metadata);
|
|
123
|
+
}
|
|
124
|
+
readMetadata() {
|
|
125
|
+
return this.readStateForCall(this.getMetadataPath());
|
|
126
|
+
}
|
|
127
|
+
getGraphPath() {
|
|
128
|
+
return `${this.prefix}/graph.json`;
|
|
129
|
+
}
|
|
130
|
+
writeGraphData(graphBlob) {
|
|
131
|
+
return this.recordServiceCall(this.getGraphPath(), graphBlob);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
export {
|
|
135
|
+
S3Connector as default
|
|
136
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@infrascan/s3-connector",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Connector for the Infrascan SDK to read and write state to an S3 bucket",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "rm -rf dist ; tsup",
|
|
20
|
+
"prepublish": "rm -rf dist ; tsup",
|
|
21
|
+
"lint": "tsc --noEmit ; eslint .",
|
|
22
|
+
"clean": "rm -rf dist node_modules",
|
|
23
|
+
"test": "tap test/*.test.ts --allow-incomplete-coverage -- --typescript"
|
|
24
|
+
},
|
|
25
|
+
"tsup": {
|
|
26
|
+
"clean": true,
|
|
27
|
+
"cjsInterop": true,
|
|
28
|
+
"splitting": false,
|
|
29
|
+
"dts": true,
|
|
30
|
+
"entry": [
|
|
31
|
+
"src/index.ts"
|
|
32
|
+
],
|
|
33
|
+
"format": [
|
|
34
|
+
"esm",
|
|
35
|
+
"cjs"
|
|
36
|
+
],
|
|
37
|
+
"target": "node18"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"AWS",
|
|
41
|
+
"Infrastructure Diagram",
|
|
42
|
+
"Infrastructure Graph",
|
|
43
|
+
"Cloud Infrastructure",
|
|
44
|
+
"Connector"
|
|
45
|
+
],
|
|
46
|
+
"author": "Liam Farrelly <liam@l3f7.dev> (https://whoisli.am/)",
|
|
47
|
+
"license": "MPL-2.0",
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@aws-sdk/util-stream-node": "^3.374.0",
|
|
50
|
+
"@infrascan/shared-types": "^0.2.2",
|
|
51
|
+
"aws-sdk-client-mock": "^3.0.0",
|
|
52
|
+
"eslint-config-custom": "*",
|
|
53
|
+
"tap": "^18.5.7",
|
|
54
|
+
"tsconfig": "*",
|
|
55
|
+
"typescript": "^5.1.6"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@aws-sdk/client-s3": "3.428.0",
|
|
59
|
+
"minimatch": "^9.0.3"
|
|
60
|
+
}
|
|
61
|
+
}
|