@ayepi/aws 0.2.0 → 0.3.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 +5 -0
- package/ayepi-aws.md +43 -0
- package/dist/http.cjs +70 -0
- package/dist/http.d.cts +44 -0
- package/dist/http.d.ts +44 -0
- package/dist/http.js +68 -0
- package/package.json +22 -7
package/README.md
CHANGED
|
@@ -49,6 +49,11 @@ const w = createWork({ queue, pubsub, store, work: [/* ... */] as const })
|
|
|
49
49
|
and rethrown.
|
|
50
50
|
- **You own the SDK clients.** The clients are optional peer deps — you construct and configure
|
|
51
51
|
them (region, credentials, endpoint) and manage their lifecycle.
|
|
52
|
+
- **Connection pooling.** The SDK's default handler caps outbound connections at `maxSockets: 50`
|
|
53
|
+
per client — a common bottleneck for a busy S3+SQS work system. `@ayepi/aws/http` exports
|
|
54
|
+
`pooledRequestHandler({ maxSockets })` and `sharedHttpAgents(...)` — a keep-alive handler with a
|
|
55
|
+
higher cap to pass as `requestHandler`, or one shared pool across clients:
|
|
56
|
+
`new S3Client({ requestHandler: pooledRequestHandler({ maxSockets: 256 }) })`.
|
|
52
57
|
|
|
53
58
|
## Options
|
|
54
59
|
|
package/ayepi-aws.md
CHANGED
|
@@ -205,6 +205,49 @@ deleted. Notes:
|
|
|
205
205
|
- `store` is any [`@ayepi/files`](./ayepi-files.md) `FileStore` — typically an `s3Files({...})`,
|
|
206
206
|
but a filesystem store or your own works too.
|
|
207
207
|
|
|
208
|
+
### `@ayepi/aws/http` — a well-pooled request handler
|
|
209
|
+
|
|
210
|
+
The SDK's default `NodeHttpHandler` caps outbound connections at **`maxSockets: 50` per client**.
|
|
211
|
+
Under a busy work system (S3 + SQS + more, each its own client) that cap is often the first thing to
|
|
212
|
+
break — calls queue behind 50 sockets and latency balloons, with no error, just slowness. This
|
|
213
|
+
subpath builds a keep-alive handler (and shareable agents) with a higher cap.
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
217
|
+
import { SQSClient } from '@aws-sdk/client-sqs';
|
|
218
|
+
import { pooledRequestHandler, sharedHttpAgents } from '@ayepi/aws/http';
|
|
219
|
+
|
|
220
|
+
// One handler per client:
|
|
221
|
+
const s3 = new S3Client({ region, requestHandler: pooledRequestHandler({ maxSockets: 256 }) });
|
|
222
|
+
|
|
223
|
+
// ...or share ONE pool across many clients (bounds total sockets, better reuse):
|
|
224
|
+
const agents = sharedHttpAgents({ maxSockets: 512 });
|
|
225
|
+
const s3b = new S3Client({ requestHandler: pooledRequestHandler(agents) });
|
|
226
|
+
const sqs = new SQSClient({ requestHandler: pooledRequestHandler(agents) });
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
function pooledRequestHandler(opts?: PooledHandlerOptions): NodeHttpHandler
|
|
231
|
+
function sharedHttpAgents(opts?: PooledAgentsOptions): { httpAgent; httpsAgent }
|
|
232
|
+
|
|
233
|
+
interface PooledAgentsOptions {
|
|
234
|
+
readonly maxSockets?: number; // per host (default 128; SDK default 50)
|
|
235
|
+
readonly maxTotalSockets?: number; // across all hosts (default: unlimited)
|
|
236
|
+
readonly keepAlive?: boolean; // default true — avoids TCP churn / port exhaustion
|
|
237
|
+
readonly keepAliveMsecs?: number; // default 1000
|
|
238
|
+
}
|
|
239
|
+
interface PooledHandlerOptions extends PooledAgentsOptions {
|
|
240
|
+
readonly connectionTimeout?: number; // ms
|
|
241
|
+
readonly requestTimeout?: number; // ms
|
|
242
|
+
readonly httpAgent?: HttpAgent; // bring your own (overrides the pool knobs)
|
|
243
|
+
readonly httpsAgent?: HttpsAgent;
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Keep-alive is on by default so connections are reused instead of churned — which also sidesteps
|
|
248
|
+
ephemeral-port / `TIME_WAIT` exhaustion under sustained load. Requires `@smithy/node-http-handler`
|
|
249
|
+
(an optional peer, already a transitive dependency of the AWS SDK clients).
|
|
250
|
+
|
|
208
251
|
### `@ayepi/aws` (root) — the retry seam
|
|
209
252
|
|
|
210
253
|
The root subpath exports the shared resilience machinery both backends build on. You rarely call
|
package/dist/http.cjs
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let node_http = require("node:http");
|
|
3
|
+
let node_https = require("node:https");
|
|
4
|
+
let _smithy_node_http_handler = require("@smithy/node-http-handler");
|
|
5
|
+
//#region src/http.ts
|
|
6
|
+
/**
|
|
7
|
+
* # @ayepi/aws/http — a well-pooled request handler for the AWS SDK
|
|
8
|
+
*
|
|
9
|
+
* The AWS SDK v3's default `NodeHttpHandler` caps outbound connections at **`maxSockets: 50` per
|
|
10
|
+
* client**. Under a busy work system (S3 + SQS + more, each its own client) that cap is often the
|
|
11
|
+
* first thing to break: calls queue behind 50 sockets and latency balloons — with no error, just
|
|
12
|
+
* mysterious slowness. This module builds a handler (and shareable agents) with keep-alive on and a
|
|
13
|
+
* higher cap, to pass as `requestHandler` to your clients.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { S3Client } from '@aws-sdk/client-s3';
|
|
17
|
+
* import { SQSClient } from '@aws-sdk/client-sqs';
|
|
18
|
+
* import { pooledRequestHandler, sharedHttpAgents } from '@ayepi/aws/http';
|
|
19
|
+
*
|
|
20
|
+
* // One handler per client:
|
|
21
|
+
* const s3 = new S3Client({ region, requestHandler: pooledRequestHandler({ maxSockets: 256 }) });
|
|
22
|
+
*
|
|
23
|
+
* // ...or share ONE pool across many clients (fewer total sockets, better reuse):
|
|
24
|
+
* const agents = sharedHttpAgents({ maxSockets: 512 });
|
|
25
|
+
* const s3b = new S3Client({ requestHandler: pooledRequestHandler(agents) });
|
|
26
|
+
* const sqs = new SQSClient({ requestHandler: pooledRequestHandler(agents) });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* Keep-alive is on by default so connections are reused instead of churned — which also avoids
|
|
30
|
+
* ephemeral-port / `TIME_WAIT` exhaustion under sustained load. Requires `@smithy/node-http-handler`
|
|
31
|
+
* (a transitive dependency of the AWS SDK clients).
|
|
32
|
+
*
|
|
33
|
+
* @module
|
|
34
|
+
*/
|
|
35
|
+
/** Agent constructor options derived from the pool knobs. */
|
|
36
|
+
function agentConf(opts) {
|
|
37
|
+
return {
|
|
38
|
+
keepAlive: opts.keepAlive ?? true,
|
|
39
|
+
keepAliveMsecs: opts.keepAliveMsecs ?? 1e3,
|
|
40
|
+
maxSockets: opts.maxSockets ?? 128,
|
|
41
|
+
maxTotalSockets: opts.maxTotalSockets
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A pair of keep-alive `node:http` / `node:https` agents you can **share across many AWS clients**
|
|
46
|
+
* (pass to {@link pooledRequestHandler}). Sharing one pair bounds total sockets across S3/SQS/etc.
|
|
47
|
+
*/
|
|
48
|
+
function sharedHttpAgents(opts = {}) {
|
|
49
|
+
const conf = agentConf(opts);
|
|
50
|
+
return {
|
|
51
|
+
httpAgent: new node_http.Agent(conf),
|
|
52
|
+
httpsAgent: new node_https.Agent(conf)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build a `NodeHttpHandler` with keep-alive and a higher socket cap than the SDK default — pass it
|
|
57
|
+
* as `requestHandler` to an `S3Client`/`SQSClient`. Reuse one handler (or one {@link sharedHttpAgents}
|
|
58
|
+
* pair) across clients to bound total sockets.
|
|
59
|
+
*/
|
|
60
|
+
function pooledRequestHandler(opts = {}) {
|
|
61
|
+
return new _smithy_node_http_handler.NodeHttpHandler({
|
|
62
|
+
httpAgent: opts.httpAgent ?? new node_http.Agent(agentConf(opts)),
|
|
63
|
+
httpsAgent: opts.httpsAgent ?? new node_https.Agent(agentConf(opts)),
|
|
64
|
+
connectionTimeout: opts.connectionTimeout,
|
|
65
|
+
requestTimeout: opts.requestTimeout
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
exports.pooledRequestHandler = pooledRequestHandler;
|
|
70
|
+
exports.sharedHttpAgents = sharedHttpAgents;
|
package/dist/http.d.cts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Agent } from "node:http";
|
|
2
|
+
import { Agent as Agent$1 } from "node:https";
|
|
3
|
+
import { NodeHttpHandler } from "@smithy/node-http-handler";
|
|
4
|
+
|
|
5
|
+
//#region src/http.d.ts
|
|
6
|
+
|
|
7
|
+
/** Connection-pool knobs shared by the http + https agents. */
|
|
8
|
+
interface PooledAgentsOptions {
|
|
9
|
+
/** Max sockets per host (default `128`; the SDK default is `50`). */
|
|
10
|
+
readonly maxSockets?: number;
|
|
11
|
+
/** Max sockets across all hosts (default: unlimited). */
|
|
12
|
+
readonly maxTotalSockets?: number;
|
|
13
|
+
/** Reuse connections (default `true`). Keep-alive avoids TCP churn and port exhaustion. */
|
|
14
|
+
readonly keepAlive?: boolean;
|
|
15
|
+
/** Idle time before a kept-alive socket may close (ms, default `1000`). */
|
|
16
|
+
readonly keepAliveMsecs?: number;
|
|
17
|
+
}
|
|
18
|
+
/** Options for {@link pooledRequestHandler}: the pool knobs plus timeouts and bring-your-own agents. */
|
|
19
|
+
interface PooledHandlerOptions extends PooledAgentsOptions {
|
|
20
|
+
/** Socket connect timeout (ms). */
|
|
21
|
+
readonly connectionTimeout?: number;
|
|
22
|
+
/** Time to wait for a response (ms). */
|
|
23
|
+
readonly requestTimeout?: number;
|
|
24
|
+
/** Bring your own http agent (overrides the pool knobs for http). */
|
|
25
|
+
readonly httpAgent?: Agent;
|
|
26
|
+
/** Bring your own https agent (overrides the pool knobs for https). */
|
|
27
|
+
readonly httpsAgent?: Agent$1;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A pair of keep-alive `node:http` / `node:https` agents you can **share across many AWS clients**
|
|
31
|
+
* (pass to {@link pooledRequestHandler}). Sharing one pair bounds total sockets across S3/SQS/etc.
|
|
32
|
+
*/
|
|
33
|
+
declare function sharedHttpAgents(opts?: PooledAgentsOptions): {
|
|
34
|
+
httpAgent: Agent;
|
|
35
|
+
httpsAgent: Agent$1;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Build a `NodeHttpHandler` with keep-alive and a higher socket cap than the SDK default — pass it
|
|
39
|
+
* as `requestHandler` to an `S3Client`/`SQSClient`. Reuse one handler (or one {@link sharedHttpAgents}
|
|
40
|
+
* pair) across clients to bound total sockets.
|
|
41
|
+
*/
|
|
42
|
+
declare function pooledRequestHandler(opts?: PooledHandlerOptions): NodeHttpHandler;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { PooledAgentsOptions, PooledHandlerOptions, pooledRequestHandler, sharedHttpAgents };
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Agent } from "node:http";
|
|
2
|
+
import { Agent as Agent$1 } from "node:https";
|
|
3
|
+
import { NodeHttpHandler } from "@smithy/node-http-handler";
|
|
4
|
+
|
|
5
|
+
//#region src/http.d.ts
|
|
6
|
+
|
|
7
|
+
/** Connection-pool knobs shared by the http + https agents. */
|
|
8
|
+
interface PooledAgentsOptions {
|
|
9
|
+
/** Max sockets per host (default `128`; the SDK default is `50`). */
|
|
10
|
+
readonly maxSockets?: number;
|
|
11
|
+
/** Max sockets across all hosts (default: unlimited). */
|
|
12
|
+
readonly maxTotalSockets?: number;
|
|
13
|
+
/** Reuse connections (default `true`). Keep-alive avoids TCP churn and port exhaustion. */
|
|
14
|
+
readonly keepAlive?: boolean;
|
|
15
|
+
/** Idle time before a kept-alive socket may close (ms, default `1000`). */
|
|
16
|
+
readonly keepAliveMsecs?: number;
|
|
17
|
+
}
|
|
18
|
+
/** Options for {@link pooledRequestHandler}: the pool knobs plus timeouts and bring-your-own agents. */
|
|
19
|
+
interface PooledHandlerOptions extends PooledAgentsOptions {
|
|
20
|
+
/** Socket connect timeout (ms). */
|
|
21
|
+
readonly connectionTimeout?: number;
|
|
22
|
+
/** Time to wait for a response (ms). */
|
|
23
|
+
readonly requestTimeout?: number;
|
|
24
|
+
/** Bring your own http agent (overrides the pool knobs for http). */
|
|
25
|
+
readonly httpAgent?: Agent;
|
|
26
|
+
/** Bring your own https agent (overrides the pool knobs for https). */
|
|
27
|
+
readonly httpsAgent?: Agent$1;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A pair of keep-alive `node:http` / `node:https` agents you can **share across many AWS clients**
|
|
31
|
+
* (pass to {@link pooledRequestHandler}). Sharing one pair bounds total sockets across S3/SQS/etc.
|
|
32
|
+
*/
|
|
33
|
+
declare function sharedHttpAgents(opts?: PooledAgentsOptions): {
|
|
34
|
+
httpAgent: Agent;
|
|
35
|
+
httpsAgent: Agent$1;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Build a `NodeHttpHandler` with keep-alive and a higher socket cap than the SDK default — pass it
|
|
39
|
+
* as `requestHandler` to an `S3Client`/`SQSClient`. Reuse one handler (or one {@link sharedHttpAgents}
|
|
40
|
+
* pair) across clients to bound total sockets.
|
|
41
|
+
*/
|
|
42
|
+
declare function pooledRequestHandler(opts?: PooledHandlerOptions): NodeHttpHandler;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { PooledAgentsOptions, PooledHandlerOptions, pooledRequestHandler, sharedHttpAgents };
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Agent } from "node:http";
|
|
2
|
+
import { Agent as Agent$1 } from "node:https";
|
|
3
|
+
import { NodeHttpHandler } from "@smithy/node-http-handler";
|
|
4
|
+
//#region src/http.ts
|
|
5
|
+
/**
|
|
6
|
+
* # @ayepi/aws/http — a well-pooled request handler for the AWS SDK
|
|
7
|
+
*
|
|
8
|
+
* The AWS SDK v3's default `NodeHttpHandler` caps outbound connections at **`maxSockets: 50` per
|
|
9
|
+
* client**. Under a busy work system (S3 + SQS + more, each its own client) that cap is often the
|
|
10
|
+
* first thing to break: calls queue behind 50 sockets and latency balloons — with no error, just
|
|
11
|
+
* mysterious slowness. This module builds a handler (and shareable agents) with keep-alive on and a
|
|
12
|
+
* higher cap, to pass as `requestHandler` to your clients.
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { S3Client } from '@aws-sdk/client-s3';
|
|
16
|
+
* import { SQSClient } from '@aws-sdk/client-sqs';
|
|
17
|
+
* import { pooledRequestHandler, sharedHttpAgents } from '@ayepi/aws/http';
|
|
18
|
+
*
|
|
19
|
+
* // One handler per client:
|
|
20
|
+
* const s3 = new S3Client({ region, requestHandler: pooledRequestHandler({ maxSockets: 256 }) });
|
|
21
|
+
*
|
|
22
|
+
* // ...or share ONE pool across many clients (fewer total sockets, better reuse):
|
|
23
|
+
* const agents = sharedHttpAgents({ maxSockets: 512 });
|
|
24
|
+
* const s3b = new S3Client({ requestHandler: pooledRequestHandler(agents) });
|
|
25
|
+
* const sqs = new SQSClient({ requestHandler: pooledRequestHandler(agents) });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* Keep-alive is on by default so connections are reused instead of churned — which also avoids
|
|
29
|
+
* ephemeral-port / `TIME_WAIT` exhaustion under sustained load. Requires `@smithy/node-http-handler`
|
|
30
|
+
* (a transitive dependency of the AWS SDK clients).
|
|
31
|
+
*
|
|
32
|
+
* @module
|
|
33
|
+
*/
|
|
34
|
+
/** Agent constructor options derived from the pool knobs. */
|
|
35
|
+
function agentConf(opts) {
|
|
36
|
+
return {
|
|
37
|
+
keepAlive: opts.keepAlive ?? true,
|
|
38
|
+
keepAliveMsecs: opts.keepAliveMsecs ?? 1e3,
|
|
39
|
+
maxSockets: opts.maxSockets ?? 128,
|
|
40
|
+
maxTotalSockets: opts.maxTotalSockets
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A pair of keep-alive `node:http` / `node:https` agents you can **share across many AWS clients**
|
|
45
|
+
* (pass to {@link pooledRequestHandler}). Sharing one pair bounds total sockets across S3/SQS/etc.
|
|
46
|
+
*/
|
|
47
|
+
function sharedHttpAgents(opts = {}) {
|
|
48
|
+
const conf = agentConf(opts);
|
|
49
|
+
return {
|
|
50
|
+
httpAgent: new Agent(conf),
|
|
51
|
+
httpsAgent: new Agent$1(conf)
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Build a `NodeHttpHandler` with keep-alive and a higher socket cap than the SDK default — pass it
|
|
56
|
+
* as `requestHandler` to an `S3Client`/`SQSClient`. Reuse one handler (or one {@link sharedHttpAgents}
|
|
57
|
+
* pair) across clients to bound total sockets.
|
|
58
|
+
*/
|
|
59
|
+
function pooledRequestHandler(opts = {}) {
|
|
60
|
+
return new NodeHttpHandler({
|
|
61
|
+
httpAgent: opts.httpAgent ?? new Agent(agentConf(opts)),
|
|
62
|
+
httpsAgent: opts.httpsAgent ?? new Agent$1(agentConf(opts)),
|
|
63
|
+
connectionTimeout: opts.connectionTimeout,
|
|
64
|
+
requestTimeout: opts.requestTimeout
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { pooledRequestHandler, sharedHttpAgents };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ayepi/aws",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "AWS backends for ayepi — an SQS @ayepi/work queue (large payloads offloaded to S3) and an S3 @ayepi/files store, all retry-wrapped for throttle resilience",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -52,6 +52,16 @@
|
|
|
52
52
|
"default": "./dist/sqs.cjs"
|
|
53
53
|
}
|
|
54
54
|
},
|
|
55
|
+
"./http": {
|
|
56
|
+
"import": {
|
|
57
|
+
"types": "./dist/http.d.ts",
|
|
58
|
+
"default": "./dist/http.js"
|
|
59
|
+
},
|
|
60
|
+
"require": {
|
|
61
|
+
"types": "./dist/http.d.cts",
|
|
62
|
+
"default": "./dist/http.cjs"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
55
65
|
"./package.json": "./package.json"
|
|
56
66
|
},
|
|
57
67
|
"engines": {
|
|
@@ -62,9 +72,10 @@
|
|
|
62
72
|
"@aws-sdk/client-sqs": "^3",
|
|
63
73
|
"@aws-sdk/lib-storage": "^3",
|
|
64
74
|
"@aws-sdk/s3-request-presigner": "^3",
|
|
65
|
-
"@
|
|
66
|
-
"@ayepi/
|
|
67
|
-
"@ayepi/
|
|
75
|
+
"@smithy/node-http-handler": "^4",
|
|
76
|
+
"@ayepi/core": "^0.3.0",
|
|
77
|
+
"@ayepi/work": "^0.3.0",
|
|
78
|
+
"@ayepi/files": "^0.3.0"
|
|
68
79
|
},
|
|
69
80
|
"peerDependenciesMeta": {
|
|
70
81
|
"@ayepi/work": {
|
|
@@ -84,6 +95,9 @@
|
|
|
84
95
|
},
|
|
85
96
|
"@aws-sdk/s3-request-presigner": {
|
|
86
97
|
"optional": true
|
|
98
|
+
},
|
|
99
|
+
"@smithy/node-http-handler": {
|
|
100
|
+
"optional": true
|
|
87
101
|
}
|
|
88
102
|
},
|
|
89
103
|
"devDependencies": {
|
|
@@ -91,15 +105,16 @@
|
|
|
91
105
|
"@aws-sdk/client-sqs": "^3.700.0",
|
|
92
106
|
"@aws-sdk/lib-storage": "^3.700.0",
|
|
93
107
|
"@aws-sdk/s3-request-presigner": "^3.700.0",
|
|
108
|
+
"@smithy/node-http-handler": "^4.0.0",
|
|
94
109
|
"@vitest/coverage-v8": "^2.1.8",
|
|
95
110
|
"publint": "^0.3.0",
|
|
96
111
|
"testcontainers": "^10.13.0",
|
|
97
112
|
"tsdown": "^0.12.0",
|
|
98
113
|
"vitest": "^2.1.8",
|
|
99
114
|
"zod": "^4.4.3",
|
|
100
|
-
"@ayepi/core": "0.
|
|
101
|
-
"@ayepi/
|
|
102
|
-
"@ayepi/
|
|
115
|
+
"@ayepi/core": "0.3.0",
|
|
116
|
+
"@ayepi/files": "0.3.0",
|
|
117
|
+
"@ayepi/work": "0.3.0"
|
|
103
118
|
},
|
|
104
119
|
"keywords": [
|
|
105
120
|
"ayepi",
|