@atproto/aws 0.2.32 → 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/CHANGELOG.md +20 -0
- package/dist/bunny.d.ts +1 -1
- package/dist/bunny.d.ts.map +1 -1
- package/dist/bunny.js +5 -14
- package/dist/bunny.js.map +1 -1
- package/dist/cloudfront.d.ts +1 -1
- package/dist/cloudfront.d.ts.map +1 -1
- package/dist/cloudfront.js +3 -58
- package/dist/cloudfront.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -22
- package/dist/index.js.map +1 -1
- package/dist/kms.d.ts.map +1 -1
- package/dist/kms.js +15 -73
- package/dist/kms.js.map +1 -1
- package/dist/s3.js +19 -46
- package/dist/s3.js.map +1 -1
- package/dist/types.js +1 -2
- package/dist/util.d.ts +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +4 -13
- package/dist/util.js.map +1 -1
- package/package.json +16 -11
- package/src/bunny.ts +1 -1
- package/src/cloudfront.ts +1 -1
- package/src/index.ts +6 -6
- package/src/kms.ts +4 -1
- package/src/util.ts +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @atproto/aws
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#4929](https://github.com/bluesky-social/atproto/pull/4929) [`f01c59f`](https://github.com/bluesky-social/atproto/commit/f01c59f5bd3f75fb8b47a9eecd4858b84033fb7c) Thanks [@devinivy](https://github.com/devinivy)! - **BREAKING:** Drop support for Node.js 18 and 20. Node.js 22 is now the minimum supported version. Docker images now use Node.js 24.
|
|
8
|
+
|
|
9
|
+
- [#4943](https://github.com/bluesky-social/atproto/pull/4943) [`c459153`](https://github.com/bluesky-social/atproto/commit/c459153395a30ce89e050892c8fab7dc98e019b9) Thanks [@devinivy](https://github.com/devinivy)! - **BREAKING:** Convert to pure ESM. All packages now ship `"type": "module"` with ES module output and Node16 module resolution.
|
|
10
|
+
|
|
11
|
+
Node.js 22's `require()` compatibility layer can still load these packages in CommonJS code.
|
|
12
|
+
|
|
13
|
+
- [#4930](https://github.com/bluesky-social/atproto/pull/4930) [`908bece`](https://github.com/bluesky-social/atproto/commit/908bece169258bff5ad121e5eec157d6ded6f705) Thanks [@devinivy](https://github.com/devinivy)! - Build with TypeScript 6.0.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Updated dependencies [[`affb50c`](https://github.com/bluesky-social/atproto/commit/affb50c040b497a12631df99a6310f8e78cab557), [`f01c59f`](https://github.com/bluesky-social/atproto/commit/f01c59f5bd3f75fb8b47a9eecd4858b84033fb7c), [`c459153`](https://github.com/bluesky-social/atproto/commit/c459153395a30ce89e050892c8fab7dc98e019b9), [`908bece`](https://github.com/bluesky-social/atproto/commit/908bece169258bff5ad121e5eec157d6ded6f705)]:
|
|
18
|
+
- @atproto/common@0.6.0
|
|
19
|
+
- @atproto/common-web@0.5.0
|
|
20
|
+
- @atproto/crypto@0.5.0
|
|
21
|
+
- @atproto/repo@0.10.0
|
|
22
|
+
|
|
3
23
|
## 0.2.32
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/dist/bunny.d.ts
CHANGED
package/dist/bunny.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bunny.d.ts","sourceRoot":"","sources":["../src/bunny.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"bunny.d.ts","sourceRoot":"","sources":["../src/bunny.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE7C,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAID,qBAAa,gBAAiB,YAAW,gBAAgB;IACpC,GAAG,EAAE,WAAW;gBAAhB,GAAG,EAAE,WAAW;IAC7B,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;CAUnD;AAED,eAAe,gBAAgB,CAAA"}
|
package/dist/bunny.js
CHANGED
|
@@ -1,26 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BunnyInvalidator = void 0;
|
|
4
|
-
const common_1 = require("@atproto/common");
|
|
1
|
+
import { allFulfilled } from '@atproto/common';
|
|
5
2
|
const API_PURGE_URL = 'https://api.bunny.net/purge';
|
|
6
|
-
class BunnyInvalidator {
|
|
3
|
+
export class BunnyInvalidator {
|
|
7
4
|
constructor(cfg) {
|
|
8
|
-
|
|
9
|
-
enumerable: true,
|
|
10
|
-
configurable: true,
|
|
11
|
-
writable: true,
|
|
12
|
-
value: cfg
|
|
13
|
-
});
|
|
5
|
+
this.cfg = cfg;
|
|
14
6
|
}
|
|
15
7
|
async invalidate(_subject, paths) {
|
|
16
|
-
await
|
|
8
|
+
await allFulfilled(paths.map(async (path) => purgeUrl({
|
|
17
9
|
url: this.cfg.urlPrefix + path,
|
|
18
10
|
accessKey: this.cfg.accessKey,
|
|
19
11
|
})));
|
|
20
12
|
}
|
|
21
13
|
}
|
|
22
|
-
|
|
23
|
-
exports.default = BunnyInvalidator;
|
|
14
|
+
export default BunnyInvalidator;
|
|
24
15
|
async function purgeUrl(opts) {
|
|
25
16
|
const search = new URLSearchParams();
|
|
26
17
|
search.set('async', 'true');
|
package/dist/bunny.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bunny.js","sourceRoot":"","sources":["../src/bunny.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bunny.js","sourceRoot":"","sources":["../src/bunny.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAQ9C,MAAM,aAAa,GAAG,6BAA6B,CAAA;AAEnD,MAAM,OAAO,gBAAgB;IAC3B,YAAmB,GAAgB;QAAhB,QAAG,GAAH,GAAG,CAAa;IAAG,CAAC;IACvC,KAAK,CAAC,UAAU,CAAC,QAAgB,EAAE,KAAe;QAChD,MAAM,YAAY,CAChB,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CACvB,QAAQ,CAAC;YACP,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI;YAC9B,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS;SAC9B,CAAC,CACH,CACF,CAAA;IACH,CAAC;CACF;AAED,eAAe,gBAAgB,CAAA;AAE/B,KAAK,UAAU,QAAQ,CAAC,IAAwC;IAC9D,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAA;IACpC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IAC3B,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IAC3B,MAAM,KAAK,CAAC,aAAa,GAAG,GAAG,GAAG,MAAM,CAAC,QAAQ,EAAE,EAAE;QACnD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;KACvC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { allFulfilled } from '@atproto/common'\nimport { ImageInvalidator } from './types.js'\n\nexport type BunnyConfig = {\n accessKey: string\n urlPrefix: string\n}\n\nconst API_PURGE_URL = 'https://api.bunny.net/purge'\n\nexport class BunnyInvalidator implements ImageInvalidator {\n constructor(public cfg: BunnyConfig) {}\n async invalidate(_subject: string, paths: string[]) {\n await allFulfilled(\n paths.map(async (path) =>\n purgeUrl({\n url: this.cfg.urlPrefix + path,\n accessKey: this.cfg.accessKey,\n }),\n ),\n )\n }\n}\n\nexport default BunnyInvalidator\n\nasync function purgeUrl(opts: { accessKey: string; url: string }) {\n const search = new URLSearchParams()\n search.set('async', 'true')\n search.set('url', opts.url)\n await fetch(API_PURGE_URL + '?' + search.toString(), {\n method: 'post',\n headers: { AccessKey: opts.accessKey },\n })\n}\n"]}
|
package/dist/cloudfront.d.ts
CHANGED
package/dist/cloudfront.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudfront.d.ts","sourceRoot":"","sources":["../src/cloudfront.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,4BAA4B,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"cloudfront.d.ts","sourceRoot":"","sources":["../src/cloudfront.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,4BAA4B,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE7C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,GAAG,IAAI,CAAC,GAAG,CAAC,sBAAsB,EAAE,YAAY,CAAC,CAAA;AAElD,qBAAa,qBAAsB,YAAW,gBAAgB;IAC5D,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,GAAG,CAAC,UAAU,CAAA;gBACV,GAAG,EAAE,gBAAgB;IAS3B,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;CAYlD;AAED,eAAe,qBAAqB,CAAA"}
|
package/dist/cloudfront.js
CHANGED
|
@@ -1,60 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.CloudfrontInvalidator = void 0;
|
|
37
|
-
const aws = __importStar(require("@aws-sdk/client-cloudfront"));
|
|
38
|
-
class CloudfrontInvalidator {
|
|
1
|
+
import * as aws from '@aws-sdk/client-cloudfront';
|
|
2
|
+
export class CloudfrontInvalidator {
|
|
39
3
|
constructor(cfg) {
|
|
40
|
-
Object.defineProperty(this, "distributionId", {
|
|
41
|
-
enumerable: true,
|
|
42
|
-
configurable: true,
|
|
43
|
-
writable: true,
|
|
44
|
-
value: void 0
|
|
45
|
-
});
|
|
46
|
-
Object.defineProperty(this, "pathPrefix", {
|
|
47
|
-
enumerable: true,
|
|
48
|
-
configurable: true,
|
|
49
|
-
writable: true,
|
|
50
|
-
value: void 0
|
|
51
|
-
});
|
|
52
|
-
Object.defineProperty(this, "client", {
|
|
53
|
-
enumerable: true,
|
|
54
|
-
configurable: true,
|
|
55
|
-
writable: true,
|
|
56
|
-
value: void 0
|
|
57
|
-
});
|
|
58
4
|
const { distributionId, pathPrefix, ...rest } = cfg;
|
|
59
5
|
this.distributionId = distributionId;
|
|
60
6
|
this.pathPrefix = pathPrefix ?? '';
|
|
@@ -76,6 +22,5 @@ class CloudfrontInvalidator {
|
|
|
76
22
|
});
|
|
77
23
|
}
|
|
78
24
|
}
|
|
79
|
-
|
|
80
|
-
exports.default = CloudfrontInvalidator;
|
|
25
|
+
export default CloudfrontInvalidator;
|
|
81
26
|
//# sourceMappingURL=cloudfront.js.map
|
package/dist/cloudfront.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloudfront.js","sourceRoot":"","sources":["../src/cloudfront.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cloudfront.js","sourceRoot":"","sources":["../src/cloudfront.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,4BAA4B,CAAA;AAQjD,MAAM,OAAO,qBAAqB;IAIhC,YAAY,GAAqB;QAC/B,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,CAAA;QACnD,IAAI,CAAC,cAAc,GAAG,cAAc,CAAA;QACpC,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,EAAE,CAAA;QAClC,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC;YAC/B,GAAG,IAAI;YACP,UAAU,EAAE,YAAY;SACzB,CAAC,CAAA;IACJ,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,OAAe,EAAE,KAAe;QAC/C,MAAM,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;YACnC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,iBAAiB,EAAE;gBACjB,eAAe,EAAE,kBAAkB,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE;gBAC1D,KAAK,EAAE;oBACL,QAAQ,EAAE,KAAK,CAAC,MAAM;oBACtB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;iBACnD;aACF;SACF,CAAC,CAAA;IACJ,CAAC;CACF;AAED,eAAe,qBAAqB,CAAA","sourcesContent":["import * as aws from '@aws-sdk/client-cloudfront'\nimport { ImageInvalidator } from './types.js'\n\nexport type CloudfrontConfig = {\n distributionId: string\n pathPrefix?: string\n} & Omit<aws.CloudFrontClientConfig, 'apiVersion'>\n\nexport class CloudfrontInvalidator implements ImageInvalidator {\n distributionId: string\n pathPrefix: string\n client: aws.CloudFront\n constructor(cfg: CloudfrontConfig) {\n const { distributionId, pathPrefix, ...rest } = cfg\n this.distributionId = distributionId\n this.pathPrefix = pathPrefix ?? ''\n this.client = new aws.CloudFront({\n ...rest,\n apiVersion: '2020-05-31',\n })\n }\n async invalidate(subject: string, paths: string[]) {\n await this.client.createInvalidation({\n DistributionId: this.distributionId,\n InvalidationBatch: {\n CallerReference: `cf-invalidator-${subject}-${Date.now()}`,\n Paths: {\n Quantity: paths.length,\n Items: paths.map((path) => this.pathPrefix + path),\n },\n },\n })\n }\n}\n\nexport default CloudfrontInvalidator\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from './kms';
|
|
2
|
-
export * from './s3';
|
|
3
|
-
export * from './cloudfront';
|
|
4
|
-
export * from './bunny';
|
|
5
|
-
export * from './util';
|
|
6
|
-
export * from './types';
|
|
1
|
+
export * from './kms.js';
|
|
2
|
+
export * from './s3.js';
|
|
3
|
+
export * from './cloudfront.js';
|
|
4
|
+
export * from './bunny.js';
|
|
5
|
+
export * from './util.js';
|
|
6
|
+
export * from './types.js';
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,23 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./kms"), exports);
|
|
18
|
-
__exportStar(require("./s3"), exports);
|
|
19
|
-
__exportStar(require("./cloudfront"), exports);
|
|
20
|
-
__exportStar(require("./bunny"), exports);
|
|
21
|
-
__exportStar(require("./util"), exports);
|
|
22
|
-
__exportStar(require("./types"), exports);
|
|
1
|
+
export * from './kms.js';
|
|
2
|
+
export * from './s3.js';
|
|
3
|
+
export * from './cloudfront.js';
|
|
4
|
+
export * from './bunny.js';
|
|
5
|
+
export * from './util.js';
|
|
6
|
+
export * from './types.js';
|
|
23
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA","sourcesContent":["export * from './kms.js'\nexport * from './s3.js'\nexport * from './cloudfront.js'\nexport * from './bunny.js'\nexport * from './util.js'\nexport * from './types.js'\n"]}
|
package/dist/kms.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kms.d.ts","sourceRoot":"","sources":["../src/kms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,qBAAqB,CAAA;AAI1C,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"kms.d.ts","sourceRoot":"","sources":["../src/kms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,qBAAqB,CAAA;AAI1C,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AAOzC,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAC9C,GAAG,CAAC,eAAe,EACnB,YAAY,CACb,CAAA;AAED,qBAAa,UAAW,YAAW,MAAM,CAAC,OAAO;IAI7C,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,SAAS;IALnB,MAAM,SAA2B;gBAGvB,MAAM,EAAE,GAAG,CAAC,GAAG,EACf,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,UAAU;WAGlB,IAAI,CAAC,GAAG,EAAE,SAAS;IAoBhC,GAAG,IAAI,MAAM;IAIP,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;CAkBjD;AAED,eAAe,UAAU,CAAA"}
|
package/dist/kms.js
CHANGED
|
@@ -1,74 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.KmsKeypair = void 0;
|
|
40
|
-
const aws = __importStar(require("@aws-sdk/client-kms"));
|
|
41
|
-
const secp256k1_1 = require("@noble/curves/secp256k1");
|
|
42
|
-
const key_encoder_1 = __importDefault(require("key-encoder"));
|
|
43
|
-
const ui8 = __importStar(require("uint8arrays"));
|
|
44
|
-
const crypto = __importStar(require("@atproto/crypto"));
|
|
45
|
-
const keyEncoder = new key_encoder_1.default('secp256k1');
|
|
46
|
-
class KmsKeypair {
|
|
1
|
+
import * as aws from '@aws-sdk/client-kms';
|
|
2
|
+
import { secp256k1 as noble } from '@noble/curves/secp256k1';
|
|
3
|
+
import KeyEncoderModule from 'key-encoder';
|
|
4
|
+
import * as ui8 from 'uint8arrays';
|
|
5
|
+
import * as crypto from '@atproto/crypto';
|
|
6
|
+
// key-encoder is CJS with exports.default; Node ESM interop wraps it as { default: Class }
|
|
7
|
+
const KeyEncoder = ((m) => m.default ?? m)(KeyEncoderModule);
|
|
8
|
+
const keyEncoder = new KeyEncoder('secp256k1');
|
|
9
|
+
export class KmsKeypair {
|
|
47
10
|
constructor(client, keyId, publicKey) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
value: client
|
|
53
|
-
});
|
|
54
|
-
Object.defineProperty(this, "keyId", {
|
|
55
|
-
enumerable: true,
|
|
56
|
-
configurable: true,
|
|
57
|
-
writable: true,
|
|
58
|
-
value: keyId
|
|
59
|
-
});
|
|
60
|
-
Object.defineProperty(this, "publicKey", {
|
|
61
|
-
enumerable: true,
|
|
62
|
-
configurable: true,
|
|
63
|
-
writable: true,
|
|
64
|
-
value: publicKey
|
|
65
|
-
});
|
|
66
|
-
Object.defineProperty(this, "jwtAlg", {
|
|
67
|
-
enumerable: true,
|
|
68
|
-
configurable: true,
|
|
69
|
-
writable: true,
|
|
70
|
-
value: crypto.SECP256K1_JWT_ALG
|
|
71
|
-
});
|
|
11
|
+
this.client = client;
|
|
12
|
+
this.keyId = keyId;
|
|
13
|
+
this.publicKey = publicKey;
|
|
14
|
+
this.jwtAlg = crypto.SECP256K1_JWT_ALG;
|
|
72
15
|
}
|
|
73
16
|
static async load(cfg) {
|
|
74
17
|
const { keyId, ...rest } = cfg;
|
|
@@ -102,11 +45,10 @@ class KmsKeypair {
|
|
|
102
45
|
// we also normalize s as no more than 1/2 prime order to pass strict verification
|
|
103
46
|
// (prevents duplicating a signature)
|
|
104
47
|
// more: https://github.com/bitcoin-core/secp256k1/blob/a1102b12196ea27f44d6201de4d25926a2ae9640/include/secp256k1.h#L530-L534
|
|
105
|
-
const sig =
|
|
48
|
+
const sig = noble.Signature.fromDER(res.Signature);
|
|
106
49
|
const normalized = sig.normalizeS();
|
|
107
50
|
return normalized.toCompactRawBytes();
|
|
108
51
|
}
|
|
109
52
|
}
|
|
110
|
-
|
|
111
|
-
exports.default = KmsKeypair;
|
|
53
|
+
export default KmsKeypair;
|
|
112
54
|
//# sourceMappingURL=kms.js.map
|
package/dist/kms.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kms.js","sourceRoot":"","sources":["../src/kms.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"kms.js","sourceRoot":"","sources":["../src/kms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,SAAS,IAAI,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,gBAAgB,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,GAAG,MAAM,aAAa,CAAA;AAClC,OAAO,KAAK,MAAM,MAAM,iBAAiB,CAAA;AAEzC,2FAA2F;AAC3F,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAA;AAE5D,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAA;AAO9C,MAAM,OAAO,UAAU;IAGrB,YACU,MAAe,EACf,KAAa,EACb,SAAqB;QAFrB,WAAM,GAAN,MAAM,CAAS;QACf,UAAK,GAAL,KAAK,CAAQ;QACb,cAAS,GAAT,SAAS,CAAY;QAL/B,WAAM,GAAG,MAAM,CAAC,iBAAiB,CAAA;IAM9B,CAAC;IAEJ,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAc;QAC9B,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,CAAA;QAC9B,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC;YACzB,GAAG,IAAI;YACP,UAAU,EAAE,YAAY;SACzB,CAAC,CAAA;QACF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;QACvD,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;QAC9C,CAAC;QACD,gFAAgF;QAChF,MAAM,eAAe,GAAG,UAAU,CAAC,YAAY,CAC7C,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAC1B,KAAK,EACL,KAAK,CACN,CAAA;QACD,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC,eAAe,EAAE,KAAK,CAAC,CAAA;QACxD,OAAO,IAAI,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAA;IACjD,CAAC;IAED,GAAG;QACD,OAAO,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;IACzD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAe;QACxB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YACjC,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,GAAG;YACZ,gBAAgB,EAAE,eAAe;SAClC,CAAC,CAAA;QACF,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAA;QAC5C,CAAC;QACD,oDAAoD;QACpD,uCAAuC;QACvC,kFAAkF;QAClF,qCAAqC;QACrC,8HAA8H;QAC9H,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAClD,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,EAAE,CAAA;QACnC,OAAO,UAAU,CAAC,iBAAiB,EAAE,CAAA;IACvC,CAAC;CACF;AAED,eAAe,UAAU,CAAA","sourcesContent":["import * as aws from '@aws-sdk/client-kms'\nimport { secp256k1 as noble } from '@noble/curves/secp256k1'\nimport KeyEncoderModule from 'key-encoder'\nimport * as ui8 from 'uint8arrays'\nimport * as crypto from '@atproto/crypto'\n\n// key-encoder is CJS with exports.default; Node ESM interop wraps it as { default: Class }\nconst KeyEncoder = ((m) => m.default ?? m)(KeyEncoderModule)\n\nconst keyEncoder = new KeyEncoder('secp256k1')\n\nexport type KmsConfig = { keyId: string } & Omit<\n aws.KMSClientConfig,\n 'apiVersion'\n>\n\nexport class KmsKeypair implements crypto.Keypair {\n jwtAlg = crypto.SECP256K1_JWT_ALG\n\n constructor(\n private client: aws.KMS,\n private keyId: string,\n private publicKey: Uint8Array,\n ) {}\n\n static async load(cfg: KmsConfig) {\n const { keyId, ...rest } = cfg\n const client = new aws.KMS({\n ...rest,\n apiVersion: '2014-11-01',\n })\n const res = await client.getPublicKey({ KeyId: keyId })\n if (!res.PublicKey) {\n throw new Error('Could not find public key')\n }\n // public key comes back DER-encoded, so we translate it to raw 65 byte encoding\n const rawPublicKeyHex = keyEncoder.encodePublic(\n Buffer.from(res.PublicKey),\n 'der',\n 'raw',\n )\n const publicKey = ui8.fromString(rawPublicKeyHex, 'hex')\n return new KmsKeypair(client, keyId, publicKey)\n }\n\n did(): string {\n return crypto.formatDidKey(this.jwtAlg, this.publicKey)\n }\n\n async sign(msg: Uint8Array): Promise<Uint8Array> {\n const res = await this.client.sign({\n KeyId: this.keyId,\n Message: msg,\n SigningAlgorithm: 'ECDSA_SHA_256',\n })\n if (!res.Signature) {\n throw new Error('Could not get signature')\n }\n // signature comes back DER encoded & not-normalized\n // we translate to raw 64 byte encoding\n // we also normalize s as no more than 1/2 prime order to pass strict verification\n // (prevents duplicating a signature)\n // more: https://github.com/bitcoin-core/secp256k1/blob/a1102b12196ea27f44d6201de4d25926a2ae9640/include/secp256k1.h#L530-L534\n const sig = noble.Signature.fromDER(res.Signature)\n const normalized = sig.normalizeS()\n return normalized.toCompactRawBytes()\n }\n}\n\nexport default KmsKeypair\n"]}
|
package/dist/s3.js
CHANGED
|
@@ -1,41 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const crypto_1 = require("@atproto/crypto");
|
|
8
|
-
const repo_1 = require("@atproto/repo");
|
|
9
|
-
class S3BlobStore {
|
|
1
|
+
import { NoSuchKey, S3 } from '@aws-sdk/client-s3';
|
|
2
|
+
import { Upload } from '@aws-sdk/lib-storage';
|
|
3
|
+
import { SECOND, aggregateErrors, chunkArray } from '@atproto/common-web';
|
|
4
|
+
import { randomStr } from '@atproto/crypto';
|
|
5
|
+
import { BlobNotFoundError } from '@atproto/repo';
|
|
6
|
+
export class S3BlobStore {
|
|
10
7
|
constructor(did, cfg) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
configurable: true,
|
|
14
|
-
writable: true,
|
|
15
|
-
value: did
|
|
16
|
-
});
|
|
17
|
-
Object.defineProperty(this, "client", {
|
|
18
|
-
enumerable: true,
|
|
19
|
-
configurable: true,
|
|
20
|
-
writable: true,
|
|
21
|
-
value: void 0
|
|
22
|
-
});
|
|
23
|
-
Object.defineProperty(this, "bucket", {
|
|
24
|
-
enumerable: true,
|
|
25
|
-
configurable: true,
|
|
26
|
-
writable: true,
|
|
27
|
-
value: void 0
|
|
28
|
-
});
|
|
29
|
-
Object.defineProperty(this, "uploadTimeoutMs", {
|
|
30
|
-
enumerable: true,
|
|
31
|
-
configurable: true,
|
|
32
|
-
writable: true,
|
|
33
|
-
value: void 0
|
|
34
|
-
});
|
|
35
|
-
const { bucket, uploadTimeoutMs = 10 * common_web_1.SECOND, requestTimeoutMs = uploadTimeoutMs, ...rest } = cfg;
|
|
8
|
+
this.did = did;
|
|
9
|
+
const { bucket, uploadTimeoutMs = 10 * SECOND, requestTimeoutMs = uploadTimeoutMs, ...rest } = cfg;
|
|
36
10
|
this.bucket = bucket;
|
|
37
11
|
this.uploadTimeoutMs = uploadTimeoutMs;
|
|
38
|
-
this.client = new
|
|
12
|
+
this.client = new S3({
|
|
39
13
|
...rest,
|
|
40
14
|
apiVersion: '2006-03-01',
|
|
41
15
|
// Ensures that all requests timeout under "requestTimeoutMs".
|
|
@@ -51,7 +25,7 @@ class S3BlobStore {
|
|
|
51
25
|
};
|
|
52
26
|
}
|
|
53
27
|
genKey() {
|
|
54
|
-
return
|
|
28
|
+
return randomStr(32, 'base32');
|
|
55
29
|
}
|
|
56
30
|
getTmpPath(key) {
|
|
57
31
|
return `tmp/${this.did}/${key}`;
|
|
@@ -73,7 +47,7 @@ class S3BlobStore {
|
|
|
73
47
|
const abortSignal = AbortSignal.timeout(this.uploadTimeoutMs);
|
|
74
48
|
const abortController = new AbortController();
|
|
75
49
|
abortSignal.addEventListener('abort', () => abortController.abort());
|
|
76
|
-
const upload = new
|
|
50
|
+
const upload = new Upload({
|
|
77
51
|
client: this.client,
|
|
78
52
|
params: {
|
|
79
53
|
Bucket: this.bucket,
|
|
@@ -114,7 +88,7 @@ class S3BlobStore {
|
|
|
114
88
|
// check if the permanent file already exists. If it does, we can assume
|
|
115
89
|
// that another process made the file permanent concurrently, and we can
|
|
116
90
|
// no-op.
|
|
117
|
-
if (err instanceof
|
|
91
|
+
if (err instanceof BlobNotFoundError) {
|
|
118
92
|
// Blob was not found from temp storage...
|
|
119
93
|
const alreadyHas = await this.hasStored(cid);
|
|
120
94
|
// already saved, so we no-op
|
|
@@ -148,7 +122,7 @@ class S3BlobStore {
|
|
|
148
122
|
return res.Body;
|
|
149
123
|
}
|
|
150
124
|
else {
|
|
151
|
-
throw new
|
|
125
|
+
throw new BlobNotFoundError();
|
|
152
126
|
}
|
|
153
127
|
}
|
|
154
128
|
async getBytes(cid) {
|
|
@@ -164,7 +138,7 @@ class S3BlobStore {
|
|
|
164
138
|
}
|
|
165
139
|
async deleteMany(cids) {
|
|
166
140
|
const errors = [];
|
|
167
|
-
for (const chunk of
|
|
141
|
+
for (const chunk of chunkArray(cids, 500)) {
|
|
168
142
|
try {
|
|
169
143
|
const keys = chunk.map((cid) => this.getStoredPath(cid));
|
|
170
144
|
await this.deleteManyKeys(keys);
|
|
@@ -174,7 +148,7 @@ class S3BlobStore {
|
|
|
174
148
|
}
|
|
175
149
|
}
|
|
176
150
|
if (errors.length)
|
|
177
|
-
throw
|
|
151
|
+
throw aggregateErrors(errors);
|
|
178
152
|
}
|
|
179
153
|
async hasStored(cid) {
|
|
180
154
|
return this.hasKey(this.getStoredPath(cid));
|
|
@@ -217,9 +191,9 @@ class S3BlobStore {
|
|
|
217
191
|
});
|
|
218
192
|
}
|
|
219
193
|
catch (cause) {
|
|
220
|
-
if (cause instanceof
|
|
194
|
+
if (cause instanceof NoSuchKey) {
|
|
221
195
|
// Already deleted, possibly by a concurrently running process
|
|
222
|
-
throw new
|
|
196
|
+
throw new BlobNotFoundError(undefined, { cause });
|
|
223
197
|
}
|
|
224
198
|
throw cause;
|
|
225
199
|
}
|
|
@@ -230,7 +204,7 @@ class S3BlobStore {
|
|
|
230
204
|
});
|
|
231
205
|
}
|
|
232
206
|
catch (err) {
|
|
233
|
-
if (err instanceof
|
|
207
|
+
if (err instanceof NoSuchKey) {
|
|
234
208
|
// Already deleted, possibly by a concurrently running process
|
|
235
209
|
return;
|
|
236
210
|
}
|
|
@@ -238,6 +212,5 @@ class S3BlobStore {
|
|
|
238
212
|
}
|
|
239
213
|
}
|
|
240
214
|
}
|
|
241
|
-
|
|
242
|
-
exports.default = S3BlobStore;
|
|
215
|
+
export default S3BlobStore;
|
|
243
216
|
//# sourceMappingURL=s3.js.map
|
package/dist/s3.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../src/s3.ts"],"names":[],"mappings":"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","sourcesContent":["import stream from 'node:stream'\nimport { NoSuchKey, S3, S3ClientConfig } from '@aws-sdk/client-s3'\nimport { Upload } from '@aws-sdk/lib-storage'\nimport { CID } from 'multiformats/cid'\nimport { SECOND, aggregateErrors, chunkArray } from '@atproto/common-web'\nimport { randomStr } from '@atproto/crypto'\nimport { BlobNotFoundError, BlobStore } from '@atproto/repo'\n\nexport type S3Config = {\n bucket: string\n /**\n * The maximum time any request to S3 (including individual blob chunks\n * uploads) can take, in milliseconds.\n */\n requestTimeoutMs?: number\n /**\n * The maximum total time a blob upload can take, in milliseconds.\n */\n uploadTimeoutMs?: number\n} & Omit<S3ClientConfig, 'apiVersion' | 'requestHandler'>\n\nexport class S3BlobStore implements BlobStore {\n private client: S3\n private bucket: string\n private uploadTimeoutMs: number\n\n constructor(\n public did: string,\n cfg: S3Config,\n ) {\n const {\n bucket,\n uploadTimeoutMs = 10 * SECOND,\n requestTimeoutMs = uploadTimeoutMs,\n ...rest\n } = cfg\n this.bucket = bucket\n this.uploadTimeoutMs = uploadTimeoutMs\n this.client = new S3({\n ...rest,\n apiVersion: '2006-03-01',\n // Ensures that all requests timeout under \"requestTimeoutMs\".\n //\n // @NOTE This will also apply to the upload of each individual chunk\n // when using Upload from @aws-sdk/lib-storage.\n requestHandler: { requestTimeout: requestTimeoutMs },\n })\n }\n\n static creator(cfg: S3Config) {\n return (did: string) => {\n return new S3BlobStore(did, cfg)\n }\n }\n\n private genKey() {\n return randomStr(32, 'base32')\n }\n\n private getTmpPath(key: string): string {\n return `tmp/${this.did}/${key}`\n }\n\n private getStoredPath(cid: CID): string {\n return `blocks/${this.did}/${cid.toString()}`\n }\n\n private getQuarantinedPath(cid: CID): string {\n return `quarantine/${this.did}/${cid.toString()}`\n }\n\n private async uploadBytes(path: string, bytes: Uint8Array | stream.Readable) {\n // @NOTE we use Upload rather than client.putObject because stream length is\n // not known in advance. See also aws/aws-sdk-js-v3#2348.\n //\n // See also https://github.com/aws/aws-sdk-js-v3/issues/6426, wherein Upload\n // may hang the s3 connection under certain circumstances. We don't have a\n // good way to avoid this, so we use timeouts defensively on all s3\n // requests.\n\n const abortSignal = AbortSignal.timeout(this.uploadTimeoutMs)\n const abortController = new AbortController()\n abortSignal.addEventListener('abort', () => abortController.abort())\n\n const upload = new Upload({\n client: this.client,\n params: {\n Bucket: this.bucket,\n Body: bytes,\n Key: path,\n },\n // @ts-ignore native implementation fine in node >=15\n abortController,\n })\n\n try {\n await upload.done()\n } catch (err) {\n // Translate aws-sdk's abort error to something more specific\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error('Blob upload timed out', { cause: err })\n }\n\n throw err\n }\n }\n\n async putTemp(bytes: Uint8Array | stream.Readable): Promise<string> {\n const key = this.genKey()\n await this.uploadBytes(this.getTmpPath(key), bytes)\n return key\n }\n\n async makePermanent(key: string, cid: CID): Promise<void> {\n try {\n // @NOTE we normally call this method when we know the file is temporary.\n // Because of this, we optimistically move the file, allowing to make\n // fewer network requests in the happy path.\n await this.move({\n from: this.getTmpPath(key),\n to: this.getStoredPath(cid),\n })\n } catch (err) {\n // If the optimistic move failed because the temp file was not found,\n // check if the permanent file already exists. If it does, we can assume\n // that another process made the file permanent concurrently, and we can\n // no-op.\n if (err instanceof BlobNotFoundError) {\n // Blob was not found from temp storage...\n const alreadyHas = await this.hasStored(cid)\n // already saved, so we no-op\n if (alreadyHas) return\n }\n\n throw err\n }\n }\n\n async putPermanent(\n cid: CID,\n bytes: Uint8Array | stream.Readable,\n ): Promise<void> {\n await this.uploadBytes(this.getStoredPath(cid), bytes)\n }\n\n async quarantine(cid: CID): Promise<void> {\n await this.move({\n from: this.getStoredPath(cid),\n to: this.getQuarantinedPath(cid),\n })\n }\n\n async unquarantine(cid: CID): Promise<void> {\n await this.move({\n from: this.getQuarantinedPath(cid),\n to: this.getStoredPath(cid),\n })\n }\n\n private async getObject(cid: CID) {\n const res = await this.client.getObject({\n Bucket: this.bucket,\n Key: this.getStoredPath(cid),\n })\n if (res.Body) {\n return res.Body\n } else {\n throw new BlobNotFoundError()\n }\n }\n\n async getBytes(cid: CID): Promise<Uint8Array> {\n const res = await this.getObject(cid)\n return res.transformToByteArray()\n }\n\n async getStream(cid: CID): Promise<stream.Readable> {\n const res = await this.getObject(cid)\n return res as stream.Readable\n }\n\n async delete(cid: CID): Promise<void> {\n await this.deleteKey(this.getStoredPath(cid))\n }\n\n async deleteMany(cids: CID[]): Promise<void> {\n const errors: unknown[] = []\n for (const chunk of chunkArray(cids, 500)) {\n try {\n const keys = chunk.map((cid) => this.getStoredPath(cid))\n await this.deleteManyKeys(keys)\n } catch (err) {\n errors.push(err)\n }\n }\n if (errors.length) throw aggregateErrors(errors)\n }\n\n async hasStored(cid: CID): Promise<boolean> {\n return this.hasKey(this.getStoredPath(cid))\n }\n\n async hasTemp(key: string): Promise<boolean> {\n return this.hasKey(this.getTmpPath(key))\n }\n\n private async hasKey(key: string) {\n try {\n const res = await this.client.headObject({\n Bucket: this.bucket,\n Key: key,\n })\n return res.$metadata.httpStatusCode === 200\n } catch (err) {\n return false\n }\n }\n\n private async deleteKey(key: string) {\n await this.client.deleteObject({\n Bucket: this.bucket,\n Key: key,\n })\n }\n\n private async deleteManyKeys(keys: string[]) {\n await this.client.deleteObjects({\n Bucket: this.bucket,\n Delete: {\n Objects: keys.map((k) => ({ Key: k })),\n },\n })\n }\n\n private async move(keys: { from: string; to: string }) {\n try {\n await this.client.copyObject({\n Bucket: this.bucket,\n CopySource: `${this.bucket}/${keys.from}`,\n Key: keys.to,\n })\n } catch (cause) {\n if (cause instanceof NoSuchKey) {\n // Already deleted, possibly by a concurrently running process\n throw new BlobNotFoundError(undefined, { cause })\n }\n\n throw cause\n }\n\n try {\n await this.client.deleteObject({\n Bucket: this.bucket,\n Key: keys.from,\n })\n } catch (err) {\n if (err instanceof NoSuchKey) {\n // Already deleted, possibly by a concurrently running process\n return\n }\n\n throw err\n }\n }\n}\n\nexport default S3BlobStore\n"]}
|
|
1
|
+
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../src/s3.ts"],"names":[],"mappings":"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","sourcesContent":["import stream from 'node:stream'\nimport { NoSuchKey, S3, S3ClientConfig } from '@aws-sdk/client-s3'\nimport { Upload } from '@aws-sdk/lib-storage'\nimport { CID } from 'multiformats/cid'\nimport { SECOND, aggregateErrors, chunkArray } from '@atproto/common-web'\nimport { randomStr } from '@atproto/crypto'\nimport { BlobNotFoundError, BlobStore } from '@atproto/repo'\n\nexport type S3Config = {\n bucket: string\n /**\n * The maximum time any request to S3 (including individual blob chunks\n * uploads) can take, in milliseconds.\n */\n requestTimeoutMs?: number\n /**\n * The maximum total time a blob upload can take, in milliseconds.\n */\n uploadTimeoutMs?: number\n} & Omit<S3ClientConfig, 'apiVersion' | 'requestHandler'>\n\nexport class S3BlobStore implements BlobStore {\n private client: S3\n private bucket: string\n private uploadTimeoutMs: number\n\n constructor(\n public did: string,\n cfg: S3Config,\n ) {\n const {\n bucket,\n uploadTimeoutMs = 10 * SECOND,\n requestTimeoutMs = uploadTimeoutMs,\n ...rest\n } = cfg\n this.bucket = bucket\n this.uploadTimeoutMs = uploadTimeoutMs\n this.client = new S3({\n ...rest,\n apiVersion: '2006-03-01',\n // Ensures that all requests timeout under \"requestTimeoutMs\".\n //\n // @NOTE This will also apply to the upload of each individual chunk\n // when using Upload from @aws-sdk/lib-storage.\n requestHandler: { requestTimeout: requestTimeoutMs },\n })\n }\n\n static creator(cfg: S3Config) {\n return (did: string) => {\n return new S3BlobStore(did, cfg)\n }\n }\n\n private genKey() {\n return randomStr(32, 'base32')\n }\n\n private getTmpPath(key: string): string {\n return `tmp/${this.did}/${key}`\n }\n\n private getStoredPath(cid: CID): string {\n return `blocks/${this.did}/${cid.toString()}`\n }\n\n private getQuarantinedPath(cid: CID): string {\n return `quarantine/${this.did}/${cid.toString()}`\n }\n\n private async uploadBytes(path: string, bytes: Uint8Array | stream.Readable) {\n // @NOTE we use Upload rather than client.putObject because stream length is\n // not known in advance. See also aws/aws-sdk-js-v3#2348.\n //\n // See also https://github.com/aws/aws-sdk-js-v3/issues/6426, wherein Upload\n // may hang the s3 connection under certain circumstances. We don't have a\n // good way to avoid this, so we use timeouts defensively on all s3\n // requests.\n\n const abortSignal = AbortSignal.timeout(this.uploadTimeoutMs)\n const abortController = new AbortController()\n abortSignal.addEventListener('abort', () => abortController.abort())\n\n const upload = new Upload({\n client: this.client,\n params: {\n Bucket: this.bucket,\n Body: bytes,\n Key: path,\n },\n // @ts-ignore native implementation fine in node >=15\n abortController,\n })\n\n try {\n await upload.done()\n } catch (err) {\n // Translate aws-sdk's abort error to something more specific\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error('Blob upload timed out', { cause: err })\n }\n\n throw err\n }\n }\n\n async putTemp(bytes: Uint8Array | stream.Readable): Promise<string> {\n const key = this.genKey()\n await this.uploadBytes(this.getTmpPath(key), bytes)\n return key\n }\n\n async makePermanent(key: string, cid: CID): Promise<void> {\n try {\n // @NOTE we normally call this method when we know the file is temporary.\n // Because of this, we optimistically move the file, allowing to make\n // fewer network requests in the happy path.\n await this.move({\n from: this.getTmpPath(key),\n to: this.getStoredPath(cid),\n })\n } catch (err) {\n // If the optimistic move failed because the temp file was not found,\n // check if the permanent file already exists. If it does, we can assume\n // that another process made the file permanent concurrently, and we can\n // no-op.\n if (err instanceof BlobNotFoundError) {\n // Blob was not found from temp storage...\n const alreadyHas = await this.hasStored(cid)\n // already saved, so we no-op\n if (alreadyHas) return\n }\n\n throw err\n }\n }\n\n async putPermanent(\n cid: CID,\n bytes: Uint8Array | stream.Readable,\n ): Promise<void> {\n await this.uploadBytes(this.getStoredPath(cid), bytes)\n }\n\n async quarantine(cid: CID): Promise<void> {\n await this.move({\n from: this.getStoredPath(cid),\n to: this.getQuarantinedPath(cid),\n })\n }\n\n async unquarantine(cid: CID): Promise<void> {\n await this.move({\n from: this.getQuarantinedPath(cid),\n to: this.getStoredPath(cid),\n })\n }\n\n private async getObject(cid: CID) {\n const res = await this.client.getObject({\n Bucket: this.bucket,\n Key: this.getStoredPath(cid),\n })\n if (res.Body) {\n return res.Body\n } else {\n throw new BlobNotFoundError()\n }\n }\n\n async getBytes(cid: CID): Promise<Uint8Array> {\n const res = await this.getObject(cid)\n return res.transformToByteArray()\n }\n\n async getStream(cid: CID): Promise<stream.Readable> {\n const res = await this.getObject(cid)\n return res as stream.Readable\n }\n\n async delete(cid: CID): Promise<void> {\n await this.deleteKey(this.getStoredPath(cid))\n }\n\n async deleteMany(cids: CID[]): Promise<void> {\n const errors: unknown[] = []\n for (const chunk of chunkArray(cids, 500)) {\n try {\n const keys = chunk.map((cid) => this.getStoredPath(cid))\n await this.deleteManyKeys(keys)\n } catch (err) {\n errors.push(err)\n }\n }\n if (errors.length) throw aggregateErrors(errors)\n }\n\n async hasStored(cid: CID): Promise<boolean> {\n return this.hasKey(this.getStoredPath(cid))\n }\n\n async hasTemp(key: string): Promise<boolean> {\n return this.hasKey(this.getTmpPath(key))\n }\n\n private async hasKey(key: string) {\n try {\n const res = await this.client.headObject({\n Bucket: this.bucket,\n Key: key,\n })\n return res.$metadata.httpStatusCode === 200\n } catch (err) {\n return false\n }\n }\n\n private async deleteKey(key: string) {\n await this.client.deleteObject({\n Bucket: this.bucket,\n Key: key,\n })\n }\n\n private async deleteManyKeys(keys: string[]) {\n await this.client.deleteObjects({\n Bucket: this.bucket,\n Delete: {\n Objects: keys.map((k) => ({ Key: k })),\n },\n })\n }\n\n private async move(keys: { from: string; to: string }) {\n try {\n await this.client.copyObject({\n Bucket: this.bucket,\n CopySource: `${this.bucket}/${keys.from}`,\n Key: keys.to,\n })\n } catch (cause) {\n if (cause instanceof NoSuchKey) {\n // Already deleted, possibly by a concurrently running process\n throw new BlobNotFoundError(undefined, { cause })\n }\n\n throw cause\n }\n\n try {\n await this.client.deleteObject({\n Bucket: this.bucket,\n Key: keys.from,\n })\n } catch (err) {\n if (err instanceof NoSuchKey) {\n // Already deleted, possibly by a concurrently running process\n return\n }\n\n throw err\n }\n }\n}\n\nexport default S3BlobStore\n"]}
|
package/dist/types.js
CHANGED
package/dist/util.d.ts
CHANGED
package/dist/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE7C,qBAAa,qBAAsB,YAAW,gBAAgB;IACzC,YAAY,EAAE,gBAAgB,EAAE;gBAAhC,YAAY,EAAE,gBAAgB,EAAE;IAC7C,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;CAOlD"}
|
package/dist/util.js
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.MultiImageInvalidator = void 0;
|
|
4
|
-
const common_1 = require("@atproto/common");
|
|
5
|
-
class MultiImageInvalidator {
|
|
1
|
+
import { allFulfilled } from '@atproto/common';
|
|
2
|
+
export class MultiImageInvalidator {
|
|
6
3
|
constructor(invalidators) {
|
|
7
|
-
|
|
8
|
-
enumerable: true,
|
|
9
|
-
configurable: true,
|
|
10
|
-
writable: true,
|
|
11
|
-
value: invalidators
|
|
12
|
-
});
|
|
4
|
+
this.invalidators = invalidators;
|
|
13
5
|
}
|
|
14
6
|
async invalidate(subject, paths) {
|
|
15
|
-
await
|
|
7
|
+
await allFulfilled(this.invalidators.map((invalidator) => invalidator.invalidate(subject, paths)));
|
|
16
8
|
}
|
|
17
9
|
}
|
|
18
|
-
exports.MultiImageInvalidator = MultiImageInvalidator;
|
|
19
10
|
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAG9C,MAAM,OAAO,qBAAqB;IAChC,YAAmB,YAAgC;QAAhC,iBAAY,GAAZ,YAAY,CAAoB;IAAG,CAAC;IACvD,KAAK,CAAC,UAAU,CAAC,OAAe,EAAE,KAAe;QAC/C,MAAM,YAAY,CAChB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CACpC,WAAW,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CACvC,CACF,CAAA;IACH,CAAC;CACF","sourcesContent":["import { allFulfilled } from '@atproto/common'\nimport { ImageInvalidator } from './types.js'\n\nexport class MultiImageInvalidator implements ImageInvalidator {\n constructor(public invalidators: ImageInvalidator[]) {}\n async invalidate(subject: string, paths: string[]) {\n await allFulfilled(\n this.invalidators.map((invalidator) =>\n invalidator.invalidate(subject, paths),\n ),\n )\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/aws",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Shared AWS cloud API helpers for atproto services",
|
|
6
6
|
"keywords": [
|
|
@@ -13,10 +13,8 @@
|
|
|
13
13
|
"url": "https://github.com/bluesky-social/atproto",
|
|
14
14
|
"directory": "packages/aws"
|
|
15
15
|
},
|
|
16
|
-
"main": "dist/index.js",
|
|
17
|
-
"types": "dist/index.d.ts",
|
|
18
16
|
"engines": {
|
|
19
|
-
"node": ">=
|
|
17
|
+
"node": ">=22"
|
|
20
18
|
},
|
|
21
19
|
"dependencies": {
|
|
22
20
|
"@aws-sdk/client-cloudfront": "^3.879.0",
|
|
@@ -25,15 +23,22 @@
|
|
|
25
23
|
"@aws-sdk/lib-storage": "3.879.0",
|
|
26
24
|
"@noble/curves": "^1.7.0",
|
|
27
25
|
"key-encoder": "^2.0.3",
|
|
28
|
-
"multiformats": "^
|
|
29
|
-
"uint8arrays": "
|
|
30
|
-
"@atproto/common": "^0.
|
|
31
|
-
"@atproto/common-web": "^0.
|
|
32
|
-
"@atproto/crypto": "^0.
|
|
33
|
-
"@atproto/repo": "^0.
|
|
26
|
+
"multiformats": "^13.0.0",
|
|
27
|
+
"uint8arrays": "^5.0.0",
|
|
28
|
+
"@atproto/common": "^0.6.0",
|
|
29
|
+
"@atproto/common-web": "^0.5.0",
|
|
30
|
+
"@atproto/crypto": "^0.5.0",
|
|
31
|
+
"@atproto/repo": "^0.10.0"
|
|
34
32
|
},
|
|
35
33
|
"devDependencies": {
|
|
36
|
-
"typescript": "^
|
|
34
|
+
"typescript": "^6.0.3"
|
|
35
|
+
},
|
|
36
|
+
"type": "module",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"default": "./dist/index.js"
|
|
41
|
+
}
|
|
37
42
|
},
|
|
38
43
|
"scripts": {
|
|
39
44
|
"build": "tsc --build tsconfig.build.json"
|
package/src/bunny.ts
CHANGED
package/src/cloudfront.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export * from './kms'
|
|
2
|
-
export * from './s3'
|
|
3
|
-
export * from './cloudfront'
|
|
4
|
-
export * from './bunny'
|
|
5
|
-
export * from './util'
|
|
6
|
-
export * from './types'
|
|
1
|
+
export * from './kms.js'
|
|
2
|
+
export * from './s3.js'
|
|
3
|
+
export * from './cloudfront.js'
|
|
4
|
+
export * from './bunny.js'
|
|
5
|
+
export * from './util.js'
|
|
6
|
+
export * from './types.js'
|
package/src/kms.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import * as aws from '@aws-sdk/client-kms'
|
|
2
2
|
import { secp256k1 as noble } from '@noble/curves/secp256k1'
|
|
3
|
-
import
|
|
3
|
+
import KeyEncoderModule from 'key-encoder'
|
|
4
4
|
import * as ui8 from 'uint8arrays'
|
|
5
5
|
import * as crypto from '@atproto/crypto'
|
|
6
6
|
|
|
7
|
+
// key-encoder is CJS with exports.default; Node ESM interop wraps it as { default: Class }
|
|
8
|
+
const KeyEncoder = ((m) => m.default ?? m)(KeyEncoderModule)
|
|
9
|
+
|
|
7
10
|
const keyEncoder = new KeyEncoder('secp256k1')
|
|
8
11
|
|
|
9
12
|
export type KmsConfig = { keyId: string } & Omit<
|
package/src/util.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/bunny.ts","./src/cloudfront.ts","./src/index.ts","./src/kms.ts","./src/s3.ts","./src/types.ts","./src/util.ts"],"version":"
|
|
1
|
+
{"root":["./src/bunny.ts","./src/cloudfront.ts","./src/index.ts","./src/kms.ts","./src/s3.ts","./src/types.ts","./src/util.ts"],"version":"6.0.3"}
|