@anvilkit/plugin-asset-manager 0.1.1
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 +159 -0
- package/dist/adapters/data-url.cjs +78 -0
- package/dist/adapters/data-url.d.cts +6 -0
- package/dist/adapters/data-url.d.cts.map +1 -0
- package/dist/adapters/data-url.d.ts +6 -0
- package/dist/adapters/data-url.d.ts.map +1 -0
- package/dist/adapters/data-url.js +44 -0
- package/dist/adapters/extract-image-dimensions.cjs +69 -0
- package/dist/adapters/extract-image-dimensions.d.cts +21 -0
- package/dist/adapters/extract-image-dimensions.d.cts.map +1 -0
- package/dist/adapters/extract-image-dimensions.d.ts +21 -0
- package/dist/adapters/extract-image-dimensions.d.ts.map +1 -0
- package/dist/adapters/extract-image-dimensions.js +35 -0
- package/dist/adapters/in-memory.cjs +62 -0
- package/dist/adapters/in-memory.d.cts +3 -0
- package/dist/adapters/in-memory.d.cts.map +1 -0
- package/dist/adapters/in-memory.d.ts +3 -0
- package/dist/adapters/in-memory.d.ts.map +1 -0
- package/dist/adapters/in-memory.js +28 -0
- package/dist/adapters/s3-presigned.cjs +166 -0
- package/dist/adapters/s3-presigned.d.cts +59 -0
- package/dist/adapters/s3-presigned.d.cts.map +1 -0
- package/dist/adapters/s3-presigned.d.ts +59 -0
- package/dist/adapters/s3-presigned.d.ts.map +1 -0
- package/dist/adapters/s3-presigned.js +129 -0
- package/dist/asset-reference.cjs +38 -0
- package/dist/asset-reference.d.cts +10 -0
- package/dist/asset-reference.d.cts.map +1 -0
- package/dist/asset-reference.d.ts +10 -0
- package/dist/asset-reference.d.ts.map +1 -0
- package/dist/asset-reference.js +4 -0
- package/dist/csp.cjs +83 -0
- package/dist/csp.d.cts +45 -0
- package/dist/csp.d.cts.map +1 -0
- package/dist/csp.d.ts +45 -0
- package/dist/csp.d.ts.map +1 -0
- package/dist/csp.js +49 -0
- package/dist/errors.cjs +58 -0
- package/dist/errors.d.cts +15 -0
- package/dist/errors.d.cts.map +1 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +21 -0
- package/dist/header-action.cjs +44 -0
- package/dist/header-action.d.cts +3 -0
- package/dist/header-action.d.cts.map +1 -0
- package/dist/header-action.d.ts +3 -0
- package/dist/header-action.d.ts.map +1 -0
- package/dist/header-action.js +10 -0
- package/dist/index.cjs +90 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/infer-kind.cjs +45 -0
- package/dist/infer-kind.d.cts +8 -0
- package/dist/infer-kind.d.cts.map +1 -0
- package/dist/infer-kind.d.ts +8 -0
- package/dist/infer-kind.d.ts.map +1 -0
- package/dist/infer-kind.js +11 -0
- package/dist/plugin.cjs +258 -0
- package/dist/plugin.d.cts +9 -0
- package/dist/plugin.d.cts.map +1 -0
- package/dist/plugin.d.ts +9 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +212 -0
- package/dist/registry.cjs +198 -0
- package/dist/registry.d.cts +3 -0
- package/dist/registry.d.cts.map +1 -0
- package/dist/registry.d.ts +3 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +164 -0
- package/dist/resolver.cjs +185 -0
- package/dist/resolver.d.cts +10 -0
- package/dist/resolver.d.cts.map +1 -0
- package/dist/resolver.d.ts +10 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/resolver.js +148 -0
- package/dist/retry.cjs +123 -0
- package/dist/retry.d.cts +71 -0
- package/dist/retry.d.cts.map +1 -0
- package/dist/retry.d.ts +71 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +86 -0
- package/dist/studio-asset-source.cjs +211 -0
- package/dist/studio-asset-source.d.cts +52 -0
- package/dist/studio-asset-source.d.cts.map +1 -0
- package/dist/studio-asset-source.d.ts +52 -0
- package/dist/studio-asset-source.d.ts.map +1 -0
- package/dist/studio-asset-source.js +171 -0
- package/dist/testing/index.cjs +66 -0
- package/dist/testing/index.d.cts +24 -0
- package/dist/testing/index.d.cts.map +1 -0
- package/dist/testing/index.d.ts +24 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +29 -0
- package/dist/types.cjs +18 -0
- package/dist/types.d.cts +132 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.ts +132 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +0 -0
- package/dist/ui/AssetBrowser.cjs +271 -0
- package/dist/ui/AssetBrowser.d.cts +45 -0
- package/dist/ui/AssetBrowser.d.cts.map +1 -0
- package/dist/ui/AssetBrowser.d.ts +45 -0
- package/dist/ui/AssetBrowser.d.ts.map +1 -0
- package/dist/ui/AssetBrowser.js +237 -0
- package/dist/ui/AssetCommandPalette.cjs +135 -0
- package/dist/ui/AssetCommandPalette.d.cts +21 -0
- package/dist/ui/AssetCommandPalette.d.cts.map +1 -0
- package/dist/ui/AssetCommandPalette.d.ts +21 -0
- package/dist/ui/AssetCommandPalette.d.ts.map +1 -0
- package/dist/ui/AssetCommandPalette.js +101 -0
- package/dist/ui/AssetManagerUI.cjs +169 -0
- package/dist/ui/AssetManagerUI.d.cts +15 -0
- package/dist/ui/AssetManagerUI.d.cts.map +1 -0
- package/dist/ui/AssetManagerUI.d.ts +15 -0
- package/dist/ui/AssetManagerUI.d.ts.map +1 -0
- package/dist/ui/AssetManagerUI.js +135 -0
- package/dist/ui/DeleteAssetDialog.cjs +70 -0
- package/dist/ui/DeleteAssetDialog.d.cts +22 -0
- package/dist/ui/DeleteAssetDialog.d.cts.map +1 -0
- package/dist/ui/DeleteAssetDialog.d.ts +22 -0
- package/dist/ui/DeleteAssetDialog.d.ts.map +1 -0
- package/dist/ui/DeleteAssetDialog.js +36 -0
- package/dist/ui/MetadataPanel.cjs +147 -0
- package/dist/ui/MetadataPanel.d.cts +21 -0
- package/dist/ui/MetadataPanel.d.cts.map +1 -0
- package/dist/ui/MetadataPanel.d.ts +21 -0
- package/dist/ui/MetadataPanel.d.ts.map +1 -0
- package/dist/ui/MetadataPanel.js +113 -0
- package/dist/ui/ReplaceAssetDialog.cjs +125 -0
- package/dist/ui/ReplaceAssetDialog.d.cts +14 -0
- package/dist/ui/ReplaceAssetDialog.d.cts.map +1 -0
- package/dist/ui/ReplaceAssetDialog.d.ts +14 -0
- package/dist/ui/ReplaceAssetDialog.d.ts.map +1 -0
- package/dist/ui/ReplaceAssetDialog.js +91 -0
- package/dist/ui/UploadButton.cjs +189 -0
- package/dist/ui/UploadButton.d.cts +17 -0
- package/dist/ui/UploadButton.d.cts.map +1 -0
- package/dist/ui/UploadButton.d.ts +17 -0
- package/dist/ui/UploadButton.d.ts.map +1 -0
- package/dist/ui/UploadButton.js +155 -0
- package/dist/ui/index.cjs +60 -0
- package/dist/ui/index.d.cts +15 -0
- package/dist/ui/index.d.cts.map +1 -0
- package/dist/ui/index.d.ts +15 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +7 -0
- package/dist/validate-upload-result.cjs +149 -0
- package/dist/validate-upload-result.d.cts +9 -0
- package/dist/validate-upload-result.d.cts.map +1 -0
- package/dist/validate-upload-result.d.ts +9 -0
- package/dist/validate-upload-result.d.ts.map +1 -0
- package/dist/validate-upload-result.js +115 -0
- package/package.json +131 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
s3PresignedAdapter: ()=>s3PresignedAdapter,
|
|
28
|
+
RetryableError: ()=>external_retry_cjs_namespaceObject.RetryableError
|
|
29
|
+
});
|
|
30
|
+
const external_errors_cjs_namespaceObject = require("../errors.cjs");
|
|
31
|
+
const external_retry_cjs_namespaceObject = require("../retry.cjs");
|
|
32
|
+
function s3PresignedAdapter(options) {
|
|
33
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
34
|
+
if ("function" != typeof fetchImpl) throw new Error("s3PresignedAdapter: no `fetch` implementation available. Pass `options.fetch`.");
|
|
35
|
+
const generateId = options.idGenerator ?? defaultIdGenerator;
|
|
36
|
+
return async (file)=>{
|
|
37
|
+
const presign = await (0, external_retry_cjs_namespaceObject.withRetry)(()=>requestPresign(file, fetchImpl, options), {
|
|
38
|
+
...options.retry ?? {},
|
|
39
|
+
signal: options.signal
|
|
40
|
+
});
|
|
41
|
+
await (0, external_retry_cjs_namespaceObject.withRetry)(()=>putToS3(file, presign, fetchImpl, options.signal), {
|
|
42
|
+
...options.retry ?? {},
|
|
43
|
+
signal: options.signal
|
|
44
|
+
});
|
|
45
|
+
const id = presign.id ?? generateId();
|
|
46
|
+
const publicUrl = presign.publicUrl ?? stripQueryAndFragment(presign.url);
|
|
47
|
+
const result = {
|
|
48
|
+
id,
|
|
49
|
+
url: publicUrl,
|
|
50
|
+
...file.name ? {
|
|
51
|
+
name: file.name
|
|
52
|
+
} : {},
|
|
53
|
+
meta: {
|
|
54
|
+
size: file.size,
|
|
55
|
+
...file.type ? {
|
|
56
|
+
mimeType: file.type
|
|
57
|
+
} : {}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return result;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function requestPresign(file, fetchImpl, options) {
|
|
64
|
+
const url = "string" == typeof options.presignEndpoint ? options.presignEndpoint : options.presignEndpoint.toString();
|
|
65
|
+
const body = JSON.stringify({
|
|
66
|
+
name: file.name,
|
|
67
|
+
type: file.type,
|
|
68
|
+
size: file.size
|
|
69
|
+
});
|
|
70
|
+
let response;
|
|
71
|
+
try {
|
|
72
|
+
response = await fetchImpl(url, {
|
|
73
|
+
method: "POST",
|
|
74
|
+
headers: {
|
|
75
|
+
"Content-Type": "application/json",
|
|
76
|
+
...options.headers ?? {}
|
|
77
|
+
},
|
|
78
|
+
body,
|
|
79
|
+
...options.signal ? {
|
|
80
|
+
signal: options.signal
|
|
81
|
+
} : {}
|
|
82
|
+
});
|
|
83
|
+
} catch (cause) {
|
|
84
|
+
throw new external_retry_cjs_namespaceObject.RetryableError(`s3PresignedAdapter: presign request failed (${describeError(cause)}).`, {
|
|
85
|
+
cause
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (response.status >= 500) throw new external_retry_cjs_namespaceObject.RetryableError(`s3PresignedAdapter: presign returned ${response.status}.`, {
|
|
89
|
+
retryAfterMs: parseRetryAfter(response.headers.get("retry-after"))
|
|
90
|
+
});
|
|
91
|
+
if (!response.ok) throw new external_errors_cjs_namespaceObject.AssetValidationError("UPLOAD_FAILED", `s3PresignedAdapter: presign returned ${response.status}.`);
|
|
92
|
+
let payload;
|
|
93
|
+
try {
|
|
94
|
+
payload = await response.json();
|
|
95
|
+
} catch (cause) {
|
|
96
|
+
throw new external_errors_cjs_namespaceObject.AssetValidationError("UPLOAD_FAILED", "s3PresignedAdapter: presign response was not JSON.", {
|
|
97
|
+
cause
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (!isPresignResponse(payload)) throw new external_errors_cjs_namespaceObject.AssetValidationError("UPLOAD_FAILED", "s3PresignedAdapter: presign response missing `url`.");
|
|
101
|
+
return payload;
|
|
102
|
+
}
|
|
103
|
+
async function putToS3(file, presign, fetchImpl, signal) {
|
|
104
|
+
const headers = {
|
|
105
|
+
...file.type ? {
|
|
106
|
+
"Content-Type": file.type
|
|
107
|
+
} : {},
|
|
108
|
+
...presign.headers ?? {}
|
|
109
|
+
};
|
|
110
|
+
let response;
|
|
111
|
+
try {
|
|
112
|
+
response = await fetchImpl(presign.url, {
|
|
113
|
+
method: "PUT",
|
|
114
|
+
body: file,
|
|
115
|
+
headers,
|
|
116
|
+
...signal ? {
|
|
117
|
+
signal
|
|
118
|
+
} : {}
|
|
119
|
+
});
|
|
120
|
+
} catch (cause) {
|
|
121
|
+
throw new external_retry_cjs_namespaceObject.RetryableError(`s3PresignedAdapter: PUT failed (${describeError(cause)}).`, {
|
|
122
|
+
cause
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
if (response.status >= 500) throw new external_retry_cjs_namespaceObject.RetryableError(`s3PresignedAdapter: PUT returned ${response.status}.`, {
|
|
126
|
+
retryAfterMs: parseRetryAfter(response.headers.get("retry-after"))
|
|
127
|
+
});
|
|
128
|
+
if (!response.ok) throw new external_errors_cjs_namespaceObject.AssetValidationError("UPLOAD_FAILED", `s3PresignedAdapter: PUT returned ${response.status}.`);
|
|
129
|
+
}
|
|
130
|
+
function isPresignResponse(value) {
|
|
131
|
+
return null !== value && "object" == typeof value && "string" == typeof value.url && value.url.length > 0;
|
|
132
|
+
}
|
|
133
|
+
function stripQueryAndFragment(url) {
|
|
134
|
+
const queryIdx = url.indexOf("?");
|
|
135
|
+
const fragmentIdx = url.indexOf("#");
|
|
136
|
+
const cuts = [
|
|
137
|
+
queryIdx,
|
|
138
|
+
fragmentIdx
|
|
139
|
+
].filter((i)=>-1 !== i);
|
|
140
|
+
if (0 === cuts.length) return url;
|
|
141
|
+
return url.slice(0, Math.min(...cuts));
|
|
142
|
+
}
|
|
143
|
+
function parseRetryAfter(header) {
|
|
144
|
+
if (null === header) return;
|
|
145
|
+
const seconds = Number(header);
|
|
146
|
+
if (Number.isFinite(seconds) && seconds >= 0) return 1000 * seconds;
|
|
147
|
+
const date = Date.parse(header);
|
|
148
|
+
if (!Number.isNaN(date)) return Math.max(0, date - Date.now());
|
|
149
|
+
}
|
|
150
|
+
function describeError(error) {
|
|
151
|
+
if (error instanceof Error) return error.message || error.name;
|
|
152
|
+
return String(error);
|
|
153
|
+
}
|
|
154
|
+
function defaultIdGenerator() {
|
|
155
|
+
if (void 0 !== globalThis.crypto && "function" == typeof globalThis.crypto.randomUUID) return globalThis.crypto.randomUUID();
|
|
156
|
+
return `asset-${Math.random().toString(36).slice(2)}-${Date.now()}`;
|
|
157
|
+
}
|
|
158
|
+
exports.RetryableError = __webpack_exports__.RetryableError;
|
|
159
|
+
exports.s3PresignedAdapter = __webpack_exports__.s3PresignedAdapter;
|
|
160
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
161
|
+
"RetryableError",
|
|
162
|
+
"s3PresignedAdapter"
|
|
163
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
164
|
+
Object.defineProperty(exports, '__esModule', {
|
|
165
|
+
value: true
|
|
166
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file S3 presigned adapter — production-ready upload backend that
|
|
3
|
+
* fronts an arbitrary "presign + PUT" service.
|
|
4
|
+
*
|
|
5
|
+
* Pipeline:
|
|
6
|
+
* 1. POST `presignEndpoint` with `{ name, type, size }`.
|
|
7
|
+
* 2. Receive `{ url, publicUrl?, fields?, headers?, id? }`.
|
|
8
|
+
* 3. PUT the file body to `url` with `Content-Type: file.type`.
|
|
9
|
+
* 4. Return a validated `UploadResult` for the registry.
|
|
10
|
+
*
|
|
11
|
+
* Both phases are wrapped in `withRetry()` — 5xx and network failures
|
|
12
|
+
* throw `RetryableError`; 4xx and shape errors throw
|
|
13
|
+
* `AssetValidationError("UPLOAD_FAILED")` (no retry).
|
|
14
|
+
*
|
|
15
|
+
* The adapter never logs file contents — only `name`, `size`, and
|
|
16
|
+
* `mimeType` are safe to log.
|
|
17
|
+
*
|
|
18
|
+
* @experimental Public surface may change before v1.0.
|
|
19
|
+
*/
|
|
20
|
+
import { type RetryOptions } from "../retry.js";
|
|
21
|
+
import type { UploadAdapter } from "../types.js";
|
|
22
|
+
export { RetryableError } from "../retry.js";
|
|
23
|
+
export type { RetryOptions } from "../retry.js";
|
|
24
|
+
export interface S3PresignedAdapterOptions {
|
|
25
|
+
/** Endpoint that returns a presigned PUT target for the file. */
|
|
26
|
+
readonly presignEndpoint: string | URL;
|
|
27
|
+
/**
|
|
28
|
+
* Injectable `fetch` implementation. Defaults to `globalThis.fetch`.
|
|
29
|
+
* Tests pass a fake; production callers can wire in a custom fetch
|
|
30
|
+
* for instrumentation or redirects.
|
|
31
|
+
*/
|
|
32
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
33
|
+
/** Recorded for logs / diagnostics; the adapter does not validate it. */
|
|
34
|
+
readonly region?: string;
|
|
35
|
+
/** Forwarded to `withRetry()` for both phases. */
|
|
36
|
+
readonly retry?: RetryOptions;
|
|
37
|
+
/** Aborts the in-flight presign + PUT (and any retry sleeps). */
|
|
38
|
+
readonly signal?: AbortSignal;
|
|
39
|
+
/** Extra headers applied to the presign POST (e.g. auth). */
|
|
40
|
+
readonly headers?: Record<string, string>;
|
|
41
|
+
/** Override the asset id generator. Default: `crypto.randomUUID()`. */
|
|
42
|
+
readonly idGenerator?: () => string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Shape returned by `presignEndpoint`. Hosts may return additional
|
|
46
|
+
* fields — the adapter ignores them.
|
|
47
|
+
*/
|
|
48
|
+
export interface S3PresignResponse {
|
|
49
|
+
/** Presigned PUT URL. */
|
|
50
|
+
readonly url: string;
|
|
51
|
+
/** Canonical URL recorded on the asset. Defaults to a stripped `url`. */
|
|
52
|
+
readonly publicUrl?: string;
|
|
53
|
+
/** Optional headers to forward on the PUT (e.g. `x-amz-*`). */
|
|
54
|
+
readonly headers?: Record<string, string>;
|
|
55
|
+
/** Optional asset id; falls back to `idGenerator()`. */
|
|
56
|
+
readonly id?: string;
|
|
57
|
+
}
|
|
58
|
+
export declare function s3PresignedAdapter(options: S3PresignedAdapterOptions): UploadAdapter;
|
|
59
|
+
//# sourceMappingURL=s3-presigned.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-presigned.d.cts","sourceRoot":"","sources":["../../src/adapters/s3-presigned.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAkB,KAAK,YAAY,EAAa,MAAM,aAAa,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,aAAa,CAAC;AAE/D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,yBAAyB;IACzC,iEAAiE;IACjE,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,GAAG,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,kDAAkD;IAClD,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,uEAAuE;IACvE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,MAAM,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IACjC,yBAAyB;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,wDAAwD;IACxD,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,yBAAyB,GAChC,aAAa,CAkCf"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file S3 presigned adapter — production-ready upload backend that
|
|
3
|
+
* fronts an arbitrary "presign + PUT" service.
|
|
4
|
+
*
|
|
5
|
+
* Pipeline:
|
|
6
|
+
* 1. POST `presignEndpoint` with `{ name, type, size }`.
|
|
7
|
+
* 2. Receive `{ url, publicUrl?, fields?, headers?, id? }`.
|
|
8
|
+
* 3. PUT the file body to `url` with `Content-Type: file.type`.
|
|
9
|
+
* 4. Return a validated `UploadResult` for the registry.
|
|
10
|
+
*
|
|
11
|
+
* Both phases are wrapped in `withRetry()` — 5xx and network failures
|
|
12
|
+
* throw `RetryableError`; 4xx and shape errors throw
|
|
13
|
+
* `AssetValidationError("UPLOAD_FAILED")` (no retry).
|
|
14
|
+
*
|
|
15
|
+
* The adapter never logs file contents — only `name`, `size`, and
|
|
16
|
+
* `mimeType` are safe to log.
|
|
17
|
+
*
|
|
18
|
+
* @experimental Public surface may change before v1.0.
|
|
19
|
+
*/
|
|
20
|
+
import { type RetryOptions } from "../retry.js";
|
|
21
|
+
import type { UploadAdapter } from "../types.js";
|
|
22
|
+
export { RetryableError } from "../retry.js";
|
|
23
|
+
export type { RetryOptions } from "../retry.js";
|
|
24
|
+
export interface S3PresignedAdapterOptions {
|
|
25
|
+
/** Endpoint that returns a presigned PUT target for the file. */
|
|
26
|
+
readonly presignEndpoint: string | URL;
|
|
27
|
+
/**
|
|
28
|
+
* Injectable `fetch` implementation. Defaults to `globalThis.fetch`.
|
|
29
|
+
* Tests pass a fake; production callers can wire in a custom fetch
|
|
30
|
+
* for instrumentation or redirects.
|
|
31
|
+
*/
|
|
32
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
33
|
+
/** Recorded for logs / diagnostics; the adapter does not validate it. */
|
|
34
|
+
readonly region?: string;
|
|
35
|
+
/** Forwarded to `withRetry()` for both phases. */
|
|
36
|
+
readonly retry?: RetryOptions;
|
|
37
|
+
/** Aborts the in-flight presign + PUT (and any retry sleeps). */
|
|
38
|
+
readonly signal?: AbortSignal;
|
|
39
|
+
/** Extra headers applied to the presign POST (e.g. auth). */
|
|
40
|
+
readonly headers?: Record<string, string>;
|
|
41
|
+
/** Override the asset id generator. Default: `crypto.randomUUID()`. */
|
|
42
|
+
readonly idGenerator?: () => string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Shape returned by `presignEndpoint`. Hosts may return additional
|
|
46
|
+
* fields — the adapter ignores them.
|
|
47
|
+
*/
|
|
48
|
+
export interface S3PresignResponse {
|
|
49
|
+
/** Presigned PUT URL. */
|
|
50
|
+
readonly url: string;
|
|
51
|
+
/** Canonical URL recorded on the asset. Defaults to a stripped `url`. */
|
|
52
|
+
readonly publicUrl?: string;
|
|
53
|
+
/** Optional headers to forward on the PUT (e.g. `x-amz-*`). */
|
|
54
|
+
readonly headers?: Record<string, string>;
|
|
55
|
+
/** Optional asset id; falls back to `idGenerator()`. */
|
|
56
|
+
readonly id?: string;
|
|
57
|
+
}
|
|
58
|
+
export declare function s3PresignedAdapter(options: S3PresignedAdapterOptions): UploadAdapter;
|
|
59
|
+
//# sourceMappingURL=s3-presigned.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-presigned.d.ts","sourceRoot":"","sources":["../../src/adapters/s3-presigned.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAkB,KAAK,YAAY,EAAa,MAAM,aAAa,CAAC;AAC3E,OAAO,KAAK,EAAE,aAAa,EAAgB,MAAM,aAAa,CAAC;AAE/D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,yBAAyB;IACzC,iEAAiE;IACjE,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,GAAG,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,kDAAkD;IAClD,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,uEAAuE;IACvE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,MAAM,CAAC;CACpC;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IACjC,yBAAyB;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,wDAAwD;IACxD,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,yBAAyB,GAChC,aAAa,CAkCf"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { AssetValidationError } from "../errors.js";
|
|
2
|
+
import { RetryableError, withRetry } from "../retry.js";
|
|
3
|
+
function s3PresignedAdapter(options) {
|
|
4
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
5
|
+
if ("function" != typeof fetchImpl) throw new Error("s3PresignedAdapter: no `fetch` implementation available. Pass `options.fetch`.");
|
|
6
|
+
const generateId = options.idGenerator ?? defaultIdGenerator;
|
|
7
|
+
return async (file)=>{
|
|
8
|
+
const presign = await withRetry(()=>requestPresign(file, fetchImpl, options), {
|
|
9
|
+
...options.retry ?? {},
|
|
10
|
+
signal: options.signal
|
|
11
|
+
});
|
|
12
|
+
await withRetry(()=>putToS3(file, presign, fetchImpl, options.signal), {
|
|
13
|
+
...options.retry ?? {},
|
|
14
|
+
signal: options.signal
|
|
15
|
+
});
|
|
16
|
+
const id = presign.id ?? generateId();
|
|
17
|
+
const publicUrl = presign.publicUrl ?? stripQueryAndFragment(presign.url);
|
|
18
|
+
const result = {
|
|
19
|
+
id,
|
|
20
|
+
url: publicUrl,
|
|
21
|
+
...file.name ? {
|
|
22
|
+
name: file.name
|
|
23
|
+
} : {},
|
|
24
|
+
meta: {
|
|
25
|
+
size: file.size,
|
|
26
|
+
...file.type ? {
|
|
27
|
+
mimeType: file.type
|
|
28
|
+
} : {}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
return result;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
async function requestPresign(file, fetchImpl, options) {
|
|
35
|
+
const url = "string" == typeof options.presignEndpoint ? options.presignEndpoint : options.presignEndpoint.toString();
|
|
36
|
+
const body = JSON.stringify({
|
|
37
|
+
name: file.name,
|
|
38
|
+
type: file.type,
|
|
39
|
+
size: file.size
|
|
40
|
+
});
|
|
41
|
+
let response;
|
|
42
|
+
try {
|
|
43
|
+
response = await fetchImpl(url, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: {
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
...options.headers ?? {}
|
|
48
|
+
},
|
|
49
|
+
body,
|
|
50
|
+
...options.signal ? {
|
|
51
|
+
signal: options.signal
|
|
52
|
+
} : {}
|
|
53
|
+
});
|
|
54
|
+
} catch (cause) {
|
|
55
|
+
throw new RetryableError(`s3PresignedAdapter: presign request failed (${describeError(cause)}).`, {
|
|
56
|
+
cause
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (response.status >= 500) throw new RetryableError(`s3PresignedAdapter: presign returned ${response.status}.`, {
|
|
60
|
+
retryAfterMs: parseRetryAfter(response.headers.get("retry-after"))
|
|
61
|
+
});
|
|
62
|
+
if (!response.ok) throw new AssetValidationError("UPLOAD_FAILED", `s3PresignedAdapter: presign returned ${response.status}.`);
|
|
63
|
+
let payload;
|
|
64
|
+
try {
|
|
65
|
+
payload = await response.json();
|
|
66
|
+
} catch (cause) {
|
|
67
|
+
throw new AssetValidationError("UPLOAD_FAILED", "s3PresignedAdapter: presign response was not JSON.", {
|
|
68
|
+
cause
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (!isPresignResponse(payload)) throw new AssetValidationError("UPLOAD_FAILED", "s3PresignedAdapter: presign response missing `url`.");
|
|
72
|
+
return payload;
|
|
73
|
+
}
|
|
74
|
+
async function putToS3(file, presign, fetchImpl, signal) {
|
|
75
|
+
const headers = {
|
|
76
|
+
...file.type ? {
|
|
77
|
+
"Content-Type": file.type
|
|
78
|
+
} : {},
|
|
79
|
+
...presign.headers ?? {}
|
|
80
|
+
};
|
|
81
|
+
let response;
|
|
82
|
+
try {
|
|
83
|
+
response = await fetchImpl(presign.url, {
|
|
84
|
+
method: "PUT",
|
|
85
|
+
body: file,
|
|
86
|
+
headers,
|
|
87
|
+
...signal ? {
|
|
88
|
+
signal
|
|
89
|
+
} : {}
|
|
90
|
+
});
|
|
91
|
+
} catch (cause) {
|
|
92
|
+
throw new RetryableError(`s3PresignedAdapter: PUT failed (${describeError(cause)}).`, {
|
|
93
|
+
cause
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (response.status >= 500) throw new RetryableError(`s3PresignedAdapter: PUT returned ${response.status}.`, {
|
|
97
|
+
retryAfterMs: parseRetryAfter(response.headers.get("retry-after"))
|
|
98
|
+
});
|
|
99
|
+
if (!response.ok) throw new AssetValidationError("UPLOAD_FAILED", `s3PresignedAdapter: PUT returned ${response.status}.`);
|
|
100
|
+
}
|
|
101
|
+
function isPresignResponse(value) {
|
|
102
|
+
return null !== value && "object" == typeof value && "string" == typeof value.url && value.url.length > 0;
|
|
103
|
+
}
|
|
104
|
+
function stripQueryAndFragment(url) {
|
|
105
|
+
const queryIdx = url.indexOf("?");
|
|
106
|
+
const fragmentIdx = url.indexOf("#");
|
|
107
|
+
const cuts = [
|
|
108
|
+
queryIdx,
|
|
109
|
+
fragmentIdx
|
|
110
|
+
].filter((i)=>-1 !== i);
|
|
111
|
+
if (0 === cuts.length) return url;
|
|
112
|
+
return url.slice(0, Math.min(...cuts));
|
|
113
|
+
}
|
|
114
|
+
function parseRetryAfter(header) {
|
|
115
|
+
if (null === header) return;
|
|
116
|
+
const seconds = Number(header);
|
|
117
|
+
if (Number.isFinite(seconds) && seconds >= 0) return 1000 * seconds;
|
|
118
|
+
const date = Date.parse(header);
|
|
119
|
+
if (!Number.isNaN(date)) return Math.max(0, date - Date.now());
|
|
120
|
+
}
|
|
121
|
+
function describeError(error) {
|
|
122
|
+
if (error instanceof Error) return error.message || error.name;
|
|
123
|
+
return String(error);
|
|
124
|
+
}
|
|
125
|
+
function defaultIdGenerator() {
|
|
126
|
+
if (void 0 !== globalThis.crypto && "function" == typeof globalThis.crypto.randomUUID) return globalThis.crypto.randomUUID();
|
|
127
|
+
return `asset-${Math.random().toString(36).slice(2)}-${Date.now()}`;
|
|
128
|
+
}
|
|
129
|
+
export { RetryableError, s3PresignedAdapter };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
createAssetReference: ()=>createAssetReference
|
|
28
|
+
});
|
|
29
|
+
function createAssetReference(id) {
|
|
30
|
+
return `asset://${id}`;
|
|
31
|
+
}
|
|
32
|
+
exports.createAssetReference = __webpack_exports__.createAssetReference;
|
|
33
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
34
|
+
"createAssetReference"
|
|
35
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
36
|
+
Object.defineProperty(exports, '__esModule', {
|
|
37
|
+
value: true
|
|
38
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Canonical `asset://${id}` reference helper.
|
|
3
|
+
*
|
|
4
|
+
* Lives in its own file so both `plugin.ts` (which dispatches asset
|
|
5
|
+
* references into Puck data) and `studio-asset-source.ts` (which
|
|
6
|
+
* surfaces the URL to the sidebar's `image` module) can reuse it
|
|
7
|
+
* without creating a circular import between them.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createAssetReference(id: string): string;
|
|
10
|
+
//# sourceMappingURL=asset-reference.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-reference.d.cts","sourceRoot":"","sources":["../src/asset-reference.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEvD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Canonical `asset://${id}` reference helper.
|
|
3
|
+
*
|
|
4
|
+
* Lives in its own file so both `plugin.ts` (which dispatches asset
|
|
5
|
+
* references into Puck data) and `studio-asset-source.ts` (which
|
|
6
|
+
* surfaces the URL to the sidebar's `image` module) can reuse it
|
|
7
|
+
* without creating a circular import between them.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createAssetReference(id: string): string;
|
|
10
|
+
//# sourceMappingURL=asset-reference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-reference.d.ts","sourceRoot":"","sources":["../src/asset-reference.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEvD"}
|
package/dist/csp.cjs
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
getRequiredCsp: ()=>getRequiredCsp
|
|
28
|
+
});
|
|
29
|
+
function getRequiredCsp(options = {}) {
|
|
30
|
+
const connectSrc = new Set();
|
|
31
|
+
const imgSrc = new Set();
|
|
32
|
+
const mediaSrc = new Set();
|
|
33
|
+
if (true === options.dataUrl) {
|
|
34
|
+
imgSrc.add("data:");
|
|
35
|
+
mediaSrc.add("data:");
|
|
36
|
+
}
|
|
37
|
+
if (true === options.inMemory) {
|
|
38
|
+
imgSrc.add("blob:");
|
|
39
|
+
mediaSrc.add("blob:");
|
|
40
|
+
}
|
|
41
|
+
const s3List = Array.isArray(options.s3) ? options.s3 : options.s3 ? [
|
|
42
|
+
options.s3
|
|
43
|
+
] : [];
|
|
44
|
+
for (const entry of s3List){
|
|
45
|
+
const presignOrigin = parseOrigin(entry.presignEndpoint);
|
|
46
|
+
if (void 0 !== presignOrigin) connectSrc.add(presignOrigin);
|
|
47
|
+
const publicOrigin = void 0 !== entry.publicHost ? parseOrigin(entry.publicHost) : void 0;
|
|
48
|
+
if (void 0 !== publicOrigin) {
|
|
49
|
+
connectSrc.add(publicOrigin);
|
|
50
|
+
imgSrc.add(publicOrigin);
|
|
51
|
+
mediaSrc.add(publicOrigin);
|
|
52
|
+
} else if (void 0 !== presignOrigin) {
|
|
53
|
+
imgSrc.add(presignOrigin);
|
|
54
|
+
mediaSrc.add(presignOrigin);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return Object.freeze({
|
|
58
|
+
connectSrc: Object.freeze([
|
|
59
|
+
...connectSrc
|
|
60
|
+
]),
|
|
61
|
+
imgSrc: Object.freeze([
|
|
62
|
+
...imgSrc
|
|
63
|
+
]),
|
|
64
|
+
mediaSrc: Object.freeze([
|
|
65
|
+
...mediaSrc
|
|
66
|
+
])
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function parseOrigin(value) {
|
|
70
|
+
const raw = "string" == typeof value ? value : value.toString();
|
|
71
|
+
try {
|
|
72
|
+
return new URL(raw).origin;
|
|
73
|
+
} catch {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.getRequiredCsp = __webpack_exports__.getRequiredCsp;
|
|
78
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
79
|
+
"getRequiredCsp"
|
|
80
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
81
|
+
Object.defineProperty(exports, '__esModule', {
|
|
82
|
+
value: true
|
|
83
|
+
});
|
package/dist/csp.d.cts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file CSP advisor — computes the minimum `connect-src` / `img-src` /
|
|
3
|
+
* `media-src` directives a host page needs in order for the
|
|
4
|
+
* configured adapters and their served URLs to load. Pure static
|
|
5
|
+
* derivation; no network or DOM dependencies.
|
|
6
|
+
*
|
|
7
|
+
* The host calls this once at boot with a description of which
|
|
8
|
+
* adapters are wired in, then merges the result into its existing CSP
|
|
9
|
+
* builder.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const csp = getRequiredCsp({
|
|
13
|
+
* dataUrl: true,
|
|
14
|
+
* s3: { presignEndpoint: "https://uploads.example.com/sign" },
|
|
15
|
+
* });
|
|
16
|
+
* // csp.connectSrc → ["https://uploads.example.com"]
|
|
17
|
+
* // csp.imgSrc → ["data:"]
|
|
18
|
+
* // csp.mediaSrc → ["data:"]
|
|
19
|
+
*/
|
|
20
|
+
export interface S3CspOptions {
|
|
21
|
+
/** The presign endpoint configured on `s3PresignedAdapter`. */
|
|
22
|
+
readonly presignEndpoint: string | URL;
|
|
23
|
+
/**
|
|
24
|
+
* Optional public-bucket origin (e.g. `https://cdn.example.com`).
|
|
25
|
+
* If your `publicUrl` returned by the presign service points at a
|
|
26
|
+
* different host than the presign endpoint itself, list it here so
|
|
27
|
+
* the advisor can include it in `img-src` / `media-src`.
|
|
28
|
+
*/
|
|
29
|
+
readonly publicHost?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface RequiredCspOptions {
|
|
32
|
+
/** True if `dataUrlUploader` is mounted. Defaults to false. */
|
|
33
|
+
readonly dataUrl?: boolean;
|
|
34
|
+
/** True if `inMemoryUploader` is mounted. Defaults to false. */
|
|
35
|
+
readonly inMemory?: boolean;
|
|
36
|
+
/** Description of any `s3PresignedAdapter` instance(s). */
|
|
37
|
+
readonly s3?: S3CspOptions | readonly S3CspOptions[];
|
|
38
|
+
}
|
|
39
|
+
export interface RequiredCsp {
|
|
40
|
+
readonly connectSrc: readonly string[];
|
|
41
|
+
readonly imgSrc: readonly string[];
|
|
42
|
+
readonly mediaSrc: readonly string[];
|
|
43
|
+
}
|
|
44
|
+
export declare function getRequiredCsp(options?: RequiredCspOptions): RequiredCsp;
|
|
45
|
+
//# sourceMappingURL=csp.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csp.d.cts","sourceRoot":"","sources":["../src/csp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,YAAY;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,GAAG,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,kBAAkB;IAClC,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,CAAC,EAAE,YAAY,GAAG,SAAS,YAAY,EAAE,CAAC;CACrD;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,kBAAuB,GAAG,WAAW,CA4C5E"}
|