@streetjs/storage 1.0.0 → 1.0.2
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/dist/drivers/local.d.ts +8 -0
- package/dist/drivers/local.d.ts.map +1 -1
- package/dist/drivers/local.js +18 -3
- package/dist/drivers/local.js.map +1 -1
- package/dist/tests/contract.d.ts +19 -0
- package/dist/tests/contract.d.ts.map +1 -1
- package/dist/tests/contract.js +28 -0
- package/dist/tests/contract.js.map +1 -1
- package/package.json +10 -6
- package/dist/tests/access.test.d.ts +0 -2
- package/dist/tests/access.test.d.ts.map +0 -1
- package/dist/tests/access.test.js +0 -270
- package/dist/tests/access.test.js.map +0 -1
- package/dist/tests/azure-driver.test.d.ts +0 -2
- package/dist/tests/azure-driver.test.d.ts.map +0 -1
- package/dist/tests/azure-driver.test.js +0 -183
- package/dist/tests/azure-driver.test.js.map +0 -1
- package/dist/tests/backblaze-driver.test.d.ts +0 -2
- package/dist/tests/backblaze-driver.test.d.ts.map +0 -1
- package/dist/tests/backblaze-driver.test.js +0 -185
- package/dist/tests/backblaze-driver.test.js.map +0 -1
- package/dist/tests/bridge-degradation.test.d.ts +0 -2
- package/dist/tests/bridge-degradation.test.d.ts.map +0 -1
- package/dist/tests/bridge-degradation.test.js +0 -138
- package/dist/tests/bridge-degradation.test.js.map +0 -1
- package/dist/tests/cli.test.d.ts +0 -2
- package/dist/tests/cli.test.d.ts.map +0 -1
- package/dist/tests/cli.test.js +0 -127
- package/dist/tests/cli.test.js.map +0 -1
- package/dist/tests/contract.test.d.ts +0 -2
- package/dist/tests/contract.test.d.ts.map +0 -1
- package/dist/tests/contract.test.js +0 -110
- package/dist/tests/contract.test.js.map +0 -1
- package/dist/tests/directory.test.d.ts +0 -2
- package/dist/tests/directory.test.d.ts.map +0 -1
- package/dist/tests/directory.test.js +0 -125
- package/dist/tests/directory.test.js.map +0 -1
- package/dist/tests/errors.test.d.ts +0 -2
- package/dist/tests/errors.test.d.ts.map +0 -1
- package/dist/tests/errors.test.js +0 -93
- package/dist/tests/errors.test.js.map +0 -1
- package/dist/tests/events-bridge.test.d.ts +0 -2
- package/dist/tests/events-bridge.test.d.ts.map +0 -1
- package/dist/tests/events-bridge.test.js +0 -228
- package/dist/tests/events-bridge.test.js.map +0 -1
- package/dist/tests/example-smoke.test.d.ts +0 -2
- package/dist/tests/example-smoke.test.d.ts.map +0 -1
- package/dist/tests/example-smoke.test.js +0 -34
- package/dist/tests/example-smoke.test.js.map +0 -1
- package/dist/tests/gcs-driver.test.d.ts +0 -2
- package/dist/tests/gcs-driver.test.d.ts.map +0 -1
- package/dist/tests/gcs-driver.test.js +0 -197
- package/dist/tests/gcs-driver.test.js.map +0 -1
- package/dist/tests/image.test.d.ts +0 -2
- package/dist/tests/image.test.d.ts.map +0 -1
- package/dist/tests/image.test.js +0 -102
- package/dist/tests/image.test.js.map +0 -1
- package/dist/tests/lifecycle.test.d.ts +0 -2
- package/dist/tests/lifecycle.test.d.ts.map +0 -1
- package/dist/tests/lifecycle.test.js +0 -171
- package/dist/tests/lifecycle.test.js.map +0 -1
- package/dist/tests/local-driver.test.d.ts +0 -2
- package/dist/tests/local-driver.test.d.ts.map +0 -1
- package/dist/tests/local-driver.test.js +0 -153
- package/dist/tests/local-driver.test.js.map +0 -1
- package/dist/tests/local-streaming.test.d.ts +0 -2
- package/dist/tests/local-streaming.test.d.ts.map +0 -1
- package/dist/tests/local-streaming.test.js +0 -121
- package/dist/tests/local-streaming.test.js.map +0 -1
- package/dist/tests/memory-driver.test.d.ts +0 -2
- package/dist/tests/memory-driver.test.d.ts.map +0 -1
- package/dist/tests/memory-driver.test.js +0 -180
- package/dist/tests/memory-driver.test.js.map +0 -1
- package/dist/tests/memory-streaming.test.d.ts +0 -2
- package/dist/tests/memory-streaming.test.d.ts.map +0 -1
- package/dist/tests/memory-streaming.test.js +0 -92
- package/dist/tests/memory-streaming.test.js.map +0 -1
- package/dist/tests/minio-driver.test.d.ts +0 -2
- package/dist/tests/minio-driver.test.d.ts.map +0 -1
- package/dist/tests/minio-driver.test.js +0 -146
- package/dist/tests/minio-driver.test.js.map +0 -1
- package/dist/tests/non-s3-integration.test.d.ts +0 -2
- package/dist/tests/non-s3-integration.test.d.ts.map +0 -1
- package/dist/tests/non-s3-integration.test.js +0 -201
- package/dist/tests/non-s3-integration.test.js.map +0 -1
- package/dist/tests/observability.registration.test.d.ts +0 -2
- package/dist/tests/observability.registration.test.d.ts.map +0 -1
- package/dist/tests/observability.registration.test.js +0 -103
- package/dist/tests/observability.registration.test.js.map +0 -1
- package/dist/tests/observability.test.d.ts +0 -2
- package/dist/tests/observability.test.d.ts.map +0 -1
- package/dist/tests/observability.test.js +0 -240
- package/dist/tests/observability.test.js.map +0 -1
- package/dist/tests/plugin.test.d.ts +0 -2
- package/dist/tests/plugin.test.d.ts.map +0 -1
- package/dist/tests/plugin.test.js +0 -112
- package/dist/tests/plugin.test.js.map +0 -1
- package/dist/tests/prop-concurrent.test.d.ts +0 -2
- package/dist/tests/prop-concurrent.test.d.ts.map +0 -1
- package/dist/tests/prop-concurrent.test.js +0 -59
- package/dist/tests/prop-concurrent.test.js.map +0 -1
- package/dist/tests/prop-copy.test.d.ts +0 -2
- package/dist/tests/prop-copy.test.d.ts.map +0 -1
- package/dist/tests/prop-copy.test.js +0 -63
- package/dist/tests/prop-copy.test.js.map +0 -1
- package/dist/tests/prop-delete.test.d.ts +0 -2
- package/dist/tests/prop-delete.test.d.ts.map +0 -1
- package/dist/tests/prop-delete.test.js +0 -35
- package/dist/tests/prop-delete.test.js.map +0 -1
- package/dist/tests/prop-directory.test.d.ts +0 -2
- package/dist/tests/prop-directory.test.d.ts.map +0 -1
- package/dist/tests/prop-directory.test.js +0 -118
- package/dist/tests/prop-directory.test.js.map +0 -1
- package/dist/tests/prop-driver-conformance.test.d.ts +0 -2
- package/dist/tests/prop-driver-conformance.test.d.ts.map +0 -1
- package/dist/tests/prop-driver-conformance.test.js +0 -110
- package/dist/tests/prop-driver-conformance.test.js.map +0 -1
- package/dist/tests/prop-driver-equivalence.test.d.ts +0 -2
- package/dist/tests/prop-driver-equivalence.test.d.ts.map +0 -1
- package/dist/tests/prop-driver-equivalence.test.js +0 -163
- package/dist/tests/prop-driver-equivalence.test.js.map +0 -1
- package/dist/tests/prop-lifecycle.test.d.ts +0 -2
- package/dist/tests/prop-lifecycle.test.d.ts.map +0 -1
- package/dist/tests/prop-lifecycle.test.js +0 -83
- package/dist/tests/prop-lifecycle.test.js.map +0 -1
- package/dist/tests/prop-list.test.d.ts +0 -2
- package/dist/tests/prop-list.test.d.ts.map +0 -1
- package/dist/tests/prop-list.test.js +0 -53
- package/dist/tests/prop-list.test.js.map +0 -1
- package/dist/tests/prop-metadata.test.d.ts +0 -2
- package/dist/tests/prop-metadata.test.d.ts.map +0 -1
- package/dist/tests/prop-metadata.test.js +0 -87
- package/dist/tests/prop-metadata.test.js.map +0 -1
- package/dist/tests/prop-move.test.d.ts +0 -2
- package/dist/tests/prop-move.test.d.ts.map +0 -1
- package/dist/tests/prop-move.test.js +0 -67
- package/dist/tests/prop-move.test.js.map +0 -1
- package/dist/tests/prop-multipart-abort.test.d.ts +0 -2
- package/dist/tests/prop-multipart-abort.test.d.ts.map +0 -1
- package/dist/tests/prop-multipart-abort.test.js +0 -48
- package/dist/tests/prop-multipart-abort.test.js.map +0 -1
- package/dist/tests/prop-multipart.test.d.ts +0 -2
- package/dist/tests/prop-multipart.test.d.ts.map +0 -1
- package/dist/tests/prop-multipart.test.js +0 -65
- package/dist/tests/prop-multipart.test.js.map +0 -1
- package/dist/tests/prop-resumable.test.d.ts +0 -2
- package/dist/tests/prop-resumable.test.d.ts.map +0 -1
- package/dist/tests/prop-resumable.test.js +0 -78
- package/dist/tests/prop-resumable.test.js.map +0 -1
- package/dist/tests/prop-search.test.d.ts +0 -2
- package/dist/tests/prop-search.test.d.ts.map +0 -1
- package/dist/tests/prop-search.test.js +0 -120
- package/dist/tests/prop-search.test.js.map +0 -1
- package/dist/tests/prop-signed-url.test.d.ts +0 -2
- package/dist/tests/prop-signed-url.test.d.ts.map +0 -1
- package/dist/tests/prop-signed-url.test.js +0 -74
- package/dist/tests/prop-signed-url.test.js.map +0 -1
- package/dist/tests/prop-streaming.test.d.ts +0 -2
- package/dist/tests/prop-streaming.test.d.ts.map +0 -1
- package/dist/tests/prop-streaming.test.js +0 -34
- package/dist/tests/prop-streaming.test.js.map +0 -1
- package/dist/tests/prop-upload-download.test.d.ts +0 -2
- package/dist/tests/prop-upload-download.test.d.ts.map +0 -1
- package/dist/tests/prop-upload-download.test.js +0 -30
- package/dist/tests/prop-upload-download.test.js.map +0 -1
- package/dist/tests/prop-validation.test.d.ts +0 -2
- package/dist/tests/prop-validation.test.d.ts.map +0 -1
- package/dist/tests/prop-validation.test.js +0 -50
- package/dist/tests/prop-validation.test.js.map +0 -1
- package/dist/tests/prop-versioning.test.d.ts +0 -2
- package/dist/tests/prop-versioning.test.d.ts.map +0 -1
- package/dist/tests/prop-versioning.test.js +0 -74
- package/dist/tests/prop-versioning.test.js.map +0 -1
- package/dist/tests/queue-bridge.test.d.ts +0 -2
- package/dist/tests/queue-bridge.test.d.ts.map +0 -1
- package/dist/tests/queue-bridge.test.js +0 -111
- package/dist/tests/queue-bridge.test.js.map +0 -1
- package/dist/tests/r2-driver.test.d.ts +0 -2
- package/dist/tests/r2-driver.test.d.ts.map +0 -1
- package/dist/tests/r2-driver.test.js +0 -143
- package/dist/tests/r2-driver.test.js.map +0 -1
- package/dist/tests/realtime-bridge.test.d.ts +0 -2
- package/dist/tests/realtime-bridge.test.d.ts.map +0 -1
- package/dist/tests/realtime-bridge.test.js +0 -106
- package/dist/tests/realtime-bridge.test.js.map +0 -1
- package/dist/tests/resumable.test.d.ts +0 -2
- package/dist/tests/resumable.test.d.ts.map +0 -1
- package/dist/tests/resumable.test.js +0 -104
- package/dist/tests/resumable.test.js.map +0 -1
- package/dist/tests/s3-base.test.d.ts +0 -2
- package/dist/tests/s3-base.test.d.ts.map +0 -1
- package/dist/tests/s3-base.test.js +0 -289
- package/dist/tests/s3-base.test.js.map +0 -1
- package/dist/tests/s3-integration.test.d.ts +0 -2
- package/dist/tests/s3-integration.test.d.ts.map +0 -1
- package/dist/tests/s3-integration.test.js +0 -270
- package/dist/tests/s3-integration.test.js.map +0 -1
- package/dist/tests/s3.test.d.ts +0 -2
- package/dist/tests/s3.test.d.ts.map +0 -1
- package/dist/tests/s3.test.js +0 -203
- package/dist/tests/s3.test.js.map +0 -1
- package/dist/tests/scaffold.test.d.ts +0 -2
- package/dist/tests/scaffold.test.d.ts.map +0 -1
- package/dist/tests/scaffold.test.js +0 -13
- package/dist/tests/scaffold.test.js.map +0 -1
- package/dist/tests/search.test.d.ts +0 -2
- package/dist/tests/search.test.d.ts.map +0 -1
- package/dist/tests/search.test.js +0 -106
- package/dist/tests/search.test.js.map +0 -1
- package/dist/tests/supabase-driver.test.d.ts +0 -2
- package/dist/tests/supabase-driver.test.d.ts.map +0 -1
- package/dist/tests/supabase-driver.test.js +0 -196
- package/dist/tests/supabase-driver.test.js.map +0 -1
- package/dist/tests/testing-utilities.test.d.ts +0 -2
- package/dist/tests/testing-utilities.test.d.ts.map +0 -1
- package/dist/tests/testing-utilities.test.js +0 -138
- package/dist/tests/testing-utilities.test.js.map +0 -1
- package/dist/tests/validation.test.d.ts +0 -2
- package/dist/tests/validation.test.d.ts.map +0 -1
- package/dist/tests/validation.test.js +0 -135
- package/dist/tests/validation.test.js.map +0 -1
- package/dist/tests/versioning.test.d.ts +0 -2
- package/dist/tests/versioning.test.d.ts.map +0 -1
- package/dist/tests/versioning.test.js +0 -128
- package/dist/tests/versioning.test.js.map +0 -1
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
// Property-based test: Memory and Local drivers are observationally equivalent.
|
|
2
|
-
//
|
|
3
|
-
// Property 18 (Memory and Local drivers are observationally equivalent): for an
|
|
4
|
-
// arbitrary sequence of object operations (put/get/exists/delete/list/stat)
|
|
5
|
-
// applied identically to a `MemoryStorageDriver` and a `LocalStorageDriver`
|
|
6
|
-
// (both constructed with the SAME injected fixed clock, the Local driver bound
|
|
7
|
-
// to a fresh temp dir), the observable results are equivalent at every step —
|
|
8
|
-
// object existence, content bytes, and returned metadata (contentType, size,
|
|
9
|
-
// checksum, etag, accessLevel, owner, tenant, custom). The two zero-dependency
|
|
10
|
-
// drivers are interchangeable, so the same generated op sequence must produce
|
|
11
|
-
// the same observations on both.
|
|
12
|
-
//
|
|
13
|
-
// Uses the Node.js built-in test runner (node:test) with fast-check for input
|
|
14
|
-
// generation, executed via `node --test dist/tests/*.test.js`. fast-check is
|
|
15
|
-
// configured with { numRuns: 100 } per the design's property-testing contract.
|
|
16
|
-
//
|
|
17
|
-
// Feature: unified-storage-framework, Property 18: Memory and Local drivers are observationally equivalent
|
|
18
|
-
//
|
|
19
|
-
// Validates: Requirements 2.2, 26.6
|
|
20
|
-
import test from "node:test";
|
|
21
|
-
import assert from "node:assert/strict";
|
|
22
|
-
import * as fs from "node:fs/promises";
|
|
23
|
-
import * as os from "node:os";
|
|
24
|
-
import * as path from "node:path";
|
|
25
|
-
import fc from "fast-check";
|
|
26
|
-
import { MemoryStorageDriver } from "../drivers/memory.js";
|
|
27
|
-
import { LocalStorageDriver } from "../drivers/local.js";
|
|
28
|
-
/** A fixed clock so both drivers stamp identical timestamps for the same op. */
|
|
29
|
-
const fixedClock = () => 1_700_000_000_000;
|
|
30
|
-
/** The valid AccessLevel values (Requirement 11.1). */
|
|
31
|
-
const ACCESS_LEVELS = [
|
|
32
|
-
"public",
|
|
33
|
-
"private",
|
|
34
|
-
"signed",
|
|
35
|
-
"authenticated",
|
|
36
|
-
"role-based",
|
|
37
|
-
"tenant-aware",
|
|
38
|
-
];
|
|
39
|
-
/**
|
|
40
|
-
* A fixed pool of filesystem-safe keys. No key is a directory-component prefix
|
|
41
|
-
* of another (e.g. there is never both a file `docs` and a file `docs/x`), so
|
|
42
|
-
* the Local driver's on-disk layout can represent any subset the op sequence
|
|
43
|
-
* touches without a file/directory collision — keeping the two drivers on equal
|
|
44
|
-
* footing for the observable behavior under test.
|
|
45
|
-
*/
|
|
46
|
-
const KEYS = [
|
|
47
|
-
"alpha.txt",
|
|
48
|
-
"beta.txt",
|
|
49
|
-
"docs/one.txt",
|
|
50
|
-
"docs/two.txt",
|
|
51
|
-
"docs/sub/three.txt",
|
|
52
|
-
"images/a.png",
|
|
53
|
-
"images/b.png",
|
|
54
|
-
];
|
|
55
|
-
/** Prefixes exercised by `list`, including the empty (match-all) prefix. */
|
|
56
|
-
const PREFIXES = ["", "docs/", "docs/sub/", "images/", "alpha.txt", "doc", "images/a.png"];
|
|
57
|
-
const keyArb = fc.constantFrom(...KEYS);
|
|
58
|
-
const contentArb = fc.uint8Array({ minLength: 0, maxLength: 64 });
|
|
59
|
-
/** Custom metadata with JSON-round-trippable values so it can compare exactly. */
|
|
60
|
-
const customArb = fc.dictionary(fc.string({ maxLength: 12 }), fc.oneof(fc.string(), fc.integer(), fc.boolean()), { maxKeys: 4 });
|
|
61
|
-
/** Arbitrary write-time metadata; every field optional to cover the defaults. */
|
|
62
|
-
const writeMetadataArb = fc.record({
|
|
63
|
-
contentType: fc.string({ minLength: 1, maxLength: 30 }),
|
|
64
|
-
owner: fc.string({ minLength: 1, maxLength: 30 }),
|
|
65
|
-
tenant: fc.string({ minLength: 1, maxLength: 30 }),
|
|
66
|
-
accessLevel: fc.constantFrom(...ACCESS_LEVELS),
|
|
67
|
-
custom: customArb,
|
|
68
|
-
}, { requiredKeys: [] });
|
|
69
|
-
/** Optional list options; both drivers implement these identically. */
|
|
70
|
-
const listOptionsArb = fc.record({
|
|
71
|
-
limit: fc.integer({ min: 1, max: 5 }),
|
|
72
|
-
cursor: fc.constantFrom(...KEYS),
|
|
73
|
-
delimiter: fc.boolean(),
|
|
74
|
-
}, { requiredKeys: [] });
|
|
75
|
-
/** A single object operation applied identically to both drivers. */
|
|
76
|
-
const operationArb = fc.oneof(fc.record({ type: fc.constant("put"), key: keyArb, bytes: contentArb, meta: writeMetadataArb }), fc.record({ type: fc.constant("get"), key: keyArb }), fc.record({ type: fc.constant("exists"), key: keyArb }), fc.record({ type: fc.constant("delete"), key: keyArb }), fc.record({ type: fc.constant("stat"), key: keyArb }), fc.record({ type: fc.constant("list"), prefix: fc.constantFrom(...PREFIXES), options: listOptionsArb }));
|
|
77
|
-
const sequenceArb = fc.array(operationArb, { minLength: 1, maxLength: 30 });
|
|
78
|
-
/**
|
|
79
|
-
* Project a metadata record onto the observable field set the property compares.
|
|
80
|
-
* `owner`/`tenant` collapse absent-vs-undefined to `null` so a driver that
|
|
81
|
-
* persists metadata through JSON (which drops `undefined` keys) compares equal
|
|
82
|
-
* to one that keeps the key present with an `undefined` value.
|
|
83
|
-
*/
|
|
84
|
-
function projectMetadata(meta) {
|
|
85
|
-
if (meta === null || meta === undefined) {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
key: meta.key,
|
|
90
|
-
size: meta.size,
|
|
91
|
-
contentType: meta.contentType,
|
|
92
|
-
checksum: meta.checksum,
|
|
93
|
-
etag: meta.etag,
|
|
94
|
-
accessLevel: meta.accessLevel,
|
|
95
|
-
owner: meta.owner ?? null,
|
|
96
|
-
tenant: meta.tenant ?? null,
|
|
97
|
-
// Spread into a plain object so a null-prototype custom map (as produced by
|
|
98
|
-
// fast-check's dictionary generator and kept verbatim by the in-memory
|
|
99
|
-
// driver) compares equal by content to the plain object the Local driver
|
|
100
|
-
// reconstructs from its JSON sidecar. The observable custom fields are the
|
|
101
|
-
// key/value pairs, not the object's internal prototype tag.
|
|
102
|
-
custom: { ...(meta.custom ?? {}) },
|
|
103
|
-
createdAt: meta.createdAt,
|
|
104
|
-
updatedAt: meta.updatedAt,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
/** Apply one operation to a driver and return its canonical observation. */
|
|
108
|
-
async function applyOp(driver, op) {
|
|
109
|
-
switch (op.type) {
|
|
110
|
-
case "put": {
|
|
111
|
-
const meta = await driver.put(op.key, op.bytes, op.meta);
|
|
112
|
-
return { type: "put", meta: projectMetadata(meta) };
|
|
113
|
-
}
|
|
114
|
-
case "get": {
|
|
115
|
-
const result = await driver.get(op.key);
|
|
116
|
-
return {
|
|
117
|
-
type: "get",
|
|
118
|
-
found: result.found,
|
|
119
|
-
bytes: result.found ? Array.from(result.bytes) : null,
|
|
120
|
-
meta: result.found ? projectMetadata(result.metadata) : null,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
case "exists": {
|
|
124
|
-
return { type: "exists", exists: await driver.exists(op.key) };
|
|
125
|
-
}
|
|
126
|
-
case "delete": {
|
|
127
|
-
await driver.delete(op.key);
|
|
128
|
-
return { type: "delete" };
|
|
129
|
-
}
|
|
130
|
-
case "stat": {
|
|
131
|
-
return { type: "stat", meta: projectMetadata(await driver.stat(op.key)) };
|
|
132
|
-
}
|
|
133
|
-
case "list": {
|
|
134
|
-
const items = await driver.list(op.prefix, op.options);
|
|
135
|
-
return {
|
|
136
|
-
type: "list",
|
|
137
|
-
items: items.map((item) => ({ key: item.key, size: item.size, updatedAt: item.updatedAt })),
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
default:
|
|
141
|
-
throw new Error(`unknown op type: ${op.type}`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
test("Feature: unified-storage-framework, Property 18: Memory and Local drivers are observationally equivalent", async () => {
|
|
145
|
-
await fc.assert(fc.asyncProperty(sequenceArb, async (operations) => {
|
|
146
|
-
// Fresh temp dir + fresh drivers per run keep every sequence independent.
|
|
147
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), "streetjs-driver-equiv-"));
|
|
148
|
-
const memory = new MemoryStorageDriver({ clock: fixedClock });
|
|
149
|
-
const local = new LocalStorageDriver({ root, clock: fixedClock });
|
|
150
|
-
try {
|
|
151
|
-
for (let i = 0; i < operations.length; i++) {
|
|
152
|
-
const op = operations[i];
|
|
153
|
-
const memObs = await applyOp(memory, op);
|
|
154
|
-
const localObs = await applyOp(local, op);
|
|
155
|
-
assert.deepEqual(localObs, memObs, `observation diverged at step ${i} for op ${JSON.stringify(op.type)} (key=${"key" in op ? op.key : op.prefix})`);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
finally {
|
|
159
|
-
await fs.rm(root, { recursive: true, force: true });
|
|
160
|
-
}
|
|
161
|
-
}), { numRuns: 100 });
|
|
162
|
-
});
|
|
163
|
-
//# sourceMappingURL=prop-driver-equivalence.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-driver-equivalence.test.js","sourceRoot":"","sources":["../../src/tests/prop-driver-equivalence.test.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,gFAAgF;AAChF,4EAA4E;AAC5E,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,8EAA8E;AAC9E,iCAAiC;AACjC,EAAE;AACF,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,EAAE;AACF,2GAA2G;AAC3G,EAAE;AACF,oCAAoC;AAEpC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAazD,gFAAgF;AAChF,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,iBAAiB,CAAC;AAE3C,uDAAuD;AACvD,MAAM,aAAa,GAA2B;IAC5C,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,eAAe;IACf,YAAY;IACZ,cAAc;CACf,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,IAAI,GAAG;IACX,WAAW;IACX,UAAU;IACV,cAAc;IACd,cAAc;IACd,oBAAoB;IACpB,cAAc;IACd,cAAc;CACf,CAAC;AAEF,4EAA4E;AAC5E,MAAM,QAAQ,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;AAE3F,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;AACxC,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;AAElE,kFAAkF;AAClF,MAAM,SAAS,GAAG,EAAE,CAAC,UAAU,CAC7B,EAAE,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,EAC5B,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,EACjD,EAAE,OAAO,EAAE,CAAC,EAAE,CACf,CAAC;AAEF,iFAAiF;AACjF,MAAM,gBAAgB,GAAG,EAAE,CAAC,MAAM,CAChC;IACE,WAAW,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACvD,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACjD,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAClD,WAAW,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,aAAa,CAAC;IAC9C,MAAM,EAAE,SAAS;CAClB,EACD,EAAE,YAAY,EAAE,EAAE,EAAE,CACrB,CAAC;AAEF,uEAAuE;AACvE,MAAM,cAAc,GAAG,EAAE,CAAC,MAAM,CAC9B;IACE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;IACrC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,EAAE,CAAC,OAAO,EAAE;CACxB,EACD,EAAE,YAAY,EAAE,EAAE,EAAE,CACrB,CAAC;AAEF,qEAAqE;AACrE,MAAM,YAAY,GAAG,EAAE,CAAC,KAAK,CAC3B,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,EAC/F,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EACpD,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EACvD,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EACvD,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EACrD,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,QAAQ,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CACzE,CAAC;AAEjC,MAAM,WAAW,GAAG,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;AAE5E;;;;;GAKG;AACH,SAAS,eAAe,CAAC,IAA8C;IACrE,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO;QACL,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;QACzB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI;QAC3B,4EAA4E;QAC5E,uEAAuE;QACvE,yEAAyE;QACzE,2EAA2E;QAC3E,4DAA4D;QAC5D,MAAM,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE;QAClC,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,KAAK,UAAU,OAAO,CAAC,MAAqB,EAAE,EAAM;IAClD,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;QAChB,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;YACzD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,CAAC;QACD,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;YACxC,OAAO;gBACL,IAAI,EAAE,KAAK;gBACX,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI;gBACrD,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI;aAC7D,CAAC;QACJ,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;QACjE,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;YAC5B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC5B,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC5E,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;YACvD,OAAO;gBACL,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;aAC5F,CAAC;QACJ,CAAC;QACD;YACE,MAAM,IAAI,KAAK,CAAC,oBAAqB,EAAuB,CAAC,IAAI,EAAE,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED,IAAI,CACF,0GAA0G,EAC1G,KAAK,IAAI,EAAE;IACT,MAAM,EAAE,CAAC,MAAM,CACb,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,KAAK,EAAE,UAAyB,EAAE,EAAE;QAChE,0EAA0E;QAC1E,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,wBAAwB,CAAC,CAAC,CAAC;QAChF,MAAM,MAAM,GAAG,IAAI,mBAAmB,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QAC9D,MAAM,KAAK,GAAG,IAAI,kBAAkB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QAElE,IAAI,CAAC;YACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;gBACzB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBACzC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBAE1C,MAAM,CAAC,SAAS,CACd,QAAQ,EACR,MAAM,EACN,gCAAgC,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,GAAG,CAChH,CAAC;YACJ,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC,CAAC,EACF,EAAE,OAAO,EAAE,GAAG,EAAE,CACjB,CAAC;AACJ,CAAC,CACF,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-lifecycle.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-lifecycle.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
// Property-based test for the storage facade's lifecycle engine (task 15.2).
|
|
2
|
-
//
|
|
3
|
-
// Property 14: Lifecycle action applies exactly once. For an arbitrary set of
|
|
4
|
-
// objects (each placed at a controllable age) and a `delete-after-days` rule
|
|
5
|
-
// with an arbitrary day threshold, evaluating the rule via
|
|
6
|
-
// `storage.applyLifecycle(rule)` at a fixed clock instant actions each
|
|
7
|
-
// qualifying object EXACTLY ONCE:
|
|
8
|
-
//
|
|
9
|
-
// - the first evaluation's outcomes are exactly the set of objects whose age
|
|
10
|
-
// meets the threshold (one `deleted` outcome per qualifying object), and
|
|
11
|
-
// - a second evaluation of the same rule at the same clock instant produces
|
|
12
|
-
// no further outcomes, because every actioned object has been removed from
|
|
13
|
-
// the space a subsequent scan enumerates.
|
|
14
|
-
//
|
|
15
|
-
// A controllable clock makes object ages deterministic: each object is written
|
|
16
|
-
// at `now - ageDays` so its age at evaluation time is exactly `ageDays`. Backed
|
|
17
|
-
// by the zero-dependency in-memory provider (no native `lifecycle` capability,
|
|
18
|
-
// so the engine simulates evaluation over the driver primitives). Exercised
|
|
19
|
-
// with fast-check at { numRuns: 100 }; executed via the Node.js built-in test
|
|
20
|
-
// runner (`node --test dist/tests/*.test.js`).
|
|
21
|
-
//
|
|
22
|
-
// Feature: unified-storage-framework, Property 14
|
|
23
|
-
// Validates: Requirements 13.2, 26.6
|
|
24
|
-
import test from "node:test";
|
|
25
|
-
import assert from "node:assert/strict";
|
|
26
|
-
import fc from "fast-check";
|
|
27
|
-
import { createStorage } from "../index.js";
|
|
28
|
-
import { MemoryStorageDriver } from "../drivers/memory.js";
|
|
29
|
-
const DAY = 24 * 60 * 60 * 1000;
|
|
30
|
-
// A fixed evaluation instant, chosen large enough that every object's write
|
|
31
|
-
// time (`NOW - ageDays * DAY`) stays positive for the age ranges used here.
|
|
32
|
-
const NOW = 1_700_000_000_000;
|
|
33
|
-
test("Feature: unified-storage-framework, Property 14 — lifecycle action applies exactly once", { concurrency: false }, async () => {
|
|
34
|
-
await fc.assert(fc.asyncProperty(
|
|
35
|
-
// An arbitrary set of objects with unique, application-visible keys
|
|
36
|
-
// (never a reserved bookkeeping prefix, which age-based rules skip),
|
|
37
|
-
// each with a deterministic age in days and arbitrary byte content.
|
|
38
|
-
fc.uniqueArray(fc.record({
|
|
39
|
-
key: fc
|
|
40
|
-
.string({ minLength: 1 })
|
|
41
|
-
.filter((k) => !k.startsWith(".") && k.trim().length > 0),
|
|
42
|
-
ageDays: fc.integer({ min: 0, max: 60 }),
|
|
43
|
-
content: fc.uint8Array(),
|
|
44
|
-
}), { selector: (o) => o.key, maxLength: 12 }),
|
|
45
|
-
// An arbitrary day threshold for the delete-after-days rule.
|
|
46
|
-
fc.integer({ min: 1, max: 30 }), async (objects, thresholdDays) => {
|
|
47
|
-
// A controllable clock shared by the driver and the facade so both
|
|
48
|
-
// object creation time and lifecycle age are deterministic.
|
|
49
|
-
let clockValue = NOW;
|
|
50
|
-
const clock = () => clockValue;
|
|
51
|
-
const driver = new MemoryStorageDriver({ clock });
|
|
52
|
-
const storage = createStorage({ provider: "memory", driver, clock });
|
|
53
|
-
// Place each object so its age at NOW is exactly `ageDays`.
|
|
54
|
-
for (const { key, ageDays, content } of objects) {
|
|
55
|
-
clockValue = NOW - ageDays * DAY;
|
|
56
|
-
await storage.put(key, content);
|
|
57
|
-
}
|
|
58
|
-
// Evaluate the rule at the fixed instant NOW.
|
|
59
|
-
clockValue = NOW;
|
|
60
|
-
const rule = { type: "delete-after-days", days: thresholdDays };
|
|
61
|
-
// The qualifying set: objects at least `thresholdDays` old.
|
|
62
|
-
const expectedKeys = objects
|
|
63
|
-
.filter((o) => o.ageDays >= thresholdDays)
|
|
64
|
-
.map((o) => o.key)
|
|
65
|
-
.sort();
|
|
66
|
-
const first = await storage.applyLifecycle(rule);
|
|
67
|
-
// Every outcome is a delete, and the actioned keys are exactly the
|
|
68
|
-
// qualifying set — each qualifying object actioned exactly once.
|
|
69
|
-
assert.ok(first.every((o) => o.action === "deleted"));
|
|
70
|
-
assert.deepEqual(first.map((o) => o.key).sort(), expectedKeys);
|
|
71
|
-
// No duplicate outcomes within a single evaluation.
|
|
72
|
-
assert.equal(new Set(first.map((o) => o.key)).size, first.length);
|
|
73
|
-
// A second evaluation at the same instant produces no further
|
|
74
|
-
// outcomes: already-actioned objects are not re-actioned.
|
|
75
|
-
const second = await storage.applyLifecycle(rule);
|
|
76
|
-
assert.deepEqual(second, []);
|
|
77
|
-
// Qualifying objects are gone; non-qualifying objects remain.
|
|
78
|
-
for (const { key, ageDays } of objects) {
|
|
79
|
-
assert.equal(await storage.exists(key), ageDays < thresholdDays);
|
|
80
|
-
}
|
|
81
|
-
}), { numRuns: 100 });
|
|
82
|
-
});
|
|
83
|
-
//# sourceMappingURL=prop-lifecycle.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-lifecycle.test.js","sourceRoot":"","sources":["../../src/tests/prop-lifecycle.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-list.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-list.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
// Property-based test for the storage facade `list(prefix)` operation.
|
|
2
|
-
//
|
|
3
|
-
// Feature: unified-storage-framework, Property 6 — List returns exactly the
|
|
4
|
-
// prefix-matching keys. For an arbitrary set of stored objects and an arbitrary
|
|
5
|
-
// prefix, `list(prefix)` returns exactly the set of stored keys that begin with
|
|
6
|
-
// that prefix: no key that starts with the prefix is missing, and no key that
|
|
7
|
-
// does not start with the prefix is included.
|
|
8
|
-
//
|
|
9
|
-
// Uses the public facade via `createStorage({ provider: 'memory' })`, the
|
|
10
|
-
// Node.js built-in test runner (node:test), and fast-check configured with
|
|
11
|
-
// { numRuns: 100 }. Executed via `node --test dist/tests/*.test.js`.
|
|
12
|
-
//
|
|
13
|
-
// Validates: Requirements 4.9
|
|
14
|
-
import test from "node:test";
|
|
15
|
-
import assert from "node:assert/strict";
|
|
16
|
-
import fc from "fast-check";
|
|
17
|
-
import { createStorage } from "../index.js";
|
|
18
|
-
// A key generator that produces non-empty keys drawn from a small alphabet so
|
|
19
|
-
// that shared prefixes arise frequently, exercising the prefix-matching logic
|
|
20
|
-
// on both matching and non-matching keys.
|
|
21
|
-
const keyArb = fc.stringMatching(/^[a-c/]{1,6}$/).filter((k) => k.length > 0);
|
|
22
|
-
test("Feature: unified-storage-framework, Property 6 — list returns exactly the prefix-matching keys", async () => {
|
|
23
|
-
await fc.assert(fc.asyncProperty(
|
|
24
|
-
// A set of unique keys, each paired with arbitrary string content.
|
|
25
|
-
fc.uniqueArray(fc.tuple(keyArb, fc.string()), {
|
|
26
|
-
selector: ([key]) => key,
|
|
27
|
-
minLength: 0,
|
|
28
|
-
maxLength: 12,
|
|
29
|
-
}),
|
|
30
|
-
// An arbitrary prefix, possibly empty, possibly unrelated to any key.
|
|
31
|
-
fc.stringMatching(/^[a-c/]{0,4}$/), async (entries, prefix) => {
|
|
32
|
-
const storage = createStorage({ provider: "memory" });
|
|
33
|
-
for (const [key, content] of entries) {
|
|
34
|
-
await storage.put(key, content, {});
|
|
35
|
-
}
|
|
36
|
-
const listed = await storage.list(prefix);
|
|
37
|
-
// Observed keys returned by list(prefix).
|
|
38
|
-
const observed = new Set(listed.map((item) => item.key));
|
|
39
|
-
// Expected keys: exactly the stored keys that start with the prefix.
|
|
40
|
-
const expected = new Set(entries
|
|
41
|
-
.map(([key]) => key)
|
|
42
|
-
.filter((key) => key.startsWith(prefix)));
|
|
43
|
-
// Same cardinality and same membership => exactly equal sets.
|
|
44
|
-
assert.equal(observed.size, expected.size);
|
|
45
|
-
for (const key of expected) {
|
|
46
|
-
assert.ok(observed.has(key), `expected listed key: ${key}`);
|
|
47
|
-
}
|
|
48
|
-
for (const key of observed) {
|
|
49
|
-
assert.ok(key.startsWith(prefix), `unexpected non-matching key listed: ${key}`);
|
|
50
|
-
}
|
|
51
|
-
}), { numRuns: 100 });
|
|
52
|
-
});
|
|
53
|
-
//# sourceMappingURL=prop-list.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-list.test.js","sourceRoot":"","sources":["../../src/tests/prop-list.test.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,EAAE;AACF,4EAA4E;AAC5E,gFAAgF;AAChF,gFAAgF;AAChF,8EAA8E;AAC9E,8CAA8C;AAC9C,EAAE;AACF,0EAA0E;AAC1E,2EAA2E;AAC3E,qEAAqE;AACrE,EAAE;AACF,8BAA8B;AAE9B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,8EAA8E;AAC9E,8EAA8E;AAC9E,0CAA0C;AAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAE9E,IAAI,CACF,gGAAgG,EAChG,KAAK,IAAI,EAAE;IACT,MAAM,EAAE,CAAC,MAAM,CACb,EAAE,CAAC,aAAa;IACd,mEAAmE;IACnE,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE;QAC5C,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG;QACxB,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,EAAE;KACd,CAAC;IACF,sEAAsE;IACtE,EAAE,CAAC,cAAc,CAAC,eAAe,CAAC,EAClC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEtD,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,OAAO,EAAE,CAAC;YACrC,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;QACtC,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE1C,0CAA0C;QAC1C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAEzD,qEAAqE;QACrE,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,OAAO;aACJ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC;aACnB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAC3C,CAAC;QAEF,8DAA8D;QAC9D,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC3C,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,wBAAwB,GAAG,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC3B,MAAM,CAAC,EAAE,CACP,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EACtB,uCAAuC,GAAG,EAAE,CAC7C,CAAC;QACJ,CAAC;IACH,CAAC,CACF,EACD,EAAE,OAAO,EAAE,GAAG,EAAE,CACjB,CAAC;AACJ,CAAC,CACF,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-metadata.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-metadata.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
// Property-based test for the storage facade metadata round-trip guarantee.
|
|
2
|
-
//
|
|
3
|
-
// Feature: unified-storage-framework, Property 5: Metadata round-trips through
|
|
4
|
-
// write and read.
|
|
5
|
-
//
|
|
6
|
-
// For arbitrary keys, byte contents, and write-time metadata (contentType,
|
|
7
|
-
// owner, tenant, accessLevel, and custom fields), after `put(key, bytes,
|
|
8
|
-
// options)` followed by `stat(key)` (and `get(key)`):
|
|
9
|
-
// - the write-supplied fields on the returned metadata equal what was written
|
|
10
|
-
// (owner/tenant/custom exactly; contentType/accessLevel fall back to the
|
|
11
|
-
// canonical defaults when the write omits them), and
|
|
12
|
-
// - the computed fields (size, checksum, etag, createdAt, updatedAt) are all
|
|
13
|
-
// present and consistent with the persisted content.
|
|
14
|
-
//
|
|
15
|
-
// Uses the Node.js built-in test runner (node:test) and fast-check at
|
|
16
|
-
// `{ numRuns: 100 }`, exercising the public facade via
|
|
17
|
-
// `createStorage({ provider: 'memory' })` with a fixed clock so timestamps are
|
|
18
|
-
// deterministic. Executed via `node --test dist/tests/*.test.js`.
|
|
19
|
-
//
|
|
20
|
-
// Validates: Requirements 10.2, 26.4
|
|
21
|
-
import test from "node:test";
|
|
22
|
-
import assert from "node:assert/strict";
|
|
23
|
-
import fc from "fast-check";
|
|
24
|
-
import { createStorage } from "../facade.js";
|
|
25
|
-
import { DEFAULT_ACCESS_LEVEL, DEFAULT_CONTENT_TYPE } from "../metadata.js";
|
|
26
|
-
/** A fixed clock so object timestamps are deterministic across runs. */
|
|
27
|
-
const fixedClock = () => 1_700_000_000_000;
|
|
28
|
-
/** The valid AccessLevel values (Requirement 11.1). */
|
|
29
|
-
const ACCESS_LEVELS = [
|
|
30
|
-
"public",
|
|
31
|
-
"private",
|
|
32
|
-
"signed",
|
|
33
|
-
"authenticated",
|
|
34
|
-
"role-based",
|
|
35
|
-
"tenant-aware",
|
|
36
|
-
];
|
|
37
|
-
/** Arbitrary object content (including empty), persisted as a Uint8Array. */
|
|
38
|
-
const contentArb = fc.uint8Array({ minLength: 0, maxLength: 256 });
|
|
39
|
-
/** Non-empty object keys. */
|
|
40
|
-
const keyArb = fc.string({ minLength: 1, maxLength: 40 });
|
|
41
|
-
/**
|
|
42
|
-
* Arbitrary custom metadata map with comparable JSON-ish values so it can be
|
|
43
|
-
* asserted to round-trip exactly via deepEqual.
|
|
44
|
-
*/
|
|
45
|
-
const customArb = fc.dictionary(fc.string({ maxLength: 20 }), fc.oneof(fc.string(), fc.integer(), fc.boolean()), { maxKeys: 5 });
|
|
46
|
-
/**
|
|
47
|
-
* Arbitrary write-time metadata. Each field is optional (may be absent) so the
|
|
48
|
-
* property covers both explicitly-supplied values and the default fallbacks.
|
|
49
|
-
*/
|
|
50
|
-
const writeMetadataArb = fc.record({
|
|
51
|
-
contentType: fc.string({ minLength: 1, maxLength: 40 }),
|
|
52
|
-
owner: fc.string({ minLength: 1, maxLength: 40 }),
|
|
53
|
-
tenant: fc.string({ minLength: 1, maxLength: 40 }),
|
|
54
|
-
accessLevel: fc.constantFrom(...ACCESS_LEVELS),
|
|
55
|
-
custom: customArb,
|
|
56
|
-
}, { requiredKeys: [] });
|
|
57
|
-
test("Feature: unified-storage-framework, Property 5: Metadata round-trips through write and read", async () => {
|
|
58
|
-
await fc.assert(fc.asyncProperty(keyArb, contentArb, writeMetadataArb, async (key, content, write) => {
|
|
59
|
-
// A fresh store per case keeps each key/content pair independent.
|
|
60
|
-
const storage = createStorage({ provider: "memory", clock: fixedClock });
|
|
61
|
-
const putMeta = await storage.put(key, content, write);
|
|
62
|
-
const statMeta = await storage.stat(key);
|
|
63
|
-
const getResult = await storage.get(key);
|
|
64
|
-
assert.notEqual(statMeta, null, "stat must return metadata for a written key");
|
|
65
|
-
assert.equal(getResult.found, true, "get must find a written key");
|
|
66
|
-
// The write-supplied fields must equal what was written on every surface
|
|
67
|
-
// that returns metadata (put, stat, get).
|
|
68
|
-
for (const meta of [putMeta, statMeta, getResult.metadata]) {
|
|
69
|
-
assert.ok(meta, "metadata must be present on every surface");
|
|
70
|
-
assert.equal(meta.owner, write.owner, "owner must round-trip");
|
|
71
|
-
assert.equal(meta.tenant, write.tenant, "tenant must round-trip");
|
|
72
|
-
assert.equal(meta.contentType, write.contentType ?? DEFAULT_CONTENT_TYPE, "contentType must round-trip (or fall back to the default)");
|
|
73
|
-
assert.equal(meta.accessLevel, write.accessLevel ?? DEFAULT_ACCESS_LEVEL, "accessLevel must round-trip (or fall back to the default)");
|
|
74
|
-
assert.deepEqual(meta.custom, write.custom ?? {}, "custom fields must round-trip (or default to {})");
|
|
75
|
-
// The computed fields must be present and consistent with the content.
|
|
76
|
-
assert.equal(meta.size, content.byteLength, "size must equal the content byte length");
|
|
77
|
-
assert.equal(typeof meta.checksum, "string", "checksum must be present");
|
|
78
|
-
assert.ok(meta.checksum.length > 0, "checksum must be non-empty");
|
|
79
|
-
assert.equal(typeof meta.etag, "string", "etag must be present");
|
|
80
|
-
assert.ok(meta.etag.length > 0, "etag must be non-empty");
|
|
81
|
-
assert.equal(typeof meta.createdAt, "number", "createdAt must be present");
|
|
82
|
-
assert.equal(typeof meta.updatedAt, "number", "updatedAt must be present");
|
|
83
|
-
}
|
|
84
|
-
await storage.close();
|
|
85
|
-
}), { numRuns: 100 });
|
|
86
|
-
});
|
|
87
|
-
//# sourceMappingURL=prop-metadata.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-metadata.test.js","sourceRoot":"","sources":["../../src/tests/prop-metadata.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-move.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-move.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
// Property test: move relocates content and removes the source.
|
|
2
|
-
//
|
|
3
|
-
// Feature: unified-storage-framework, Property 3: Move relocates content and
|
|
4
|
-
// removes the source.
|
|
5
|
-
// Validates: Requirements 4.7, 4.8, 26.3
|
|
6
|
-
//
|
|
7
|
-
// Req 4.7: `move(source, destination)` relocates the object — the content
|
|
8
|
-
// becomes available at `destination` and the source object is removed.
|
|
9
|
-
// Req 4.8: after a successful relocation the source key no longer exists.
|
|
10
|
-
// Req 26.3: the observable move semantics hold across arbitrary keys/content.
|
|
11
|
-
//
|
|
12
|
-
// Strategy: through the real facade built with the zero-dependency memory
|
|
13
|
-
// provider (`createStorage({ provider: "memory" })`), for arbitrary DISTINCT
|
|
14
|
-
// source/destination keys and arbitrary content bytes:
|
|
15
|
-
// 1. `put(source, bytes)` stores the content,
|
|
16
|
-
// 2. `move(source, dest)` relocates it, and we assert the four observable
|
|
17
|
-
// consequences of a successful move:
|
|
18
|
-
// (a) the move result is `{ moved: true }`,
|
|
19
|
-
// (b) `get(dest)` returns bytes byte-for-byte equal to the original,
|
|
20
|
-
// (c) `exists(source)` is now false, and
|
|
21
|
-
// (d) `get(source)` reports `{ found: false }`.
|
|
22
|
-
// A control case guards the not-found path: moving a source that was never
|
|
23
|
-
// stored returns `{ moved: false }` without throwing.
|
|
24
|
-
//
|
|
25
|
-
// Uses the Node.js built-in test runner (node:test) and fast-check at the
|
|
26
|
-
// spec-mandated `{ numRuns: 100 }`.
|
|
27
|
-
import test from "node:test";
|
|
28
|
-
import assert from "node:assert/strict";
|
|
29
|
-
import fc from "fast-check";
|
|
30
|
-
import { createStorage } from "../index.js";
|
|
31
|
-
/**
|
|
32
|
-
* Generate two distinct, non-empty object keys. fast-check's `uniqueArray`
|
|
33
|
-
* guarantees the pair differs, so `source` and `destination` never collide
|
|
34
|
-
* (a collision would make "removes the source" ambiguous).
|
|
35
|
-
*/
|
|
36
|
-
const distinctKeys = fc
|
|
37
|
-
.uniqueArray(fc.string({ minLength: 1, maxLength: 40 }).filter((s) => s.trim().length > 0), { minLength: 2, maxLength: 2 })
|
|
38
|
-
.map(([source, destination]) => ({ source, destination }));
|
|
39
|
-
test("Feature: unified-storage-framework, Property 3: move relocates content and removes the source", async () => {
|
|
40
|
-
await fc.assert(fc.asyncProperty(distinctKeys, fc.uint8Array({ minLength: 0, maxLength: 512 }), async ({ source, destination }, content) => {
|
|
41
|
-
const storage = createStorage({ provider: "memory" });
|
|
42
|
-
await storage.put(source, content);
|
|
43
|
-
const result = await storage.move(source, destination);
|
|
44
|
-
// (a) the move reports success.
|
|
45
|
-
assert.equal(result.moved, true);
|
|
46
|
-
// (b) the destination now holds the original bytes, unchanged.
|
|
47
|
-
const atDest = await storage.get(destination);
|
|
48
|
-
assert.equal(atDest.found, true);
|
|
49
|
-
assert.deepEqual(atDest.bytes, content);
|
|
50
|
-
// (c) the source no longer exists.
|
|
51
|
-
assert.equal(await storage.exists(source), false);
|
|
52
|
-
// (d) reading the source reports not-found (never throws).
|
|
53
|
-
const atSource = await storage.get(source);
|
|
54
|
-
assert.equal(atSource.found, false);
|
|
55
|
-
}), { numRuns: 100 });
|
|
56
|
-
});
|
|
57
|
-
test("Feature: unified-storage-framework, Property 3: moving a missing source returns { moved: false }", async () => {
|
|
58
|
-
await fc.assert(fc.asyncProperty(distinctKeys, async ({ source, destination }) => {
|
|
59
|
-
const storage = createStorage({ provider: "memory" });
|
|
60
|
-
// Nothing was ever stored under `source`.
|
|
61
|
-
const result = await storage.move(source, destination);
|
|
62
|
-
assert.equal(result.moved, false);
|
|
63
|
-
// No object is fabricated at the destination.
|
|
64
|
-
assert.equal(await storage.exists(destination), false);
|
|
65
|
-
}), { numRuns: 100 });
|
|
66
|
-
});
|
|
67
|
-
//# sourceMappingURL=prop-move.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-move.test.js","sourceRoot":"","sources":["../../src/tests/prop-move.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-multipart-abort.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-multipart-abort.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// Property-based test for the storage facade's multipart abort guarantee.
|
|
2
|
-
//
|
|
3
|
-
// Property 9 (Abort leaves no object): for an arbitrary key and an arbitrary
|
|
4
|
-
// list of parts uploaded via `createMultipartUpload` → `uploadPart` for each
|
|
5
|
-
// part, calling `abortMultipartUpload(uploadId)` discards every uploaded part
|
|
6
|
-
// and creates no completed object. After the abort the target key must not
|
|
7
|
-
// exist (`exists(key) === false`) and reading it must report not-found, so no
|
|
8
|
-
// leftover final object is ever produced by the aborted upload (Requirement
|
|
9
|
-
// 6.4). The abort path runs over the zero-dependency `memory` provider — the
|
|
10
|
-
// identical code path every provider shares — exercised via the public facade.
|
|
11
|
-
//
|
|
12
|
-
// Uses the Node.js built-in test runner (node:test) with fast-check for input
|
|
13
|
-
// generation, executed via `node --test dist/tests/*.test.js`. fast-check is
|
|
14
|
-
// configured with { numRuns: 100 } per the design's property-testing contract.
|
|
15
|
-
//
|
|
16
|
-
// Feature: unified-storage-framework, Property 9: Abort leaves no object
|
|
17
|
-
//
|
|
18
|
-
// Validates: Requirements 6.4
|
|
19
|
-
import test from "node:test";
|
|
20
|
-
import assert from "node:assert/strict";
|
|
21
|
-
import fc from "fast-check";
|
|
22
|
-
import { createStorage } from "../index.js";
|
|
23
|
-
test("Feature: unified-storage-framework, Property 9: Abort leaves no object", async () => {
|
|
24
|
-
await fc.assert(fc.asyncProperty(
|
|
25
|
-
// An arbitrary target key for the multipart upload and an arbitrary
|
|
26
|
-
// ordered list of parts. At least one part is generated so there is
|
|
27
|
-
// always something to upload before aborting; individual parts may be
|
|
28
|
-
// empty, exercising abort after zero-length segments.
|
|
29
|
-
fc.string(), fc.array(fc.uint8Array(), { minLength: 1, maxLength: 8 }), async (key, parts) => {
|
|
30
|
-
// A fresh store per run keeps each key/parts pair independent.
|
|
31
|
-
const storage = createStorage({ provider: "memory" });
|
|
32
|
-
// ── Upload parts, then abort ──────────────────────────────────────
|
|
33
|
-
const uploadId = await storage.createMultipartUpload(key);
|
|
34
|
-
for (let index = 0; index < parts.length; index += 1) {
|
|
35
|
-
// Part numbers are 1-based positive integers assigned in order.
|
|
36
|
-
await storage.uploadPart(uploadId, index + 1, parts[index]);
|
|
37
|
-
}
|
|
38
|
-
await storage.abortMultipartUpload(uploadId);
|
|
39
|
-
// The aborted upload must create no completed object at the key: the
|
|
40
|
-
// key must not exist and reading it must report not-found (no
|
|
41
|
-
// leftover final object).
|
|
42
|
-
assert.equal(await storage.exists(key), false, "aborted multipart upload must leave no object at the target key");
|
|
43
|
-
const result = await storage.get(key);
|
|
44
|
-
assert.equal(result.found, false, "reading the target key after abort must report not-found");
|
|
45
|
-
await storage.close();
|
|
46
|
-
}), { numRuns: 100 });
|
|
47
|
-
});
|
|
48
|
-
//# sourceMappingURL=prop-multipart-abort.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-multipart-abort.test.js","sourceRoot":"","sources":["../../src/tests/prop-multipart-abort.test.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,8EAA8E;AAC9E,4EAA4E;AAC5E,6EAA6E;AAC7E,+EAA+E;AAC/E,EAAE;AACF,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,EAAE;AACF,yEAAyE;AACzE,EAAE;AACF,8BAA8B;AAE9B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,IAAI,CACF,wEAAwE,EACxE,KAAK,IAAI,EAAE;IACT,MAAM,EAAE,CAAC,MAAM,CACb,EAAE,CAAC,aAAa;IACd,oEAAoE;IACpE,oEAAoE;IACpE,sEAAsE;IACtE,sDAAsD;IACtD,EAAE,CAAC,MAAM,EAAE,EACX,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EACzD,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACnB,+DAA+D;QAC/D,MAAM,OAAO,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEtD,qEAAqE;QACrE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAC1D,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;YACrD,gEAAgE;YAChE,MAAM,OAAO,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9D,CAAC;QAED,MAAM,OAAO,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAE7C,qEAAqE;QACrE,8DAA8D;QAC9D,0BAA0B;QAC1B,MAAM,CAAC,KAAK,CACV,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EACzB,KAAK,EACL,iEAAiE,CAClE,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CACV,MAAM,CAAC,KAAK,EACZ,KAAK,EACL,0DAA0D,CAC3D,CAAC;QAEF,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC,CACF,EACD,EAAE,OAAO,EAAE,GAAG,EAAE,CACjB,CAAC;AACJ,CAAC,CACF,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prop-multipart.test.d.ts","sourceRoot":"","sources":["../../src/tests/prop-multipart.test.ts"],"names":[],"mappings":""}
|