@kutur-kit/assets 0.0.0-stage → 0.1.0-alpha.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 +21 -0
- package/README.md +161 -2
- package/dist/Asset.d.ts +174 -0
- package/dist/Asset.d.ts.map +1 -0
- package/dist/Asset.js +156 -0
- package/dist/Asset.js.map +1 -0
- package/dist/AssetBucket.d.ts +73 -0
- package/dist/AssetBucket.d.ts.map +1 -0
- package/dist/AssetBucket.js +19 -0
- package/dist/AssetBucket.js.map +1 -0
- package/dist/AssetDelivery.d.ts +23 -0
- package/dist/AssetDelivery.d.ts.map +1 -0
- package/dist/AssetDelivery.js +12 -0
- package/dist/AssetDelivery.js.map +1 -0
- package/dist/AssetSigning.d.ts +109 -0
- package/dist/AssetSigning.d.ts.map +1 -0
- package/dist/AssetSigning.js +93 -0
- package/dist/AssetSigning.js.map +1 -0
- package/dist/alchemy/r2.d.ts +40 -0
- package/dist/alchemy/r2.d.ts.map +1 -0
- package/dist/alchemy/r2.js +84 -0
- package/dist/alchemy/r2.js.map +1 -0
- package/dist/delivery/local.d.ts +17 -0
- package/dist/delivery/local.d.ts.map +1 -0
- package/dist/delivery/local.js +20 -0
- package/dist/delivery/local.js.map +1 -0
- package/dist/filesystem.d.ts +15 -0
- package/dist/filesystem.d.ts.map +1 -0
- package/dist/filesystem.js +90 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/bytes.d.ts +3 -0
- package/dist/internal/bytes.d.ts.map +1 -0
- package/dist/internal/bytes.js +11 -0
- package/dist/internal/bytes.js.map +1 -0
- package/dist/internal/http.d.ts +17 -0
- package/dist/internal/http.d.ts.map +1 -0
- package/dist/internal/http.js +38 -0
- package/dist/internal/http.js.map +1 -0
- package/dist/internal/sigv4.d.ts +15 -0
- package/dist/internal/sigv4.d.ts.map +1 -0
- package/dist/internal/sigv4.js +52 -0
- package/dist/internal/sigv4.js.map +1 -0
- package/dist/internal/url.d.ts +3 -0
- package/dist/internal/url.d.ts.map +1 -0
- package/dist/internal/url.js +3 -0
- package/dist/internal/url.js.map +1 -0
- package/dist/memory.d.ts +11 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +34 -0
- package/dist/memory.js.map +1 -0
- package/dist/s3.d.ts +42 -0
- package/dist/s3.d.ts.map +1 -0
- package/dist/s3.js +67 -0
- package/dist/s3.js.map +1 -0
- package/dist/signing/local.d.ts +27 -0
- package/dist/signing/local.d.ts.map +1 -0
- package/dist/signing/local.js +128 -0
- package/dist/signing/local.js.map +1 -0
- package/dist/testing/AssetBucketContract.d.ts +18 -0
- package/dist/testing/AssetBucketContract.d.ts.map +1 -0
- package/dist/testing/AssetBucketContract.js +124 -0
- package/dist/testing/AssetBucketContract.js.map +1 -0
- package/dist/testing/AssetSigningContract.d.ts +18 -0
- package/dist/testing/AssetSigningContract.d.ts.map +1 -0
- package/dist/testing/AssetSigningContract.js +132 -0
- package/dist/testing/AssetSigningContract.js.map +1 -0
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +3 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +103 -3
- package/src/Asset.ts +443 -0
- package/src/AssetBucket.ts +82 -0
- package/src/AssetDelivery.ts +41 -0
- package/src/AssetSigning.ts +206 -0
- package/src/alchemy/r2.ts +151 -0
- package/src/delivery/local.ts +41 -0
- package/src/filesystem.ts +166 -0
- package/src/index.ts +3 -0
- package/src/internal/bytes.ts +12 -0
- package/src/internal/http.ts +54 -0
- package/src/internal/sigv4.ts +84 -0
- package/src/internal/url.ts +2 -0
- package/src/memory.ts +65 -0
- package/src/s3.ts +138 -0
- package/src/signing/local.ts +210 -0
- package/src/testing/AssetBucketContract.ts +215 -0
- package/src/testing/AssetSigningContract.ts +254 -0
- package/src/testing/index.ts +3 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { ByteSize, Effect, Option, Result, Schema, Stream } from "effect";
|
|
2
|
+
import * as AssetBucket from "../AssetBucket.js";
|
|
3
|
+
/** The bucket the cases use. Back it with the implementation under test. */
|
|
4
|
+
export class ContractBucket extends AssetBucket.Service()("assets-contract") {
|
|
5
|
+
}
|
|
6
|
+
const text = (value) => new TextEncoder().encode(value);
|
|
7
|
+
const put = (key, chunks, contentType = "text/plain", cacheControl) => Effect.flatMap(ContractBucket, (bucket) => bucket.put({ key, contentType, cacheControl, body: Stream.fromIterable(chunks.map(text)) }));
|
|
8
|
+
// The stored body as text, or null when the object is missing.
|
|
9
|
+
const read = (key) => Effect.flatMap(ContractBucket, (bucket) => bucket.get(key)).pipe(Effect.flatMap(Option.match({
|
|
10
|
+
onNone: () => Effect.succeed(null),
|
|
11
|
+
onSome: ({ body }) => Stream.runCollect(body).pipe(Effect.map((chunks) => chunks.map((chunk) => new TextDecoder().decode(chunk)).join(""))),
|
|
12
|
+
})));
|
|
13
|
+
const head = (key) => Effect.flatMap(ContractBucket, (bucket) => bucket.head(key));
|
|
14
|
+
const remove = (key) => Effect.flatMap(ContractBucket, (bucket) => bucket.delete(key));
|
|
15
|
+
const expectEqual = (label, expected, received) => {
|
|
16
|
+
const [want, got] = [expected, received].map((value) => JSON.stringify(value));
|
|
17
|
+
return want === got
|
|
18
|
+
? Effect.void
|
|
19
|
+
: Effect.die(new Error(`AssetBucket contract violated: ${label}\nexpected: ${want}\nreceived: ${got}`));
|
|
20
|
+
};
|
|
21
|
+
const expectBody = (key, expected) => Effect.flatMap(read(key), (body) => expectEqual(`body of ${key}`, expected, body));
|
|
22
|
+
// Encoding checks that sizes are ByteSize values and drops fields stores may add.
|
|
23
|
+
const encodeInfo = Schema.encodeEffect(Schema.toCodecJson(Schema.NullOr(Schema.Struct({
|
|
24
|
+
size: Schema.ByteSize,
|
|
25
|
+
contentType: Schema.String,
|
|
26
|
+
cacheControl: Schema.optionalKey(Schema.String),
|
|
27
|
+
}))));
|
|
28
|
+
// No cache control compares equal whether a store omits it or sets it to undefined.
|
|
29
|
+
const comparable = (info) => {
|
|
30
|
+
if (info === null)
|
|
31
|
+
return null;
|
|
32
|
+
const { size, contentType, cacheControl } = info;
|
|
33
|
+
return cacheControl === undefined ? { size, contentType } : { size, contentType, cacheControl };
|
|
34
|
+
};
|
|
35
|
+
const expectInfo = (label, expected, received) => Effect.flatMap(Effect.all([encodeInfo(comparable(expected)), encodeInfo(comparable(received))]), ([want, got]) => expectEqual(label, want, got)).pipe(Effect.orDie);
|
|
36
|
+
const expectHead = (key, expected) => Effect.flatMap(head(key), (info) => expectInfo(`head of ${key}`, expected, Option.getOrNull(info)));
|
|
37
|
+
const stored = "contract/stored.txt";
|
|
38
|
+
const nested = "contract/nested";
|
|
39
|
+
const child = "contract/nested/child";
|
|
40
|
+
export const cases = [
|
|
41
|
+
{
|
|
42
|
+
name: "returns the stored bytes and info",
|
|
43
|
+
run: Effect.gen(function* () {
|
|
44
|
+
const info = yield* put(stored, ["hello, ", "", "wörld"], "text/plain; charset=utf-8");
|
|
45
|
+
const expected = { size: ByteSize.bytes(13), contentType: "text/plain; charset=utf-8" };
|
|
46
|
+
yield* expectInfo("put info", expected, info);
|
|
47
|
+
yield* expectHead(stored, expected);
|
|
48
|
+
yield* expectBody(stored, "hello, wörld");
|
|
49
|
+
const object = yield* Effect.flatMap(ContractBucket, (bucket) => bucket.get(stored));
|
|
50
|
+
yield* expectInfo(`get info of ${stored}`, expected, Option.getOrNull(Option.map(object, ({ info }) => info)));
|
|
51
|
+
}).pipe(Effect.orDie),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "stores empty objects",
|
|
55
|
+
run: Effect.gen(function* () {
|
|
56
|
+
yield* put(stored, [], "application/octet-stream");
|
|
57
|
+
yield* expectHead(stored, { size: ByteSize.zero, contentType: "application/octet-stream" });
|
|
58
|
+
yield* expectBody(stored, "");
|
|
59
|
+
}).pipe(Effect.orDie),
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "replaces an object on put",
|
|
63
|
+
run: Effect.gen(function* () {
|
|
64
|
+
yield* put(stored, ["first version"]);
|
|
65
|
+
yield* put(stored, ["second"], "text/markdown");
|
|
66
|
+
yield* expectHead(stored, { size: ByteSize.bytes(6), contentType: "text/markdown" });
|
|
67
|
+
yield* expectBody(stored, "second");
|
|
68
|
+
}).pipe(Effect.orDie),
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "stores the cache control an object is served with, and replaces it on put",
|
|
72
|
+
run: Effect.gen(function* () {
|
|
73
|
+
const immutable = "public, max-age=31536000, immutable";
|
|
74
|
+
const info = yield* put(stored, ["cached"], "text/plain", immutable);
|
|
75
|
+
const expected = {
|
|
76
|
+
size: ByteSize.bytes(6),
|
|
77
|
+
contentType: "text/plain",
|
|
78
|
+
cacheControl: immutable,
|
|
79
|
+
};
|
|
80
|
+
yield* expectInfo("put info", expected, info);
|
|
81
|
+
yield* expectHead(stored, expected);
|
|
82
|
+
const object = yield* Effect.flatMap(ContractBucket, (bucket) => bucket.get(stored));
|
|
83
|
+
yield* expectInfo(`get info of ${stored}`, expected, Option.getOrNull(Option.map(object, ({ info }) => info)));
|
|
84
|
+
yield* put(stored, ["uncached"]);
|
|
85
|
+
yield* expectHead(stored, { size: ByteSize.bytes(8), contentType: "text/plain" });
|
|
86
|
+
}).pipe(Effect.orDie),
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "keeps a key and the keys nested under it apart",
|
|
90
|
+
run: Effect.gen(function* () {
|
|
91
|
+
yield* put(nested, ["parent"]);
|
|
92
|
+
yield* put(child, ["child"]);
|
|
93
|
+
yield* remove(child);
|
|
94
|
+
yield* expectBody(nested, "parent");
|
|
95
|
+
yield* expectBody(child, null);
|
|
96
|
+
yield* put(child, ["child"]);
|
|
97
|
+
yield* remove(nested);
|
|
98
|
+
yield* expectBody(child, "child");
|
|
99
|
+
}).pipe(Effect.orDie),
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "reports missing objects and deletes them more than once",
|
|
103
|
+
run: Effect.gen(function* () {
|
|
104
|
+
yield* put(stored, ["to delete"]);
|
|
105
|
+
yield* remove(stored);
|
|
106
|
+
yield* expectHead(stored, null);
|
|
107
|
+
yield* expectBody(stored, null);
|
|
108
|
+
yield* remove(stored);
|
|
109
|
+
}).pipe(Effect.orDie),
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: "keeps the previous object when a body fails",
|
|
113
|
+
run: Effect.gen(function* () {
|
|
114
|
+
yield* put(stored, ["previous"]);
|
|
115
|
+
const failing = Stream.concat(Stream.make(text("partial")), Stream.fail("body failed"));
|
|
116
|
+
const bucket = yield* ContractBucket;
|
|
117
|
+
const result = yield* Effect.result(bucket.put({ key: stored, contentType: "text/plain", body: failing }));
|
|
118
|
+
yield* expectEqual("error of a put whose body failed", "body failed", Result.isFailure(result) ? result.failure : "success");
|
|
119
|
+
yield* expectHead(stored, { size: ByteSize.bytes(8), contentType: "text/plain" });
|
|
120
|
+
yield* expectBody(stored, "previous");
|
|
121
|
+
}).pipe(Effect.orDie),
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
//# sourceMappingURL=AssetBucketContract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetBucketContract.js","sourceRoot":"","sources":["../../src/testing/AssetBucketContract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { HttpClient } from "effect/http";
|
|
3
|
+
import * as AssetSigning from "../AssetSigning.ts";
|
|
4
|
+
import { ContractBucket } from "./AssetBucketContract.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Checks a `Signing` implementation and the storage it signs for, over HTTP:
|
|
7
|
+
* signed requests succeed, and requests that differ from what was signed are
|
|
8
|
+
* refused without changing what is stored, and a signed upload writes once. Provide the `ContractBucket`, its
|
|
9
|
+
* `Signing` and an `HttpClient` that can reach the signed URLs. Expiry is not
|
|
10
|
+
* checked: it depends on the storage's clock. Cases delete the keys they
|
|
11
|
+
* use under `contract/` first, so storage may keep objects between cases.
|
|
12
|
+
*/
|
|
13
|
+
export interface Case {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly run: Effect.Effect<void, never, ContractBucket | AssetSigning.SigningOf<ContractBucket> | HttpClient.HttpClient>;
|
|
16
|
+
}
|
|
17
|
+
export declare const cases: ReadonlyArray<Case>;
|
|
18
|
+
//# sourceMappingURL=AssetSigningContract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetSigningContract.d.ts","sourceRoot":"","sources":["../../src/testing/AssetSigningContract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,EAAU,MAAM,QAAQ,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CACzB,IAAI,EACJ,KAAK,EACL,cAAc,GAAG,YAAY,CAAC,SAAS,CAAC,cAAc,CAAC,GAAG,UAAU,CAAC,UAAU,CAChF,CAAC;CACH;AA0ED,eAAO,MAAM,KAAK,EAAE,aAAa,CAAC,IAAI,CA8JrC,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { ByteSize, Duration, Effect, Option } from "effect";
|
|
2
|
+
import { HttpClient, HttpClientRequest } from "effect/http";
|
|
3
|
+
import * as AssetSigning from "../AssetSigning.js";
|
|
4
|
+
import { ContractBucket } from "./AssetBucketContract.js";
|
|
5
|
+
const signing = AssetSigning.of(ContractBucket);
|
|
6
|
+
const key = "contract/signed.png";
|
|
7
|
+
const expiresIn = Duration.minutes(5);
|
|
8
|
+
const png = new Uint8Array([0x89, 0x50, 0x4e, 0x47]);
|
|
9
|
+
// Not `no-cache`, which clients add to conditional requests themselves.
|
|
10
|
+
const cacheControl = "public, max-age=60";
|
|
11
|
+
const violated = (message) => Effect.die(new Error(`AssetSigning contract violated: ${message}`));
|
|
12
|
+
const ensure = (holds, message) => (holds ? Effect.void : violated(message));
|
|
13
|
+
const ok = (status) => status >= 200 && status < 300;
|
|
14
|
+
const signPut = (contentType = "image/png", contentLength = png.length) => Effect.flatMap(signing, (signer) => signer.signPut({
|
|
15
|
+
key,
|
|
16
|
+
contentType,
|
|
17
|
+
contentLength: ByteSize.bytes(contentLength),
|
|
18
|
+
cacheControl,
|
|
19
|
+
expiresIn,
|
|
20
|
+
}));
|
|
21
|
+
/** Sends a signed request as a client would, with its headers and a body. */
|
|
22
|
+
const send = (signed, options = {}) => HttpClient.execute(HttpClientRequest.make(signed.method)(options.url ?? signed.url).pipe(HttpClientRequest.setHeaders({ ...signed.headers, ...options.headers }), (request) => options.body === undefined
|
|
23
|
+
? request
|
|
24
|
+
: HttpClientRequest.bodyUint8Array(request, options.body, options.headers?.["content-type"] ?? signed.headers["content-type"])));
|
|
25
|
+
// The value of the URL's signature parameter, such as S3's `X-Amz-Signature`.
|
|
26
|
+
const signatureOf = (url) => [...new URL(url, "http://localhost").searchParams].find(([name]) => /signature$/iu.test(name))?.[1] ?? "";
|
|
27
|
+
// Cases start without the objects they check for.
|
|
28
|
+
const clear = Effect.flatMap(ContractBucket, (bucket) => Effect.andThen(bucket.delete(key), bucket.delete("contract/other.png")));
|
|
29
|
+
const stored = Effect.flatMap(ContractBucket, (bucket) => bucket.head(key));
|
|
30
|
+
const expectRefused = (label, response) => ok(response.status)
|
|
31
|
+
? violated(`${label} was accepted with ${response.status}`)
|
|
32
|
+
: Effect.flatMap(stored, (info) => Option.isSome(info) ? violated(`${label} stored an object`) : Effect.void);
|
|
33
|
+
export const cases = [
|
|
34
|
+
{
|
|
35
|
+
name: "stores a signed upload and serves it to a signed download",
|
|
36
|
+
run: Effect.gen(function* () {
|
|
37
|
+
yield* clear;
|
|
38
|
+
const put = yield* signPut();
|
|
39
|
+
const uploaded = yield* send(put, { body: png });
|
|
40
|
+
yield* ensure(ok(uploaded.status), `a signed upload failed with ${uploaded.status}`);
|
|
41
|
+
const info = yield* stored;
|
|
42
|
+
yield* ensure(Option.isSome(info) &&
|
|
43
|
+
info.value.contentType === "image/png" &&
|
|
44
|
+
info.value.cacheControl === cacheControl, "a signed upload was not stored with its content type and cache control");
|
|
45
|
+
const get = yield* Effect.flatMap(signing, (signer) => signer.signGet({ key, expiresIn }));
|
|
46
|
+
const downloaded = yield* send(get);
|
|
47
|
+
const body = new Uint8Array(yield* downloaded.arrayBuffer);
|
|
48
|
+
yield* ensure(downloaded.status === 200 && body.join() === png.join(), "a signed download did not return the upload");
|
|
49
|
+
}).pipe(Effect.orDie),
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "signs uploads with no headers but `uploadHeaders`, which CORS rules allow",
|
|
53
|
+
run: Effect.gen(function* () {
|
|
54
|
+
const put = yield* signPut();
|
|
55
|
+
const allowed = new Set(AssetSigning.uploadHeaders);
|
|
56
|
+
const others = Object.keys(put.headers).filter((name) => !allowed.has(name));
|
|
57
|
+
yield* ensure(others.length === 0, `a signed upload needs other headers: ${others.join(", ")}`);
|
|
58
|
+
}).pipe(Effect.orDie),
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: "refuses an upload of another content type than signed",
|
|
62
|
+
run: Effect.gen(function* () {
|
|
63
|
+
yield* clear;
|
|
64
|
+
const put = yield* signPut("image/png");
|
|
65
|
+
yield* expectRefused("an upload as text/html", yield* send(put, { body: png, headers: { "content-type": "text/html" } }));
|
|
66
|
+
}).pipe(Effect.orDie),
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "refuses an upload with another cache control than signed",
|
|
70
|
+
run: Effect.gen(function* () {
|
|
71
|
+
yield* clear;
|
|
72
|
+
const put = yield* signPut();
|
|
73
|
+
yield* expectRefused("an upload cached for a year", yield* send(put, {
|
|
74
|
+
body: png,
|
|
75
|
+
headers: { "cache-control": "public, max-age=31536000, immutable" },
|
|
76
|
+
}));
|
|
77
|
+
}).pipe(Effect.orDie),
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "refuses an upload of another length than signed",
|
|
81
|
+
run: Effect.gen(function* () {
|
|
82
|
+
yield* clear;
|
|
83
|
+
const put = yield* signPut("image/png", png.length);
|
|
84
|
+
yield* expectRefused("a longer upload", yield* send(put, { body: new Uint8Array([...png, 0]) }));
|
|
85
|
+
yield* expectRefused("a shorter upload", yield* send(put, { body: png.slice(1) }));
|
|
86
|
+
}).pipe(Effect.orDie),
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "refuses a signed URL used for another key or with its signature changed",
|
|
90
|
+
run: Effect.gen(function* () {
|
|
91
|
+
yield* clear;
|
|
92
|
+
const put = yield* signPut();
|
|
93
|
+
const signature = signatureOf(put.url);
|
|
94
|
+
yield* ensure(signature !== "", "a signed URL has no signature parameter");
|
|
95
|
+
const flipped = `${signature.slice(0, -1)}${signature.endsWith("0") ? "1" : "0"}`;
|
|
96
|
+
yield* expectRefused("an upload to another key", yield* send(put, { body: png, url: put.url.replace("signed.png", "other.png") }));
|
|
97
|
+
yield* expectRefused("an upload with a changed signature", yield* send(put, { body: png, url: put.url.replace(signature, flipped) }));
|
|
98
|
+
const other = yield* Effect.flatMap(ContractBucket, (bucket) => bucket.head("contract/other.png"));
|
|
99
|
+
yield* ensure(Option.isNone(other), "an upload to another key was stored");
|
|
100
|
+
}).pipe(Effect.orDie),
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: "writes a signed upload once, however its URL is replayed",
|
|
104
|
+
run: Effect.gen(function* () {
|
|
105
|
+
yield* clear;
|
|
106
|
+
const put = yield* signPut();
|
|
107
|
+
yield* send(put, { body: png });
|
|
108
|
+
// Same length and type, so only the write-once condition stops it.
|
|
109
|
+
const other = png.map((byte) => 255 - byte);
|
|
110
|
+
const { "if-none-match": _, ...unconditional } = put.headers;
|
|
111
|
+
const replays = [
|
|
112
|
+
yield* send(put, { body: other }),
|
|
113
|
+
yield* send({ ...put, headers: unconditional }, { body: other }),
|
|
114
|
+
];
|
|
115
|
+
yield* ensure(replays.every((response) => !ok(response.status)), `a replayed upload was accepted with ${replays.map((response) => response.status).join(", ")}`);
|
|
116
|
+
const get = yield* Effect.flatMap(signing, (signer) => signer.signGet({ key, expiresIn }));
|
|
117
|
+
const body = new Uint8Array(yield* (yield* send(get)).arrayBuffer);
|
|
118
|
+
yield* ensure(body.join() === png.join(), "a replayed upload replaced the object");
|
|
119
|
+
}).pipe(Effect.orDie),
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "refuses a signed upload URL used to download",
|
|
123
|
+
run: Effect.gen(function* () {
|
|
124
|
+
yield* clear;
|
|
125
|
+
const put = yield* signPut();
|
|
126
|
+
yield* send(put, { body: png });
|
|
127
|
+
const downloaded = yield* send({ ...put, method: "GET" });
|
|
128
|
+
yield* ensure(!ok(downloaded.status), "an upload URL served a download");
|
|
129
|
+
}).pipe(Effect.orDie),
|
|
130
|
+
},
|
|
131
|
+
];
|
|
132
|
+
//# sourceMappingURL=AssetSigningContract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AssetSigningContract.js","sourceRoot":"","sources":["../../src/testing/AssetSigningContract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,mBAAmB,MAAM,0BAA0B,CAAC;AAEhE,OAAO,KAAK,oBAAoB,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,mBAAmB,MAAM,0BAA0B,CAAC;AAEhE,OAAO,KAAK,oBAAoB,MAAM,2BAA2B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,106 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kutur-kit/assets",
|
|
3
|
-
"version": "0.0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "Typed asset definitions and swappable object storage for Effect.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/kutur-labs/kit.git",
|
|
9
|
+
"directory": "packages/assets"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"src",
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"type": "module",
|
|
16
|
+
"sideEffects": false,
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./Asset": {
|
|
23
|
+
"types": "./dist/Asset.d.ts",
|
|
24
|
+
"default": "./dist/Asset.js"
|
|
25
|
+
},
|
|
26
|
+
"./AssetBucket": {
|
|
27
|
+
"types": "./dist/AssetBucket.d.ts",
|
|
28
|
+
"default": "./dist/AssetBucket.js"
|
|
29
|
+
},
|
|
30
|
+
"./AssetDelivery": {
|
|
31
|
+
"types": "./dist/AssetDelivery.d.ts",
|
|
32
|
+
"default": "./dist/AssetDelivery.js"
|
|
33
|
+
},
|
|
34
|
+
"./AssetSigning": {
|
|
35
|
+
"types": "./dist/AssetSigning.d.ts",
|
|
36
|
+
"default": "./dist/AssetSigning.js"
|
|
37
|
+
},
|
|
38
|
+
"./alchemy/r2": {
|
|
39
|
+
"types": "./dist/alchemy/r2.d.ts",
|
|
40
|
+
"default": "./dist/alchemy/r2.js"
|
|
41
|
+
},
|
|
42
|
+
"./delivery/local": {
|
|
43
|
+
"types": "./dist/delivery/local.d.ts",
|
|
44
|
+
"default": "./dist/delivery/local.js"
|
|
45
|
+
},
|
|
46
|
+
"./filesystem": {
|
|
47
|
+
"types": "./dist/filesystem.d.ts",
|
|
48
|
+
"default": "./dist/filesystem.js"
|
|
49
|
+
},
|
|
50
|
+
"./memory": {
|
|
51
|
+
"types": "./dist/memory.d.ts",
|
|
52
|
+
"default": "./dist/memory.js"
|
|
53
|
+
},
|
|
54
|
+
"./s3": {
|
|
55
|
+
"types": "./dist/s3.d.ts",
|
|
56
|
+
"default": "./dist/s3.js"
|
|
57
|
+
},
|
|
58
|
+
"./signing/local": {
|
|
59
|
+
"types": "./dist/signing/local.d.ts",
|
|
60
|
+
"default": "./dist/signing/local.js"
|
|
61
|
+
},
|
|
62
|
+
"./testing": {
|
|
63
|
+
"types": "./dist/testing/index.d.ts",
|
|
64
|
+
"default": "./dist/testing/index.js"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"publishConfig": {
|
|
68
|
+
"access": "public"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@distilled.cloud/aws": "1.0.0-rc.15",
|
|
72
|
+
"@effect/platform-node": "4.0.5",
|
|
73
|
+
"@effect/tsgo": "0.53.3",
|
|
74
|
+
"@effect/vitest": "4.0.5",
|
|
75
|
+
"@kutur-kit/testcontainers": "0.0.0",
|
|
76
|
+
"@kutur-kit/tsconfig": "0.1.0-alpha.0",
|
|
77
|
+
"@stryker-mutator/core": "10.0.0",
|
|
78
|
+
"@stryker-mutator/vitest-runner": "10.0.0",
|
|
79
|
+
"@types/node": "24.19.2",
|
|
80
|
+
"alchemy": "2.0.0-beta.83",
|
|
81
|
+
"effect": "4.0.5",
|
|
82
|
+
"publint": "0.3.25",
|
|
83
|
+
"typescript": "7.0.2",
|
|
84
|
+
"vitest": "5.0.5"
|
|
85
|
+
},
|
|
86
|
+
"peerDependencies": {
|
|
87
|
+
"@distilled.cloud/aws": "1.0.0-rc.15",
|
|
88
|
+
"alchemy": "2.0.0-beta.83",
|
|
89
|
+
"effect": "^4.0.5"
|
|
90
|
+
},
|
|
91
|
+
"peerDependenciesMeta": {
|
|
92
|
+
"@distilled.cloud/aws": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"alchemy": {
|
|
96
|
+
"optional": true
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"scripts": {
|
|
100
|
+
"build": "node --input-type=module -e 'import { rmSync } from \"node:fs\"; rmSync(\"dist\", { recursive: true, force: true });' && tsc -p tsconfig.build.json",
|
|
101
|
+
"lint:package": "publint --pack pnpm --strict",
|
|
102
|
+
"test": "vitest run",
|
|
103
|
+
"test:mutation": "stryker run",
|
|
104
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
105
|
+
}
|
|
6
106
|
}
|