@revealui/core 0.12.4 → 0.13.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/dist/client/admin/utils/csrf.d.ts +4 -3
- package/dist/client/admin/utils/csrf.d.ts.map +1 -1
- package/dist/client/admin/utils/csrf.js +4 -3
- package/dist/monitoring/alerts.d.ts +6 -1
- package/dist/monitoring/alerts.d.ts.map +1 -1
- package/dist/monitoring/alerts.js +6 -1
- package/dist/observability/alerts.d.ts +7 -2
- package/dist/observability/alerts.d.ts.map +1 -1
- package/dist/observability/alerts.js +7 -2
- package/dist/storage/_sigv4.d.ts +35 -1
- package/dist/storage/_sigv4.d.ts.map +1 -1
- package/dist/storage/_sigv4.js +53 -0
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +2 -3
- package/dist/storage/mock.d.ts +5 -2
- package/dist/storage/mock.d.ts.map +1 -1
- package/dist/storage/mock.js +54 -1
- package/dist/storage/r2.d.ts +6 -4
- package/dist/storage/r2.d.ts.map +1 -1
- package/dist/storage/r2.js +107 -13
- package/dist/storage/types.d.ts +54 -4
- package/dist/storage/types.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CSRF helpers for browser clients (admin, auth hooks, agent stream).
|
|
2
|
+
* CSRF helpers for browser clients (admin, auth hooks, agent stream, sync).
|
|
3
3
|
*
|
|
4
4
|
* Single source of truth for reading the JS-readable `revealui-csrf` cookie
|
|
5
|
-
* (fleet-redundancy P2-C). Consumers: this package's
|
|
6
|
-
* `@revealui/auth/react` (re-export), `@revealui/ai`
|
|
5
|
+
* (fleet-redundancy P2-C; C12 residual 2026-08-07). Consumers: this package's
|
|
6
|
+
* admin APIClient, `@revealui/auth/react` (re-export), `@revealui/ai`
|
|
7
|
+
* useAgentStream, `@revealui/sync` csrfHeaders, and apps/admin `apiFetch`.
|
|
7
8
|
*
|
|
8
9
|
* The admin proxy and the api server's csrfMiddleware require any unsafe
|
|
9
10
|
* request carrying a `revealui-session` cookie to echo this cookie as an
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/utils/csrf.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/utils/csrf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,GAAG,SAAS,CAgBlD;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC,CAOrD"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CSRF helpers for browser clients (admin, auth hooks, agent stream).
|
|
2
|
+
* CSRF helpers for browser clients (admin, auth hooks, agent stream, sync).
|
|
3
3
|
*
|
|
4
4
|
* Single source of truth for reading the JS-readable `revealui-csrf` cookie
|
|
5
|
-
* (fleet-redundancy P2-C). Consumers: this package's
|
|
6
|
-
* `@revealui/auth/react` (re-export), `@revealui/ai`
|
|
5
|
+
* (fleet-redundancy P2-C; C12 residual 2026-08-07). Consumers: this package's
|
|
6
|
+
* admin APIClient, `@revealui/auth/react` (re-export), `@revealui/ai`
|
|
7
|
+
* useAgentStream, `@revealui/sync` csrfHeaders, and apps/admin `apiFetch`.
|
|
7
8
|
*
|
|
8
9
|
* The admin proxy and the api server's csrfMiddleware require any unsafe
|
|
9
10
|
* request carrying a `revealui-session` cookie to echo this cookie as an
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Alert System
|
|
2
|
+
* Alert System (monitoring / process-health plane)
|
|
3
3
|
*
|
|
4
4
|
* Manages alert channels (logger, Sentry, console) and alert delivery.
|
|
5
5
|
* Provides configurable thresholds and aggregation for production.
|
|
6
|
+
*
|
|
7
|
+
* Ownership (ADR 2026-08-07-core-alert-planes): this is the **monitoring**
|
|
8
|
+
* plane (`sendAlert`). Rule/threshold lifecycle lives in
|
|
9
|
+
* `observability/alerts` (`AlertingSystem`). Cron failures use only
|
|
10
|
+
* `observability/cron-failure-alert`. Do not reimplement a fourth path.
|
|
6
11
|
*/
|
|
7
12
|
import type { Alert } from './types.js';
|
|
8
13
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../../src/monitoring/alerts.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../../src/monitoring/alerts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;GAEG;AACH,UAAU,YAAY;IACpB,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAClC;AAsCD;;GAEG;AACH,KAAK,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEpD;;GAEG;AACH,UAAU,WAAW;IACnB,uBAAuB;IACvB,QAAQ,EAAE,YAAY,EAAE,CAAC;IAEzB,kFAAkF;IAClF,qBAAqB,EAAE,OAAO,CAAC;IAE/B,2CAA2C;IAC3C,mBAAmB,EAAE,MAAM,CAAC;IAE5B,uCAAuC;IACvC,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAYD;;GAEG;AACH,cAAM,YAAY;IAChB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,UAAU,CAAe;IACjC,OAAO,CAAC,gBAAgB,CAA+B;IACvD,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,YAAY,CAA6B;gBAErC,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM,EAAE,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI;IAUjF;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAU7B;;OAEG;IACH,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;IAMjC;;OAEG;IACH,OAAO,CAAC,YAAY;IAoBpB;;OAEG;IACH,OAAO,CAAC,YAAY;IAuBpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAYrB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmEpB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAaxB;;OAEG;IACH,OAAO,CAAC,WAAW;IAwCnB;;OAEG;IACH,eAAe,IAAI,IAAI;IAOvB;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,QAAQ,IAAI;QACV,SAAS,EAAE,MAAM,CAAC;QAClB,mBAAmB,EAAE,MAAM,CAAC;QAC5B,kBAAkB,EAAE,OAAO,CAAC;KAC7B;IAQD;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IAI3C;;OAEG;IACH,OAAO,IAAI,IAAI;CAIhB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,cAAqB,CAAC;AAE/C;;GAEG;AACH,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;AAC3C;;GAEG;AACH,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;GAEG;AAEH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAE5C;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAEhD;AAED,wBAAgB,aAAa,IAAI,UAAU,CAAC,OAAO,YAAY,CAAC,QAAQ,CAAC,CAExE;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI,CAE/D"}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Alert System
|
|
2
|
+
* Alert System (monitoring / process-health plane)
|
|
3
3
|
*
|
|
4
4
|
* Manages alert channels (logger, Sentry, console) and alert delivery.
|
|
5
5
|
* Provides configurable thresholds and aggregation for production.
|
|
6
|
+
*
|
|
7
|
+
* Ownership (ADR 2026-08-07-core-alert-planes): this is the **monitoring**
|
|
8
|
+
* plane (`sendAlert`). Rule/threshold lifecycle lives in
|
|
9
|
+
* `observability/alerts` (`AlertingSystem`). Cron failures use only
|
|
10
|
+
* `observability/cron-failure-alert`. Do not reimplement a fourth path.
|
|
6
11
|
*/
|
|
7
12
|
import { logger } from '../utils/logger-server.js';
|
|
8
13
|
import { getRequestContext } from '../utils/request-context.js';
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Alert System
|
|
2
|
+
* Alert System (observability rule plane)
|
|
3
3
|
*
|
|
4
|
-
* Configure and trigger alerts based on metrics and thresholds
|
|
4
|
+
* Configure and trigger alerts based on metrics and thresholds.
|
|
5
|
+
*
|
|
6
|
+
* Ownership (ADR 2026-08-07-core-alert-planes): this is the **observability**
|
|
7
|
+
* plane (`AlertingSystem`). Process/health ops delivery is
|
|
8
|
+
* `monitoring/alerts` (`sendAlert`). Cron failures use only
|
|
9
|
+
* `cron-failure-alert`. Do not reimplement a fourth path.
|
|
5
10
|
*/
|
|
6
11
|
export type AlertSeverity = 'info' | 'warning' | 'error' | 'critical';
|
|
7
12
|
export type AlertStatus = 'firing' | 'resolved';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../../src/observability/alerts.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"alerts.d.ts","sourceRoot":"","sources":["../../src/observability/alerts.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Alert System
|
|
2
|
+
* Alert System (observability rule plane)
|
|
3
3
|
*
|
|
4
|
-
* Configure and trigger alerts based on metrics and thresholds
|
|
4
|
+
* Configure and trigger alerts based on metrics and thresholds.
|
|
5
|
+
*
|
|
6
|
+
* Ownership (ADR 2026-08-07-core-alert-planes): this is the **observability**
|
|
7
|
+
* plane (`AlertingSystem`). Process/health ops delivery is
|
|
8
|
+
* `monitoring/alerts` (`sendAlert`). Cron failures use only
|
|
9
|
+
* `cron-failure-alert`. Do not reimplement a fourth path.
|
|
5
10
|
*/
|
|
6
11
|
import { logger } from './logger.js';
|
|
7
12
|
export class AlertingSystem {
|
package/dist/storage/_sigv4.d.ts
CHANGED
|
@@ -45,9 +45,11 @@ export interface SigV4Result {
|
|
|
45
45
|
* key → signature. Verified against AWS's official `get-vanilla` test vector.
|
|
46
46
|
*/
|
|
47
47
|
export declare function computeSigV4(input: CanonicalInput): SigV4Result;
|
|
48
|
+
/** Payload hash token for presigned URLs (body hash unknown at sign time). */
|
|
49
|
+
export declare const UNSIGNED_PAYLOAD = "UNSIGNED-PAYLOAD";
|
|
48
50
|
/** Inputs for an R2/S3 request signature. */
|
|
49
51
|
export interface SignS3Input {
|
|
50
|
-
method: 'GET' | 'PUT' | 'DELETE';
|
|
52
|
+
method: 'GET' | 'PUT' | 'DELETE' | 'HEAD';
|
|
51
53
|
accountId: string;
|
|
52
54
|
bucket: string;
|
|
53
55
|
/** Object key; omit for bucket-level operations (e.g. ListObjectsV2). */
|
|
@@ -73,4 +75,36 @@ export interface SignedS3Request {
|
|
|
73
75
|
* from the URL (same value), and `Host` is a forbidden header to set manually.
|
|
74
76
|
*/
|
|
75
77
|
export declare function signS3Request(input: SignS3Input): SignedS3Request;
|
|
78
|
+
/** Inputs for a query-string presigned S3/R2 URL (no Authorization header). */
|
|
79
|
+
export interface SignS3PresignedInput {
|
|
80
|
+
method: 'GET' | 'PUT' | 'DELETE' | 'HEAD';
|
|
81
|
+
accountId: string;
|
|
82
|
+
bucket: string;
|
|
83
|
+
key: string;
|
|
84
|
+
region: string;
|
|
85
|
+
accessKeyId: string;
|
|
86
|
+
secretAccessKey: string;
|
|
87
|
+
/** Lifetime of the URL in seconds. */
|
|
88
|
+
expiresInSeconds: number;
|
|
89
|
+
/**
|
|
90
|
+
* Headers the client must send and that are included in the signature
|
|
91
|
+
* (content-type, content-length, …). Host is always signed and omitted
|
|
92
|
+
* from the returned headers (fetch sets it from the URL).
|
|
93
|
+
*/
|
|
94
|
+
signedHeaders?: Record<string, string>;
|
|
95
|
+
now: Date;
|
|
96
|
+
}
|
|
97
|
+
export interface PresignedS3Url {
|
|
98
|
+
url: string;
|
|
99
|
+
/** Headers the client must include (signed set minus host). */
|
|
100
|
+
headers: Record<string, string>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Build a query-string SigV4 presigned URL for R2/S3.
|
|
104
|
+
*
|
|
105
|
+
* Uses UNSIGNED-PAYLOAD so the client does not need to pre-hash the body.
|
|
106
|
+
* Credential and signature ride in the query string; the client sends only
|
|
107
|
+
* the signed non-host headers (e.g. content-type) with the request.
|
|
108
|
+
*/
|
|
109
|
+
export declare function signS3PresignedUrl(input: SignS3PresignedInput): PresignedS3Url;
|
|
76
110
|
//# sourceMappingURL=_sigv4.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_sigv4.d.ts","sourceRoot":"","sources":["../../src/storage/_sigv4.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,iFAAiF;AACjF,eAAO,MAAM,YAAY,qEAAqE,CAAC;AAE/F,gEAAgE;AAChE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAE3D;AAQD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,GAAG,MAAM,CAaxE;AAQD,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,aAAa,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IAC1B,4EAA4E;IAC5E,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,WAAW,CAkC/D;AAED,6CAA6C;AAC7C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"_sigv4.d.ts","sourceRoot":"","sources":["../../src/storage/_sigv4.ts"],"names":[],"mappings":"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"}
|
package/dist/storage/_sigv4.js
CHANGED
|
@@ -81,6 +81,8 @@ export function computeSigV4(input) {
|
|
|
81
81
|
const signature = createHmac('sha256', kSigning).update(stringToSign, 'utf8').digest('hex');
|
|
82
82
|
return { signature, signedHeaders, scope, canonicalQuery };
|
|
83
83
|
}
|
|
84
|
+
/** Payload hash token for presigned URLs (body hash unknown at sign time). */
|
|
85
|
+
export const UNSIGNED_PAYLOAD = 'UNSIGNED-PAYLOAD';
|
|
84
86
|
/**
|
|
85
87
|
* Build a signed R2 request: a path-style URL + AWS4-HMAC-SHA256 Authorization
|
|
86
88
|
* header. The `host` header is signed but not returned — fetch/undici sets it
|
|
@@ -132,3 +134,54 @@ export function signS3Request(input) {
|
|
|
132
134
|
const url = `https://${host}${canonicalPath}${canonicalQuery ? `?${canonicalQuery}` : ''}`;
|
|
133
135
|
return { url, headers };
|
|
134
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Build a query-string SigV4 presigned URL for R2/S3.
|
|
139
|
+
*
|
|
140
|
+
* Uses UNSIGNED-PAYLOAD so the client does not need to pre-hash the body.
|
|
141
|
+
* Credential and signature ride in the query string; the client sends only
|
|
142
|
+
* the signed non-host headers (e.g. content-type) with the request.
|
|
143
|
+
*/
|
|
144
|
+
export function signS3PresignedUrl(input) {
|
|
145
|
+
const host = `${input.accountId}.r2.cloudflarestorage.com`;
|
|
146
|
+
const { amzDate, dateStamp } = toAmzDate(input.now);
|
|
147
|
+
const scope = `${dateStamp}/${input.region}/${S3_SERVICE}/aws4_request`;
|
|
148
|
+
const encodedKey = input.key
|
|
149
|
+
.split('/')
|
|
150
|
+
.map((segment) => awsUriEncode(segment, false))
|
|
151
|
+
.join('/');
|
|
152
|
+
const canonicalPath = `/${awsUriEncode(input.bucket, false)}/${encodedKey}`;
|
|
153
|
+
const clientHeaders = {};
|
|
154
|
+
const headersToSign = { host };
|
|
155
|
+
for (const [name, value] of Object.entries(input.signedHeaders ?? {})) {
|
|
156
|
+
const lower = name.toLowerCase();
|
|
157
|
+
if (lower === 'host')
|
|
158
|
+
continue;
|
|
159
|
+
headersToSign[lower] = value;
|
|
160
|
+
clientHeaders[lower] = value;
|
|
161
|
+
}
|
|
162
|
+
const signedHeaderNames = Object.keys(headersToSign).sort().join(';');
|
|
163
|
+
const query = [
|
|
164
|
+
['X-Amz-Algorithm', ALGORITHM],
|
|
165
|
+
['X-Amz-Credential', `${input.accessKeyId}/${scope}`],
|
|
166
|
+
['X-Amz-Date', amzDate],
|
|
167
|
+
['X-Amz-Expires', String(input.expiresInSeconds)],
|
|
168
|
+
['X-Amz-SignedHeaders', signedHeaderNames],
|
|
169
|
+
];
|
|
170
|
+
const { signature, canonicalQuery } = computeSigV4({
|
|
171
|
+
method: input.method,
|
|
172
|
+
canonicalPath,
|
|
173
|
+
query,
|
|
174
|
+
headersToSign,
|
|
175
|
+
payloadHash: UNSIGNED_PAYLOAD,
|
|
176
|
+
amzDate,
|
|
177
|
+
region: input.region,
|
|
178
|
+
service: S3_SERVICE,
|
|
179
|
+
accessKeyId: input.accessKeyId,
|
|
180
|
+
secretAccessKey: input.secretAccessKey,
|
|
181
|
+
});
|
|
182
|
+
const fullQuery = `${canonicalQuery}&${awsUriEncode('X-Amz-Signature', true)}=${awsUriEncode(signature, true)}`;
|
|
183
|
+
return {
|
|
184
|
+
url: `https://${host}${canonicalPath}?${fullQuery}`,
|
|
185
|
+
headers: clientHeaders,
|
|
186
|
+
};
|
|
187
|
+
}
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { createMockProvider } from './mock.js';
|
|
|
3
3
|
export type { ObjectStorageConfig } from './object-storage.js';
|
|
4
4
|
export { objectStorage } from './object-storage.js';
|
|
5
5
|
export { createR2Provider } from './r2.js';
|
|
6
|
-
export type { ListItem, ListOptions, ListResult, PutOptions, PutResult, R2Config, StorageConfig, StorageProvider, } from './types.js';
|
|
6
|
+
export type { HeadObjectResult, ListItem, ListOptions, ListResult, PresignPutOptions, PresignPutResult, PutOptions, PutResult, R2Config, StorageConfig, StorageProvider, } from './types.js';
|
|
7
7
|
/**
|
|
8
8
|
* Construct a StorageProvider from a tagged config.
|
|
9
9
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAK/D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,YAAY,EACV,gBAAgB,EAChB,QAAQ,EACR,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,QAAQ,EACR,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,eAAe,CAcpE"}
|
package/dist/storage/index.js
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
//
|
|
4
4
|
// Phase 1 (#959): types.ts + index.ts type re-exports.
|
|
5
5
|
// Phase 2a (#959 follow-up): r2 + mock providers + createStorage factory.
|
|
6
|
-
// Phase 2b
|
|
7
|
-
//
|
|
8
|
-
// every production environment — R2 is now the sole non-mock backend.
|
|
6
|
+
// Phase 2b media-route cutover onto R2 (server) + #1644 Vercel Blob removal.
|
|
7
|
+
// Phase 2b presign (GAP-215): createPresignedPutUrl + headObject + getObjectRange.
|
|
9
8
|
import { createMockProvider } from './mock.js';
|
|
10
9
|
import { createR2Provider } from './r2.js';
|
|
11
10
|
export { createMockProvider } from './mock.js';
|
package/dist/storage/mock.d.ts
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* `mock://` scheme so callers can distinguish mock results from real ones
|
|
9
9
|
* without parsing host names.
|
|
10
10
|
*
|
|
11
|
-
* GAP-208 Phase 2a (2026-05-18).
|
|
11
|
+
* GAP-208 Phase 2a (2026-05-18). Phase 2b (GAP-215): presigned PUT + head + range.
|
|
12
12
|
*/
|
|
13
|
-
import type { ListOptions, ListResult, PutOptions, PutResult, StorageProvider } from './types.js';
|
|
13
|
+
import type { HeadObjectResult, ListOptions, ListResult, PresignPutOptions, PresignPutResult, PutOptions, PutResult, StorageProvider } from './types.js';
|
|
14
14
|
interface MockEntry {
|
|
15
15
|
body: Uint8Array;
|
|
16
16
|
contentType: string;
|
|
@@ -22,6 +22,9 @@ declare class MockProvider implements StorageProvider {
|
|
|
22
22
|
readonly provider = "mock";
|
|
23
23
|
private readonly store;
|
|
24
24
|
put(key: string, data: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array>, opts?: PutOptions): Promise<PutResult>;
|
|
25
|
+
createPresignedPutUrl(opts: PresignPutOptions): Promise<PresignPutResult>;
|
|
26
|
+
headObject(key: string): Promise<HeadObjectResult>;
|
|
27
|
+
getObjectRange(key: string, start: number, endInclusive: number): Promise<Uint8Array>;
|
|
25
28
|
del(keyOrUrl: string): Promise<void>;
|
|
26
29
|
list(opts?: ListOptions): Promise<ListResult>;
|
|
27
30
|
/** Test helper — read the raw bytes back. Not part of StorageProvider. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/storage/mock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/storage/mock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EACV,gBAAgB,EAEhB,WAAW,EACX,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,eAAe,EAChB,MAAM,YAAY,CAAC;AAOpB,UAAU,SAAS;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,UAAU,EAAE,IAAI,CAAC;CAClB;AAED,cAAM,YAAa,YAAW,eAAe;IAC3C,QAAQ,CAAC,QAAQ,UAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IAEhD,GAAG,CACP,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,EAClE,IAAI,CAAC,EAAE,UAAU,GAChB,OAAO,CAAC,SAAS,CAAC;IAiBf,qBAAqB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA6BzE,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAYlD,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAkBrF,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpC,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAgCnD,0EAA0E;IAC1E,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAIzC,wEAAwE;IACxE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAI3C,0EAA0E;IAC1E,IAAI,IAAI,MAAM;IAId,0EAA0E;IAC1E,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,UAAU;CAMnB;AAED,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD;AAED,YAAY,EAAE,YAAY,EAAE,CAAC"}
|
package/dist/storage/mock.js
CHANGED
|
@@ -8,12 +8,13 @@
|
|
|
8
8
|
* `mock://` scheme so callers can distinguish mock results from real ones
|
|
9
9
|
* without parsing host names.
|
|
10
10
|
*
|
|
11
|
-
* GAP-208 Phase 2a (2026-05-18).
|
|
11
|
+
* GAP-208 Phase 2a (2026-05-18). Phase 2b (GAP-215): presigned PUT + head + range.
|
|
12
12
|
*/
|
|
13
13
|
import { toUint8Array } from './_helpers.js';
|
|
14
14
|
const PROVIDER_TAG = 'mock';
|
|
15
15
|
const MOCK_URL_SCHEME = 'mock://storage';
|
|
16
16
|
const DEFAULT_LIST_LIMIT = 1000;
|
|
17
|
+
const DEFAULT_PRESIGN_EXPIRES_SECONDS = 900;
|
|
17
18
|
class MockProvider {
|
|
18
19
|
provider = PROVIDER_TAG;
|
|
19
20
|
store = new Map();
|
|
@@ -33,6 +34,58 @@ class MockProvider {
|
|
|
33
34
|
provider: PROVIDER_TAG,
|
|
34
35
|
};
|
|
35
36
|
}
|
|
37
|
+
async createPresignedPutUrl(opts) {
|
|
38
|
+
const expiresInSeconds = opts.expiresInSeconds ?? DEFAULT_PRESIGN_EXPIRES_SECONDS;
|
|
39
|
+
if (expiresInSeconds <= 0) {
|
|
40
|
+
throw new Error('createPresignedPutUrl: expiresInSeconds must be positive');
|
|
41
|
+
}
|
|
42
|
+
const now = new Date();
|
|
43
|
+
const expiresAt = new Date(now.getTime() + expiresInSeconds * 1000);
|
|
44
|
+
const headers = {
|
|
45
|
+
'content-type': opts.contentType,
|
|
46
|
+
};
|
|
47
|
+
if (opts.contentLength !== undefined) {
|
|
48
|
+
headers['content-length'] = String(opts.contentLength);
|
|
49
|
+
}
|
|
50
|
+
// Synthetic presigned URL. Tests that exercise the full client flow call
|
|
51
|
+
// put() with the same key after "uploading"; route tests mock this method.
|
|
52
|
+
const params = new URLSearchParams({
|
|
53
|
+
expires: String(Math.floor(expiresAt.getTime() / 1000)),
|
|
54
|
+
'content-type': opts.contentType,
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
url: `${MOCK_URL_SCHEME}/presign/${opts.key}?${params.toString()}`,
|
|
58
|
+
headers,
|
|
59
|
+
key: opts.key,
|
|
60
|
+
expiresAt,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async headObject(key) {
|
|
64
|
+
const entry = this.store.get(key);
|
|
65
|
+
if (!entry) {
|
|
66
|
+
throw new Error(`mock HEAD failed for "${key}": NoSuchKey object not found`);
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
size: entry.body.byteLength,
|
|
70
|
+
contentType: entry.contentType,
|
|
71
|
+
url: `${MOCK_URL_SCHEME}/${key}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async getObjectRange(key, start, endInclusive) {
|
|
75
|
+
if (start < 0 || endInclusive < start) {
|
|
76
|
+
throw new Error(`getObjectRange: invalid range ${start}-${endInclusive} (start must be >= 0 and endInclusive >= start)`);
|
|
77
|
+
}
|
|
78
|
+
const entry = this.store.get(key);
|
|
79
|
+
if (!entry) {
|
|
80
|
+
throw new Error(`mock GET range failed for "${key}": NoSuchKey object not found`);
|
|
81
|
+
}
|
|
82
|
+
// Inclusive end, clamped to body length (mirrors S3 range semantics).
|
|
83
|
+
const end = Math.min(endInclusive, entry.body.byteLength - 1);
|
|
84
|
+
if (start >= entry.body.byteLength) {
|
|
85
|
+
return new Uint8Array(0);
|
|
86
|
+
}
|
|
87
|
+
return entry.body.slice(start, end + 1);
|
|
88
|
+
}
|
|
36
89
|
async del(keyOrUrl) {
|
|
37
90
|
const key = this.extractKey(keyOrUrl);
|
|
38
91
|
this.store.delete(key);
|
package/dist/storage/r2.d.ts
CHANGED
|
@@ -12,13 +12,15 @@
|
|
|
12
12
|
*
|
|
13
13
|
* GAP-208 Phase 2a (2026-05-18). Phase 1 (interface + types) shipped in #959.
|
|
14
14
|
* Native client (dropping @aws-sdk/client-s3) landed 2026-06-09.
|
|
15
|
+
* Phase 2b (GAP-215): createPresignedPutUrl + headObject + getObjectRange for
|
|
16
|
+
* direct-to-R2 media uploads.
|
|
15
17
|
*
|
|
16
18
|
* Server-only. Do NOT import from client-side code or edge runtime.
|
|
17
19
|
*
|
|
18
|
-
* Known limitation
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* Known limitation: request bodies for server-side put() are buffered fully in
|
|
21
|
+
* memory (see toUint8Array) so the payload can be hashed for SigV4. Streaming
|
|
22
|
+
* uploads (STREAMING-AWS4-HMAC-SHA256-PAYLOAD) are a future enhancement.
|
|
23
|
+
* Direct client uploads use createPresignedPutUrl and never buffer in the API.
|
|
22
24
|
*/
|
|
23
25
|
import type { R2Config, StorageProvider } from './types.js';
|
|
24
26
|
export declare function createR2Provider(config: R2Config): StorageProvider;
|
package/dist/storage/r2.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../../src/storage/r2.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"r2.d.ts","sourceRoot":"","sources":["../../src/storage/r2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EASV,QAAQ,EACR,eAAe,EAChB,MAAM,YAAY,CAAC;AA6QpB,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,eAAe,CAElE"}
|
package/dist/storage/r2.js
CHANGED
|
@@ -12,20 +12,23 @@
|
|
|
12
12
|
*
|
|
13
13
|
* GAP-208 Phase 2a (2026-05-18). Phase 1 (interface + types) shipped in #959.
|
|
14
14
|
* Native client (dropping @aws-sdk/client-s3) landed 2026-06-09.
|
|
15
|
+
* Phase 2b (GAP-215): createPresignedPutUrl + headObject + getObjectRange for
|
|
16
|
+
* direct-to-R2 media uploads.
|
|
15
17
|
*
|
|
16
18
|
* Server-only. Do NOT import from client-side code or edge runtime.
|
|
17
19
|
*
|
|
18
|
-
* Known limitation
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* Known limitation: request bodies for server-side put() are buffered fully in
|
|
21
|
+
* memory (see toUint8Array) so the payload can be hashed for SigV4. Streaming
|
|
22
|
+
* uploads (STREAMING-AWS4-HMAC-SHA256-PAYLOAD) are a future enhancement.
|
|
23
|
+
* Direct client uploads use createPresignedPutUrl and never buffer in the API.
|
|
22
24
|
*/
|
|
23
25
|
import { toUint8Array } from './_helpers.js';
|
|
24
|
-
import { EMPTY_SHA256, sha256Hex, signS3Request } from './_sigv4.js';
|
|
26
|
+
import { EMPTY_SHA256, sha256Hex, signS3PresignedUrl, signS3Request } from './_sigv4.js';
|
|
25
27
|
import { parseListObjectsV2, s3ErrorFields } from './_xml.js';
|
|
26
28
|
const PROVIDER_TAG = 'r2';
|
|
27
29
|
const DEFAULT_CONTENT_TYPE = 'application/octet-stream';
|
|
28
30
|
const DEFAULT_LIST_LIMIT = 1000;
|
|
31
|
+
const DEFAULT_PRESIGN_EXPIRES_SECONDS = 900;
|
|
29
32
|
const REGION = 'auto';
|
|
30
33
|
class R2Provider {
|
|
31
34
|
provider = PROVIDER_TAG;
|
|
@@ -36,9 +39,9 @@ class R2Provider {
|
|
|
36
39
|
publicBaseUrl;
|
|
37
40
|
constructor(config) {
|
|
38
41
|
if (!config.publicBaseUrl) {
|
|
39
|
-
throw new Error('R2 provider requires R2Config.publicBaseUrl
|
|
40
|
-
'
|
|
41
|
-
"
|
|
42
|
+
throw new Error('R2 provider requires R2Config.publicBaseUrl for public media URLs after ' +
|
|
43
|
+
'upload. Set publicBaseUrl to either a bound custom domain ' +
|
|
44
|
+
"(e.g. 'https://media.revealui.com') or the R2 dev URL " +
|
|
42
45
|
"('https://<account-id>.r2.cloudflarestorage.com/<bucket>').");
|
|
43
46
|
}
|
|
44
47
|
this.accountId = config.accountId;
|
|
@@ -49,9 +52,9 @@ class R2Provider {
|
|
|
49
52
|
}
|
|
50
53
|
async put(key, data, opts) {
|
|
51
54
|
if (opts?.access === 'private') {
|
|
52
|
-
throw new Error("R2 provider
|
|
53
|
-
'
|
|
54
|
-
'
|
|
55
|
+
throw new Error("R2 provider does not support access: 'private' for put(). Use " +
|
|
56
|
+
'createPresignedPutUrl for client direct uploads; public object URLs ' +
|
|
57
|
+
'still use publicBaseUrl after confirm.');
|
|
55
58
|
}
|
|
56
59
|
const body = await toUint8Array(data);
|
|
57
60
|
const extraHeaders = {
|
|
@@ -90,11 +93,99 @@ class R2Provider {
|
|
|
90
93
|
}
|
|
91
94
|
return {
|
|
92
95
|
key,
|
|
93
|
-
url:
|
|
96
|
+
url: this.objectPublicUrl(key),
|
|
94
97
|
size: body.byteLength,
|
|
95
98
|
provider: PROVIDER_TAG,
|
|
96
99
|
};
|
|
97
100
|
}
|
|
101
|
+
async createPresignedPutUrl(opts) {
|
|
102
|
+
const expiresInSeconds = opts.expiresInSeconds ?? DEFAULT_PRESIGN_EXPIRES_SECONDS;
|
|
103
|
+
if (expiresInSeconds <= 0) {
|
|
104
|
+
throw new Error('createPresignedPutUrl: expiresInSeconds must be positive');
|
|
105
|
+
}
|
|
106
|
+
const signedHeaders = {
|
|
107
|
+
'content-type': opts.contentType,
|
|
108
|
+
};
|
|
109
|
+
if (opts.contentLength !== undefined) {
|
|
110
|
+
signedHeaders['content-length'] = String(opts.contentLength);
|
|
111
|
+
}
|
|
112
|
+
const now = new Date();
|
|
113
|
+
const { url, headers } = signS3PresignedUrl({
|
|
114
|
+
method: 'PUT',
|
|
115
|
+
accountId: this.accountId,
|
|
116
|
+
bucket: this.bucket,
|
|
117
|
+
key: opts.key,
|
|
118
|
+
region: REGION,
|
|
119
|
+
accessKeyId: this.accessKeyId,
|
|
120
|
+
secretAccessKey: this.secretAccessKey,
|
|
121
|
+
expiresInSeconds,
|
|
122
|
+
signedHeaders,
|
|
123
|
+
now,
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
url,
|
|
127
|
+
headers,
|
|
128
|
+
key: opts.key,
|
|
129
|
+
expiresAt: new Date(now.getTime() + expiresInSeconds * 1000),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
async headObject(key) {
|
|
133
|
+
const { url, headers } = signS3Request({
|
|
134
|
+
method: 'HEAD',
|
|
135
|
+
accountId: this.accountId,
|
|
136
|
+
bucket: this.bucket,
|
|
137
|
+
key,
|
|
138
|
+
region: REGION,
|
|
139
|
+
accessKeyId: this.accessKeyId,
|
|
140
|
+
secretAccessKey: this.secretAccessKey,
|
|
141
|
+
payloadHash: EMPTY_SHA256,
|
|
142
|
+
now: new Date(),
|
|
143
|
+
});
|
|
144
|
+
const response = await fetch(url, { method: 'HEAD', headers });
|
|
145
|
+
if (response.status === 404) {
|
|
146
|
+
throw new Error(`R2 HEAD failed for "${key}": NoSuchKey object not found`);
|
|
147
|
+
}
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
throw await storageError('HEAD', key, response);
|
|
150
|
+
}
|
|
151
|
+
const lengthHeader = response.headers.get('content-length');
|
|
152
|
+
const size = lengthHeader === null ? 0 : Number(lengthHeader);
|
|
153
|
+
if (!Number.isFinite(size) || size < 0) {
|
|
154
|
+
throw new Error(`R2 HEAD failed for "${key}": invalid content-length`);
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
size,
|
|
158
|
+
contentType: response.headers.get('content-type') ?? DEFAULT_CONTENT_TYPE,
|
|
159
|
+
url: this.objectPublicUrl(key),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
async getObjectRange(key, start, endInclusive) {
|
|
163
|
+
if (start < 0 || endInclusive < start) {
|
|
164
|
+
throw new Error(`getObjectRange: invalid range ${start}-${endInclusive} (start must be >= 0 and endInclusive >= start)`);
|
|
165
|
+
}
|
|
166
|
+
const { url, headers } = signS3Request({
|
|
167
|
+
method: 'GET',
|
|
168
|
+
accountId: this.accountId,
|
|
169
|
+
bucket: this.bucket,
|
|
170
|
+
key,
|
|
171
|
+
region: REGION,
|
|
172
|
+
accessKeyId: this.accessKeyId,
|
|
173
|
+
secretAccessKey: this.secretAccessKey,
|
|
174
|
+
payloadHash: EMPTY_SHA256,
|
|
175
|
+
extraHeaders: { range: `bytes=${start}-${endInclusive}` },
|
|
176
|
+
now: new Date(),
|
|
177
|
+
});
|
|
178
|
+
const response = await fetch(url, { method: 'GET', headers });
|
|
179
|
+
if (response.status === 404) {
|
|
180
|
+
throw new Error(`R2 GET range failed for "${key}": NoSuchKey object not found`);
|
|
181
|
+
}
|
|
182
|
+
// 206 Partial Content is the expected success; some backends return 200
|
|
183
|
+
// with the full object when range is unsupported — still accept it.
|
|
184
|
+
if (!response.ok && response.status !== 206) {
|
|
185
|
+
throw await storageError('GET range', key, response);
|
|
186
|
+
}
|
|
187
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
188
|
+
}
|
|
98
189
|
async del(keyOrUrl) {
|
|
99
190
|
const key = this.extractKey(keyOrUrl);
|
|
100
191
|
const { url, headers } = signS3Request({
|
|
@@ -139,7 +230,7 @@ class R2Provider {
|
|
|
139
230
|
const parsed = parseListObjectsV2(await response.text());
|
|
140
231
|
const items = parsed.objects.map((entry) => ({
|
|
141
232
|
key: entry.key,
|
|
142
|
-
url:
|
|
233
|
+
url: this.objectPublicUrl(entry.key),
|
|
143
234
|
size: entry.size,
|
|
144
235
|
uploadedAt: entry.lastModified,
|
|
145
236
|
}));
|
|
@@ -149,6 +240,9 @@ class R2Provider {
|
|
|
149
240
|
hasMore: parsed.isTruncated,
|
|
150
241
|
};
|
|
151
242
|
}
|
|
243
|
+
objectPublicUrl(key) {
|
|
244
|
+
return `${this.publicBaseUrl}/${key}`;
|
|
245
|
+
}
|
|
152
246
|
extractKey(keyOrUrl) {
|
|
153
247
|
const parsed = tryParseUrl(keyOrUrl);
|
|
154
248
|
if (!parsed) {
|
package/dist/storage/types.d.ts
CHANGED
|
@@ -20,9 +20,58 @@ export interface StorageProvider {
|
|
|
20
20
|
del(keyOrUrl: string): Promise<void>;
|
|
21
21
|
/** List items, optionally filtered by key prefix. Used by health probes + admin browsing. */
|
|
22
22
|
list(opts?: ListOptions): Promise<ListResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Issue a short-lived presigned PUT URL so clients upload bytes direct to the
|
|
25
|
+
* backend (GAP-215 / Phase 2b). File bytes never buffer in the API function.
|
|
26
|
+
*/
|
|
27
|
+
createPresignedPutUrl(opts: PresignPutOptions): Promise<PresignPutResult>;
|
|
28
|
+
/**
|
|
29
|
+
* HEAD an object. Used by the media confirm endpoint to re-check size and
|
|
30
|
+
* content-type after a direct-to-storage upload.
|
|
31
|
+
*/
|
|
32
|
+
headObject(key: string): Promise<HeadObjectResult>;
|
|
33
|
+
/**
|
|
34
|
+
* GET a byte range of an object (inclusive end). Used to re-check magic
|
|
35
|
+
* bytes on confirm without downloading the whole file.
|
|
36
|
+
*/
|
|
37
|
+
getObjectRange(key: string, start: number, endInclusive: number): Promise<Uint8Array>;
|
|
23
38
|
/** Provider tag (e.g. "r2", "mock") — exposed so consumers can adapt URL handling. */
|
|
24
39
|
readonly provider: string;
|
|
25
40
|
}
|
|
41
|
+
export interface PresignPutOptions {
|
|
42
|
+
/** Storage key the client will write (provider-relative, e.g. "media/uuid.jpg"). */
|
|
43
|
+
key: string;
|
|
44
|
+
/** MIME type the client must send as Content-Type (signed into the URL). */
|
|
45
|
+
contentType: string;
|
|
46
|
+
/**
|
|
47
|
+
* Optional declared Content-Length. When set, signed into the request so the
|
|
48
|
+
* client cannot upload a larger body. Browser fetch cannot set Content-Length
|
|
49
|
+
* manually, so media direct-upload leaves this unset and re-checks size via
|
|
50
|
+
* headObject on confirm.
|
|
51
|
+
*/
|
|
52
|
+
contentLength?: number;
|
|
53
|
+
/** URL lifetime in seconds. Defaults to provider-specific value (typically 900). */
|
|
54
|
+
expiresInSeconds?: number;
|
|
55
|
+
}
|
|
56
|
+
export interface PresignPutResult {
|
|
57
|
+
/** Fully-qualified presigned PUT URL (query-string SigV4). */
|
|
58
|
+
url: string;
|
|
59
|
+
/**
|
|
60
|
+
* Headers the client MUST send with the PUT (at least content-type). Values
|
|
61
|
+
* are already signed into the URL's X-Amz-SignedHeaders set.
|
|
62
|
+
*/
|
|
63
|
+
headers: Record<string, string>;
|
|
64
|
+
/** Storage key the URL writes to (echo of PresignPutOptions.key). */
|
|
65
|
+
key: string;
|
|
66
|
+
/** Absolute expiry of the URL. */
|
|
67
|
+
expiresAt: Date;
|
|
68
|
+
}
|
|
69
|
+
export interface HeadObjectResult {
|
|
70
|
+
size: number;
|
|
71
|
+
contentType: string;
|
|
72
|
+
/** Public (or mock) URL the object is reachable at for GET. */
|
|
73
|
+
url: string;
|
|
74
|
+
}
|
|
26
75
|
export interface PutOptions {
|
|
27
76
|
/** MIME type — written to the object's Content-Type header. Defaults to "application/octet-stream". */
|
|
28
77
|
contentType?: string;
|
|
@@ -93,10 +142,11 @@ export interface R2Config {
|
|
|
93
142
|
/** Bucket name (per-account-globally-unique within R2). */
|
|
94
143
|
bucket: string;
|
|
95
144
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
145
|
+
* Public base URL for objects (e.g. "https://media.revealui.com" if a custom
|
|
146
|
+
* domain is bound, or the R2 dev URL). Required: PutResult.url, HeadObjectResult.url,
|
|
147
|
+
* and media rows after confirm use this base. Presigned PUT URLs themselves
|
|
148
|
+
* target the S3 API endpoint and do not need this, but the final public media
|
|
149
|
+
* URL still does.
|
|
100
150
|
*/
|
|
101
151
|
publicBaseUrl?: string;
|
|
102
152
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,GAAG,CACD,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,EAClE,IAAI,CAAC,EAAE,UAAU,GAChB,OAAO,CAAC,SAAS,CAAC,CAAC;IAEtB,8FAA8F;IAC9F,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErC,6FAA6F;IAC7F,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAE9C,sFAAsF;IACtF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAID,MAAM,WAAW,UAAU;IACzB,uGAAuG;IACvG,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAE9B,oFAAoF;IACpF,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,SAAS;IACxB,4FAA4F;IAC5F,GAAG,EAAE,MAAM,CAAC;IAEZ,8DAA8D;IAC9D,GAAG,EAAE,MAAM,CAAC;IAEZ,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IAEb,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAElB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,IAAI,CAAC;CAClB;AAID;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF,MAAM,WAAW,QAAQ;IACvB,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAElB,qEAAqE;IACrE,WAAW,EAAE,MAAM,CAAC;IAEpB,gEAAgE;IAChE,eAAe,EAAE,MAAM,CAAC;IAExB,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IAEf
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/storage/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revealui/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "RevealUI's runtime engine — admin UI, REST API, auth, rich text, plugin system, and access control. The heart of the open-source platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"dependencies": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"zod": "^4.4.3",
|
|
26
26
|
"@revealui/contracts": "0.8.2",
|
|
27
27
|
"@revealui/resilience": "0.2.4",
|
|
28
|
-
"@revealui/security": "0.
|
|
28
|
+
"@revealui/security": "0.7.0",
|
|
29
29
|
"@revealui/utils": "0.3.6"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|