meridianjs 0.2.5 → 0.2.8
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/README.md +86 -16
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js +7 -0
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/types.js +1 -1
- package/dist/generator/index.d.ts +2 -0
- package/dist/generator/index.d.ts.map +1 -1
- package/dist/generator/index.js +2 -1
- package/dist/generator/index.js.map +1 -1
- package/dist/generator/openapi-export.d.ts +51 -0
- package/dist/generator/openapi-export.d.ts.map +1 -0
- package/dist/generator/openapi-export.js +95 -0
- package/dist/generator/openapi-export.js.map +1 -0
- package/dist/generator/templates.d.ts.map +1 -1
- package/dist/generator/templates.js +86 -17
- package/dist/generator/templates.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/billdesk/adapter.d.ts +36 -0
- package/dist/providers/billdesk/adapter.d.ts.map +1 -0
- package/dist/providers/billdesk/adapter.js +212 -0
- package/dist/providers/billdesk/adapter.js.map +1 -0
- package/dist/providers/billdesk/index.d.ts +3 -0
- package/dist/providers/billdesk/index.d.ts.map +1 -0
- package/dist/providers/billdesk/index.js +3 -0
- package/dist/providers/billdesk/index.js.map +1 -0
- package/dist/providers/billdesk/pagination.d.ts +15 -0
- package/dist/providers/billdesk/pagination.d.ts.map +1 -0
- package/dist/providers/billdesk/pagination.js +51 -0
- package/dist/providers/billdesk/pagination.js.map +1 -0
- package/dist/providers/ccavenue/adapter.d.ts +38 -0
- package/dist/providers/ccavenue/adapter.d.ts.map +1 -0
- package/dist/providers/ccavenue/adapter.js +181 -0
- package/dist/providers/ccavenue/adapter.js.map +1 -0
- package/dist/providers/ccavenue/index.d.ts +3 -0
- package/dist/providers/ccavenue/index.d.ts.map +1 -0
- package/dist/providers/ccavenue/index.js +3 -0
- package/dist/providers/ccavenue/index.js.map +1 -0
- package/dist/providers/ccavenue/pagination.d.ts +16 -0
- package/dist/providers/ccavenue/pagination.d.ts.map +1 -0
- package/dist/providers/ccavenue/pagination.js +20 -0
- package/dist/providers/ccavenue/pagination.js.map +1 -0
- package/dist/providers/datadog/adapter.d.ts +30 -0
- package/dist/providers/datadog/adapter.d.ts.map +1 -0
- package/dist/providers/datadog/adapter.js +163 -0
- package/dist/providers/datadog/adapter.js.map +1 -0
- package/dist/providers/datadog/index.d.ts +3 -0
- package/dist/providers/datadog/index.d.ts.map +1 -0
- package/dist/providers/datadog/index.js +3 -0
- package/dist/providers/datadog/index.js.map +1 -0
- package/dist/providers/datadog/pagination.d.ts +16 -0
- package/dist/providers/datadog/pagination.d.ts.map +1 -0
- package/dist/providers/datadog/pagination.js +41 -0
- package/dist/providers/datadog/pagination.js.map +1 -0
- package/dist/providers/googlemaps/adapter.d.ts +17 -0
- package/dist/providers/googlemaps/adapter.d.ts.map +1 -0
- package/dist/providers/googlemaps/adapter.js +154 -0
- package/dist/providers/googlemaps/adapter.js.map +1 -0
- package/dist/providers/googlemaps/pagination.d.ts +17 -0
- package/dist/providers/googlemaps/pagination.d.ts.map +1 -0
- package/dist/providers/googlemaps/pagination.js +36 -0
- package/dist/providers/googlemaps/pagination.js.map +1 -0
- package/dist/providers/s3/adapter.d.ts +37 -0
- package/dist/providers/s3/adapter.d.ts.map +1 -0
- package/dist/providers/s3/adapter.js +206 -0
- package/dist/providers/s3/adapter.js.map +1 -0
- package/dist/providers/s3/index.d.ts +4 -0
- package/dist/providers/s3/index.d.ts.map +1 -0
- package/dist/providers/s3/index.js +4 -0
- package/dist/providers/s3/index.js.map +1 -0
- package/dist/providers/s3/pagination.d.ts +18 -0
- package/dist/providers/s3/pagination.d.ts.map +1 -0
- package/dist/providers/s3/pagination.js +58 -0
- package/dist/providers/s3/pagination.js.map +1 -0
- package/dist/providers/s3/sigv4.d.ts +29 -0
- package/dist/providers/s3/sigv4.d.ts.map +1 -0
- package/dist/providers/s3/sigv4.js +101 -0
- package/dist/providers/s3/sigv4.js.map +1 -0
- package/dist/providers/sentry/adapter.d.ts +29 -0
- package/dist/providers/sentry/adapter.d.ts.map +1 -0
- package/dist/providers/sentry/adapter.js +154 -0
- package/dist/providers/sentry/adapter.js.map +1 -0
- package/dist/providers/sentry/index.d.ts +3 -0
- package/dist/providers/sentry/index.d.ts.map +1 -0
- package/dist/providers/sentry/index.js +3 -0
- package/dist/providers/sentry/index.js.map +1 -0
- package/dist/providers/sentry/pagination.d.ts +17 -0
- package/dist/providers/sentry/pagination.d.ts.map +1 -0
- package/dist/providers/sentry/pagination.js +54 -0
- package/dist/providers/sentry/pagination.js.map +1 -0
- package/dist/public.d.ts +11 -1
- package/dist/public.d.ts.map +1 -1
- package/dist/public.js +9 -1
- package/dist/public.js.map +1 -1
- package/dist/upi/index.d.ts +43 -0
- package/dist/upi/index.d.ts.map +1 -0
- package/dist/upi/index.js +57 -0
- package/dist/upi/index.js.map +1 -0
- package/package.json +29 -6
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { parseRetryAfter } from "../../core/header-parser.js";
|
|
2
|
+
import { ResponseNormalizer } from "../../core/normalizer.js";
|
|
3
|
+
import { MeridianError, SDK_VERSION } from "../../core/types.js";
|
|
4
|
+
import { GoogleMapsPaginationStrategy } from "./pagination.js";
|
|
5
|
+
// Google Maps API-level status codes that indicate specific failure modes.
|
|
6
|
+
const OVER_QUOTA_STATUSES = new Set(["OVER_DAILY_LIMIT", "OVER_QUERY_LIMIT"]);
|
|
7
|
+
const AUTH_STATUSES = new Set(["REQUEST_DENIED"]);
|
|
8
|
+
const VALIDATION_STATUSES = new Set([
|
|
9
|
+
"INVALID_REQUEST",
|
|
10
|
+
"MAX_WAYPOINTS_EXCEEDED",
|
|
11
|
+
"MAX_ROUTE_LENGTH_EXCEEDED",
|
|
12
|
+
"NOT_FOUND",
|
|
13
|
+
"ZERO_RESULTS",
|
|
14
|
+
]);
|
|
15
|
+
export class GoogleMapsAdapter {
|
|
16
|
+
baseUrl;
|
|
17
|
+
constructor(baseUrl = "https://maps.googleapis.com/maps/api") {
|
|
18
|
+
this.baseUrl = baseUrl;
|
|
19
|
+
}
|
|
20
|
+
buildRequest(input) {
|
|
21
|
+
const { endpoint, options, authToken, baseUrl } = input;
|
|
22
|
+
const effectiveBaseUrl = baseUrl ?? this.baseUrl;
|
|
23
|
+
const url = new URL(endpoint.replace(/^\//, ""), `${effectiveBaseUrl}/`);
|
|
24
|
+
// API key is passed as a query parameter — this is the standard auth
|
|
25
|
+
// mechanism for Google Maps Platform REST APIs.
|
|
26
|
+
url.searchParams.set("key", authToken.token);
|
|
27
|
+
if (options.query) {
|
|
28
|
+
for (const [key, value] of Object.entries(options.query)) {
|
|
29
|
+
// Don't let callers overwrite the auth key.
|
|
30
|
+
if (key !== "key")
|
|
31
|
+
url.searchParams.set(key, String(value));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const headers = {
|
|
35
|
+
"User-Agent": `Meridian-SDK/${SDK_VERSION}`,
|
|
36
|
+
Accept: "application/json",
|
|
37
|
+
...options.headers,
|
|
38
|
+
};
|
|
39
|
+
let body;
|
|
40
|
+
const method = options.method ?? "GET";
|
|
41
|
+
if (options.body && method !== "GET" && method !== "HEAD") {
|
|
42
|
+
body = JSON.stringify(options.body);
|
|
43
|
+
headers["Content-Type"] = "application/json";
|
|
44
|
+
}
|
|
45
|
+
const built = { url: url.toString(), method, headers };
|
|
46
|
+
if (body !== undefined) {
|
|
47
|
+
built.body = body;
|
|
48
|
+
}
|
|
49
|
+
return built;
|
|
50
|
+
}
|
|
51
|
+
parseResponse(raw) {
|
|
52
|
+
const rateLimitInfo = this.rateLimitPolicy(raw.headers);
|
|
53
|
+
const paginationStrategy = this.paginationStrategy();
|
|
54
|
+
const paginationInfo = ResponseNormalizer.extractPaginationInfo(raw, paginationStrategy);
|
|
55
|
+
return ResponseNormalizer.normalize(raw, "googlemaps", rateLimitInfo, paginationInfo, [], "1.0.0");
|
|
56
|
+
}
|
|
57
|
+
parseError(raw) {
|
|
58
|
+
if (raw instanceof Error) {
|
|
59
|
+
const msg = raw.message.toLowerCase();
|
|
60
|
+
if (msg.includes("fetch") ||
|
|
61
|
+
msg.includes("network") ||
|
|
62
|
+
msg.includes("econnreset") ||
|
|
63
|
+
msg.includes("etimedout") ||
|
|
64
|
+
msg.includes("enotfound") ||
|
|
65
|
+
msg.includes("timeout")) {
|
|
66
|
+
return this.createMeridianError("network", true, "Network request failed. Check your connection and try again.", { originalError: raw.message });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (typeof raw === "object" &&
|
|
70
|
+
raw !== null &&
|
|
71
|
+
"status" in raw &&
|
|
72
|
+
typeof raw.status === "number") {
|
|
73
|
+
return this.parseHttpError(raw);
|
|
74
|
+
}
|
|
75
|
+
return this.createMeridianError("provider", false, "An unexpected error occurred", { raw });
|
|
76
|
+
}
|
|
77
|
+
parseHttpError(error) {
|
|
78
|
+
const { status, body, headers } = error;
|
|
79
|
+
const errorBody = body;
|
|
80
|
+
// Google Maps often returns 200 with a non-OK status in the body.
|
|
81
|
+
// When the pipeline surfaces an error, check the body status first.
|
|
82
|
+
const apiStatus = errorBody?.status ?? errorBody?.error?.status;
|
|
83
|
+
const message = errorBody?.error_message ?? errorBody?.error?.message;
|
|
84
|
+
if (apiStatus && OVER_QUOTA_STATUSES.has(apiStatus)) {
|
|
85
|
+
const retryAfter = this.extractRetryAfter(headers);
|
|
86
|
+
return this.createMeridianError("rate_limit", true, message ?? "Google Maps quota exceeded. Check your usage limits in Google Cloud Console.", { apiStatus }, retryAfter, 429);
|
|
87
|
+
}
|
|
88
|
+
if (apiStatus && AUTH_STATUSES.has(apiStatus)) {
|
|
89
|
+
return this.createMeridianError("auth", false, message ??
|
|
90
|
+
"Request denied. Check that your API key is valid and the Maps API is enabled in Google Cloud Console.", { apiStatus }, undefined, 403);
|
|
91
|
+
}
|
|
92
|
+
if (apiStatus && VALIDATION_STATUSES.has(apiStatus)) {
|
|
93
|
+
return this.createMeridianError("validation", false, message ?? `Request failed with status ${apiStatus}.`, { apiStatus }, undefined, 400);
|
|
94
|
+
}
|
|
95
|
+
if (status === 400) {
|
|
96
|
+
return this.createMeridianError("validation", false, message ?? "Bad request. Check the request parameters.", { googleMapsError: errorBody }, undefined, 400);
|
|
97
|
+
}
|
|
98
|
+
if (status === 401 || status === 403) {
|
|
99
|
+
return this.createMeridianError("auth", false, message ??
|
|
100
|
+
"Authentication failed. Ensure your API key is valid and billing is enabled in Google Cloud Console.", { googleMapsError: errorBody }, undefined, status);
|
|
101
|
+
}
|
|
102
|
+
if (status === 404) {
|
|
103
|
+
return this.createMeridianError("validation", false, message ?? "Resource not found.", { googleMapsError: errorBody }, undefined, 404);
|
|
104
|
+
}
|
|
105
|
+
if (status === 429) {
|
|
106
|
+
const retryAfter = this.extractRetryAfter(headers);
|
|
107
|
+
return this.createMeridianError("rate_limit", true, message ?? "Rate limit exceeded. Check your quota settings in Google Cloud Console.", { retryAfter: retryAfter?.toISOString() }, retryAfter, 429);
|
|
108
|
+
}
|
|
109
|
+
if (status >= 500) {
|
|
110
|
+
return this.createMeridianError("provider", true, message ?? `Google Maps API returned error ${status}. This may be temporary.`, { status, googleMapsError: errorBody }, undefined, status);
|
|
111
|
+
}
|
|
112
|
+
if (status >= 400) {
|
|
113
|
+
return this.createMeridianError("validation", false, message ?? `Request failed with status ${status}.`, { status, googleMapsError: errorBody }, undefined, status);
|
|
114
|
+
}
|
|
115
|
+
return this.createMeridianError("provider", false, `Unexpected response status ${status}.`, { status }, undefined, status);
|
|
116
|
+
}
|
|
117
|
+
async authStrategy(config) {
|
|
118
|
+
const key = config.apiKey ?? config.token;
|
|
119
|
+
if (!key) {
|
|
120
|
+
throw this.createMeridianError("auth", false, "Google Maps authentication requires an API key. Set auth.apiKey to your Google Maps Platform API key.", {}, undefined, 401);
|
|
121
|
+
}
|
|
122
|
+
return { token: key };
|
|
123
|
+
}
|
|
124
|
+
rateLimitPolicy(_headers) {
|
|
125
|
+
// Google Maps Platform does not expose rate-limit headers in responses.
|
|
126
|
+
// Quotas are managed in Google Cloud Console (per-day and per-minute limits).
|
|
127
|
+
return {
|
|
128
|
+
limit: 3000,
|
|
129
|
+
remaining: 3000,
|
|
130
|
+
reset: new Date(Date.now() + 60_000),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
paginationStrategy() {
|
|
134
|
+
return new GoogleMapsPaginationStrategy();
|
|
135
|
+
}
|
|
136
|
+
getIdempotencyConfig() {
|
|
137
|
+
return {
|
|
138
|
+
defaultSafeOperations: new Set(["GET", "HEAD", "OPTIONS"]),
|
|
139
|
+
operationOverrides: new Map(),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
createMeridianError(category, retryable, message, metadata, retryAfter, status) {
|
|
143
|
+
return new MeridianError(message, category, "googlemaps", retryable, "", metadata, retryAfter, status);
|
|
144
|
+
}
|
|
145
|
+
extractRetryAfter(headers) {
|
|
146
|
+
if (!headers)
|
|
147
|
+
return undefined;
|
|
148
|
+
const value = headers instanceof Headers
|
|
149
|
+
? headers.get("retry-after")
|
|
150
|
+
: (Object.entries(headers).find(([k]) => k.toLowerCase() === "retry-after")?.[1] ?? null);
|
|
151
|
+
return parseRetryAfter(value) ?? undefined;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/providers/googlemaps/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PaginationStrategy, RawResponse, RequestOptions } from "../../core/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Google Maps Places API uses `next_page_token` in the JSON response body.
|
|
4
|
+
* The token is passed back as the `pagetoken` query parameter on the next request.
|
|
5
|
+
* Note: Google requires a short delay before using a page token — the token itself
|
|
6
|
+
* becomes valid ~2 seconds after the previous response is received.
|
|
7
|
+
*/
|
|
8
|
+
export declare class GoogleMapsPaginationStrategy implements PaginationStrategy {
|
|
9
|
+
extractCursor(response: RawResponse): string | null;
|
|
10
|
+
extractTotal(_response: RawResponse): number | null;
|
|
11
|
+
hasNext(response: RawResponse): boolean;
|
|
12
|
+
buildNextRequest(endpoint: string, options: RequestOptions, cursor: string): {
|
|
13
|
+
endpoint: string;
|
|
14
|
+
options: RequestOptions;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../src/providers/googlemaps/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE3F;;;;;GAKG;AACH,qBAAa,4BAA6B,YAAW,kBAAkB;IACrE,aAAa,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IAUnD,YAAY,CAAC,SAAS,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IAInD,OAAO,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO;IAIvC,gBAAgB,CACd,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,MAAM,GACb;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,cAAc,CAAA;KAAE;CAYjD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Maps Places API uses `next_page_token` in the JSON response body.
|
|
3
|
+
* The token is passed back as the `pagetoken` query parameter on the next request.
|
|
4
|
+
* Note: Google requires a short delay before using a page token — the token itself
|
|
5
|
+
* becomes valid ~2 seconds after the previous response is received.
|
|
6
|
+
*/
|
|
7
|
+
export class GoogleMapsPaginationStrategy {
|
|
8
|
+
extractCursor(response) {
|
|
9
|
+
if (typeof response.body === "object" && response.body !== null) {
|
|
10
|
+
const body = response.body;
|
|
11
|
+
if (typeof body.next_page_token === "string" && body.next_page_token.length > 0) {
|
|
12
|
+
return body.next_page_token;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
extractTotal(_response) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
hasNext(response) {
|
|
21
|
+
return this.extractCursor(response) !== null;
|
|
22
|
+
}
|
|
23
|
+
buildNextRequest(endpoint, options, cursor) {
|
|
24
|
+
return {
|
|
25
|
+
endpoint,
|
|
26
|
+
options: {
|
|
27
|
+
...options,
|
|
28
|
+
query: {
|
|
29
|
+
...options.query,
|
|
30
|
+
pagetoken: cursor,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../../src/providers/googlemaps/pagination.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,4BAA4B;IACvC,aAAa,CAAC,QAAqB;QACjC,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAChE,MAAM,IAAI,GAAG,QAAQ,CAAC,IAA+B,CAAC;YACtD,IAAI,OAAO,IAAI,CAAC,eAAe,KAAK,QAAQ,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChF,OAAO,IAAI,CAAC,eAAe,CAAC;YAC9B,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,YAAY,CAAC,SAAsB;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,QAAqB;QAC3B,OAAO,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAC/C,CAAC;IAED,gBAAgB,CACd,QAAgB,EAChB,OAAuB,EACvB,MAAc;QAEd,OAAO;YACL,QAAQ;YACR,OAAO,EAAE;gBACP,GAAG,OAAO;gBACV,KAAK,EAAE;oBACL,GAAG,OAAO,CAAC,KAAK;oBAChB,SAAS,EAAE,MAAM;iBAClB;aACF;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { AdapterInput, AuthConfig, AuthToken, BuiltRequest, IdempotencyConfig, NormalizedResponse, PaginationStrategy, ProviderAdapter, RateLimitInfo, RawResponse } from "../../core/types.js";
|
|
2
|
+
import { MeridianError } from "../../core/types.js";
|
|
3
|
+
/**
|
|
4
|
+
* S3-compatible object storage (AWS S3, Cloudflare R2, and other S3-API stores)
|
|
5
|
+
* authenticates every request with AWS Signature Version 4 — there's no bearer
|
|
6
|
+
* token or static API key header. Each call is signed in `buildRequest` using
|
|
7
|
+
* the access key / secret key (and, for R2, region `"auto"`) supplied via
|
|
8
|
+
* `auth.custom`. Responses are XML, not JSON; pagination and error parsing
|
|
9
|
+
* extract the handful of fields they need from that XML directly.
|
|
10
|
+
*
|
|
11
|
+
* Configure with `auth.username`/`auth.password` (access key / secret key) and
|
|
12
|
+
* `auth.custom = { region, endpoint?, sessionToken? }`. For R2, set
|
|
13
|
+
* `auth.custom.region = "auto"` and `auth.custom.endpoint` to your account's
|
|
14
|
+
* `https://<account_id>.r2.cloudflarestorage.com` URL (or pass it as `baseUrl`
|
|
15
|
+
* in the provider config).
|
|
16
|
+
*/
|
|
17
|
+
export declare class S3Adapter implements ProviderAdapter {
|
|
18
|
+
private baseUrl;
|
|
19
|
+
constructor(baseUrl?: string);
|
|
20
|
+
buildRequest(input: AdapterInput): BuiltRequest;
|
|
21
|
+
parseResponse(raw: RawResponse): NormalizedResponse;
|
|
22
|
+
parseError(raw: unknown): MeridianError;
|
|
23
|
+
private parseHttpError;
|
|
24
|
+
authStrategy(config: AuthConfig): Promise<AuthToken>;
|
|
25
|
+
rateLimitPolicy(_headers: Headers): RateLimitInfo;
|
|
26
|
+
paginationStrategy(): PaginationStrategy;
|
|
27
|
+
getIdempotencyConfig(): IdempotencyConfig;
|
|
28
|
+
/**
|
|
29
|
+
* Verifies an S3 Event Notification delivered via SNS/EventBridge webhook —
|
|
30
|
+
* an HMAC-SHA256 digest of the raw request body, hex-encoded, keyed by a
|
|
31
|
+
* shared secret configured on the destination (S3 itself does not sign
|
|
32
|
+
* notifications; this supports the common "shared secret" relay pattern).
|
|
33
|
+
*/
|
|
34
|
+
verifyWebhook(payload: string | Buffer, signature: string, secret: string): boolean;
|
|
35
|
+
private createMeridianError;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/providers/s3/adapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,WAAW,EACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAoB,aAAa,EAAe,MAAM,qBAAqB,CAAC;AA+CnF;;;;;;;;;;;;;GAaG;AACH,qBAAa,SAAU,YAAW,eAAe;IAC/C,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,SAA8B;IAIjD,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY;IAqC/C,aAAa,CAAC,GAAG,EAAE,WAAW,GAAG,kBAAkB;IAOnD,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa;IAkCvC,OAAO,CAAC,cAAc;IAkGhB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IA8B1D,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,aAAa;IASjD,kBAAkB,IAAI,kBAAkB;IAIxC,oBAAoB,IAAI,iBAAiB;IAOzC;;;;;OAKG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAYnF,OAAO,CAAC,mBAAmB;CAU5B"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { ResponseNormalizer } from "../../core/normalizer.js";
|
|
3
|
+
import { IdempotencyLevel, MeridianError, SDK_VERSION } from "../../core/types.js";
|
|
4
|
+
import { S3PaginationStrategy } from "./pagination.js";
|
|
5
|
+
import { signSigV4 } from "./sigv4.js";
|
|
6
|
+
function extractXmlField(xml, tag) {
|
|
7
|
+
const match = xml.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));
|
|
8
|
+
return match?.[1] ?? null;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The auth token carries SigV4 credentials JSON-encoded (see `authStrategy`).
|
|
12
|
+
* Falls back to treating an opaque token string as the access key ID — this
|
|
13
|
+
* keeps `buildRequest` resilient to non-JSON tokens (e.g. generic contract
|
|
14
|
+
* tests that pass a placeholder string) without producing a usable signature.
|
|
15
|
+
*/
|
|
16
|
+
function parseSigV4Credentials(token) {
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(token);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return { accessKeyId: token, secretAccessKey: "", region: "us-east-1", service: "s3" };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** Parses S3/R2's XML error body into a plain object, when present. */
|
|
25
|
+
function parseS3ErrorXml(body) {
|
|
26
|
+
if (typeof body !== "string" || !body.includes("<Error>")) {
|
|
27
|
+
return typeof body === "object" && body !== null ? body : undefined;
|
|
28
|
+
}
|
|
29
|
+
const result = {};
|
|
30
|
+
const code = extractXmlField(body, "Code");
|
|
31
|
+
const message = extractXmlField(body, "Message");
|
|
32
|
+
const requestId = extractXmlField(body, "RequestId");
|
|
33
|
+
const resource = extractXmlField(body, "Resource");
|
|
34
|
+
if (code !== null)
|
|
35
|
+
result.Code = code;
|
|
36
|
+
if (message !== null)
|
|
37
|
+
result.Message = message;
|
|
38
|
+
if (requestId !== null)
|
|
39
|
+
result.RequestId = requestId;
|
|
40
|
+
if (resource !== null)
|
|
41
|
+
result.Resource = resource;
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* S3-compatible object storage (AWS S3, Cloudflare R2, and other S3-API stores)
|
|
46
|
+
* authenticates every request with AWS Signature Version 4 — there's no bearer
|
|
47
|
+
* token or static API key header. Each call is signed in `buildRequest` using
|
|
48
|
+
* the access key / secret key (and, for R2, region `"auto"`) supplied via
|
|
49
|
+
* `auth.custom`. Responses are XML, not JSON; pagination and error parsing
|
|
50
|
+
* extract the handful of fields they need from that XML directly.
|
|
51
|
+
*
|
|
52
|
+
* Configure with `auth.username`/`auth.password` (access key / secret key) and
|
|
53
|
+
* `auth.custom = { region, endpoint?, sessionToken? }`. For R2, set
|
|
54
|
+
* `auth.custom.region = "auto"` and `auth.custom.endpoint` to your account's
|
|
55
|
+
* `https://<account_id>.r2.cloudflarestorage.com` URL (or pass it as `baseUrl`
|
|
56
|
+
* in the provider config).
|
|
57
|
+
*/
|
|
58
|
+
export class S3Adapter {
|
|
59
|
+
baseUrl;
|
|
60
|
+
constructor(baseUrl = "https://s3.amazonaws.com/") {
|
|
61
|
+
this.baseUrl = baseUrl;
|
|
62
|
+
}
|
|
63
|
+
buildRequest(input) {
|
|
64
|
+
const { endpoint, options, authToken, baseUrl } = input;
|
|
65
|
+
const effectiveBaseUrl = baseUrl ?? this.baseUrl;
|
|
66
|
+
const url = new URL(endpoint.replace(/^\//, ""), effectiveBaseUrl);
|
|
67
|
+
if (options.query) {
|
|
68
|
+
for (const [key, value] of Object.entries(options.query)) {
|
|
69
|
+
url.searchParams.set(key, String(value));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const credentials = parseSigV4Credentials(authToken.token);
|
|
73
|
+
const method = options.method ?? "GET";
|
|
74
|
+
let body;
|
|
75
|
+
const baseHeaders = {
|
|
76
|
+
"User-Agent": `Meridian-SDK/${SDK_VERSION}`,
|
|
77
|
+
...options.headers,
|
|
78
|
+
};
|
|
79
|
+
if (options.body && method !== "GET" && method !== "HEAD") {
|
|
80
|
+
body = typeof options.body === "string" ? options.body : JSON.stringify(options.body);
|
|
81
|
+
baseHeaders["Content-Type"] ??= "application/octet-stream";
|
|
82
|
+
}
|
|
83
|
+
const signed = signSigV4(body !== undefined
|
|
84
|
+
? { method, url, headers: baseHeaders, body, credentials }
|
|
85
|
+
: { method, url, headers: baseHeaders, credentials });
|
|
86
|
+
const built = { url: url.toString(), method, headers: signed.headers };
|
|
87
|
+
if (body !== undefined) {
|
|
88
|
+
built.body = body;
|
|
89
|
+
}
|
|
90
|
+
return built;
|
|
91
|
+
}
|
|
92
|
+
parseResponse(raw) {
|
|
93
|
+
const rateLimitInfo = this.rateLimitPolicy(raw.headers);
|
|
94
|
+
const paginationStrategy = this.paginationStrategy();
|
|
95
|
+
const paginationInfo = ResponseNormalizer.extractPaginationInfo(raw, paginationStrategy);
|
|
96
|
+
return ResponseNormalizer.normalize(raw, "s3", rateLimitInfo, paginationInfo, [], "1.0.0");
|
|
97
|
+
}
|
|
98
|
+
parseError(raw) {
|
|
99
|
+
if (raw instanceof Error) {
|
|
100
|
+
const msg = raw.message.toLowerCase();
|
|
101
|
+
if (msg.includes("fetch") ||
|
|
102
|
+
msg.includes("network") ||
|
|
103
|
+
msg.includes("econnreset") ||
|
|
104
|
+
msg.includes("etimedout") ||
|
|
105
|
+
msg.includes("enotfound") ||
|
|
106
|
+
msg.includes("timeout")) {
|
|
107
|
+
return this.createMeridianError("network", true, "Network request failed. Check your connection and try again.", { originalError: raw.message });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (typeof raw === "object" &&
|
|
111
|
+
raw !== null &&
|
|
112
|
+
"status" in raw &&
|
|
113
|
+
typeof raw.status === "number") {
|
|
114
|
+
return this.parseHttpError(raw);
|
|
115
|
+
}
|
|
116
|
+
return this.createMeridianError("provider", false, "An unexpected error occurred", { raw });
|
|
117
|
+
}
|
|
118
|
+
parseHttpError(error) {
|
|
119
|
+
const { status } = error;
|
|
120
|
+
const errorBody = parseS3ErrorXml(error.body);
|
|
121
|
+
const errorMessage = errorBody?.Message;
|
|
122
|
+
const metadata = { code: errorBody?.Code, requestId: errorBody?.RequestId };
|
|
123
|
+
if (status === 401 || status === 403) {
|
|
124
|
+
return this.createMeridianError("auth", false, errorMessage ??
|
|
125
|
+
"Authentication failed. Check your access key ID, secret access key, and signing region.", metadata, undefined, status);
|
|
126
|
+
}
|
|
127
|
+
if (status === 404) {
|
|
128
|
+
return this.createMeridianError("validation", false, errorMessage ?? "Bucket or object not found.", metadata, undefined, 404);
|
|
129
|
+
}
|
|
130
|
+
if (status === 409 || status === 412 || status === 422) {
|
|
131
|
+
return this.createMeridianError("validation", false, errorMessage ?? "Request validation failed.", metadata, undefined, status);
|
|
132
|
+
}
|
|
133
|
+
if (status === 429 || (status === 503 && errorBody?.Code === "SlowDown")) {
|
|
134
|
+
return this.createMeridianError("rate_limit", true, errorMessage ?? "Request rate exceeded. Please slow down and retry.", metadata, undefined, status);
|
|
135
|
+
}
|
|
136
|
+
if (status === 400) {
|
|
137
|
+
return this.createMeridianError("validation", false, errorMessage ?? "Request validation failed.", metadata, undefined, 400);
|
|
138
|
+
}
|
|
139
|
+
if (status >= 500) {
|
|
140
|
+
return this.createMeridianError("provider", true, errorMessage ?? `S3 API returned error ${status}. This may be temporary.`, metadata, undefined, status);
|
|
141
|
+
}
|
|
142
|
+
if (status >= 400) {
|
|
143
|
+
return this.createMeridianError("validation", false, errorMessage ?? `Request failed with status ${status}.`, metadata, undefined, status);
|
|
144
|
+
}
|
|
145
|
+
return this.createMeridianError("provider", false, `Unexpected response status ${status}.`, metadata, undefined, status);
|
|
146
|
+
}
|
|
147
|
+
async authStrategy(config) {
|
|
148
|
+
const accessKeyId = config.username ?? config.apiKey ?? config.clientId;
|
|
149
|
+
const secretAccessKey = config.password ?? config.apiSecret ?? config.clientSecret;
|
|
150
|
+
const region = config.custom?.region ?? "us-east-1";
|
|
151
|
+
const sessionToken = config.custom?.sessionToken ?? config.refreshToken;
|
|
152
|
+
if (!accessKeyId || !secretAccessKey) {
|
|
153
|
+
throw this.createMeridianError("auth", false, "S3 authentication requires an access key ID and secret access key. " +
|
|
154
|
+
"Set auth.username (access key ID) + auth.password (secret access key), " +
|
|
155
|
+
'and optionally auth.custom = { region, sessionToken } (use region: "auto" for R2).', {}, undefined, 401);
|
|
156
|
+
}
|
|
157
|
+
const credentials = {
|
|
158
|
+
accessKeyId,
|
|
159
|
+
secretAccessKey,
|
|
160
|
+
region,
|
|
161
|
+
service: "s3",
|
|
162
|
+
...(sessionToken ? { sessionToken } : {}),
|
|
163
|
+
};
|
|
164
|
+
return { token: JSON.stringify(credentials) };
|
|
165
|
+
}
|
|
166
|
+
rateLimitPolicy(_headers) {
|
|
167
|
+
// S3 does not publish rate-limit headers; it signals throttling via 503 SlowDown.
|
|
168
|
+
return {
|
|
169
|
+
limit: 100,
|
|
170
|
+
remaining: 100,
|
|
171
|
+
reset: new Date(Date.now() + 60_000),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
paginationStrategy() {
|
|
175
|
+
return new S3PaginationStrategy();
|
|
176
|
+
}
|
|
177
|
+
getIdempotencyConfig() {
|
|
178
|
+
return {
|
|
179
|
+
defaultSafeOperations: new Set(["GET", "HEAD", "OPTIONS"]),
|
|
180
|
+
operationOverrides: new Map([["PUT", IdempotencyLevel.IDEMPOTENT]]),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Verifies an S3 Event Notification delivered via SNS/EventBridge webhook —
|
|
185
|
+
* an HMAC-SHA256 digest of the raw request body, hex-encoded, keyed by a
|
|
186
|
+
* shared secret configured on the destination (S3 itself does not sign
|
|
187
|
+
* notifications; this supports the common "shared secret" relay pattern).
|
|
188
|
+
*/
|
|
189
|
+
verifyWebhook(payload, signature, secret) {
|
|
190
|
+
const expected = createHmac("sha256", secret).update(payload).digest("hex");
|
|
191
|
+
try {
|
|
192
|
+
const a = Buffer.from(expected);
|
|
193
|
+
const b = Buffer.from(signature);
|
|
194
|
+
if (a.length !== b.length)
|
|
195
|
+
return false;
|
|
196
|
+
return timingSafeEqual(a, b);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
createMeridianError(category, retryable, message, metadata, retryAfter, status) {
|
|
203
|
+
return new MeridianError(message, category, "s3", retryable, "", metadata, retryAfter, status);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/providers/s3/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/s3/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/s3/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PaginationStrategy, RawResponse, RequestOptions } from "../../core/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* S3 / R2's `ListObjectsV2` returns XML with `IsTruncated` and, when there are
|
|
4
|
+
* more results, a `NextContinuationToken` — fed back as the `continuation-token`
|
|
5
|
+
* query parameter. The SDK's HTTP layer hands us the raw XML string as the body
|
|
6
|
+
* for non-JSON responses.
|
|
7
|
+
*/
|
|
8
|
+
export declare class S3PaginationStrategy implements PaginationStrategy {
|
|
9
|
+
extractCursor(response: RawResponse): string | null;
|
|
10
|
+
extractTotal(response: RawResponse): number | null;
|
|
11
|
+
hasNext(response: RawResponse): boolean;
|
|
12
|
+
buildNextRequest(endpoint: string, options: RequestOptions, cursor: string): {
|
|
13
|
+
endpoint: string;
|
|
14
|
+
options: RequestOptions;
|
|
15
|
+
};
|
|
16
|
+
private bodyAsXml;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../src/providers/s3/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAY3F;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,kBAAkB;IAC7D,aAAa,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IAMnD,YAAY,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI;IASlD,OAAO,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO;IAMvC,gBAAgB,CACd,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,MAAM,GACb;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,cAAc,CAAA;KAAE;IAahD,OAAO,CAAC,SAAS;CAMlB"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts a top-level XML element's text content via a narrow regex match.
|
|
3
|
+
* S3's ListObjectsV2 response is flat enough (no nested elements share these
|
|
4
|
+
* tag names) that a full XML parser isn't warranted here.
|
|
5
|
+
*/
|
|
6
|
+
function extractXmlField(xml, tag) {
|
|
7
|
+
const match = xml.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));
|
|
8
|
+
return match?.[1] ?? null;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* S3 / R2's `ListObjectsV2` returns XML with `IsTruncated` and, when there are
|
|
12
|
+
* more results, a `NextContinuationToken` — fed back as the `continuation-token`
|
|
13
|
+
* query parameter. The SDK's HTTP layer hands us the raw XML string as the body
|
|
14
|
+
* for non-JSON responses.
|
|
15
|
+
*/
|
|
16
|
+
export class S3PaginationStrategy {
|
|
17
|
+
extractCursor(response) {
|
|
18
|
+
const xml = this.bodyAsXml(response);
|
|
19
|
+
if (!xml)
|
|
20
|
+
return null;
|
|
21
|
+
return extractXmlField(xml, "NextContinuationToken");
|
|
22
|
+
}
|
|
23
|
+
extractTotal(response) {
|
|
24
|
+
const xml = this.bodyAsXml(response);
|
|
25
|
+
if (!xml)
|
|
26
|
+
return null;
|
|
27
|
+
const keyCount = extractXmlField(xml, "KeyCount");
|
|
28
|
+
if (keyCount === null)
|
|
29
|
+
return null;
|
|
30
|
+
const parsed = Number.parseInt(keyCount, 10);
|
|
31
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
32
|
+
}
|
|
33
|
+
hasNext(response) {
|
|
34
|
+
const xml = this.bodyAsXml(response);
|
|
35
|
+
if (!xml)
|
|
36
|
+
return false;
|
|
37
|
+
return extractXmlField(xml, "IsTruncated") === "true";
|
|
38
|
+
}
|
|
39
|
+
buildNextRequest(endpoint, options, cursor) {
|
|
40
|
+
return {
|
|
41
|
+
endpoint,
|
|
42
|
+
options: {
|
|
43
|
+
...options,
|
|
44
|
+
query: {
|
|
45
|
+
...options.query,
|
|
46
|
+
"continuation-token": cursor,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
bodyAsXml(response) {
|
|
52
|
+
if (typeof response.body === "string" && response.body.includes("<ListBucketResult")) {
|
|
53
|
+
return response.body;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../../src/providers/s3/pagination.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,SAAS,eAAe,CAAC,GAAW,EAAE,GAAW;IAC/C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,aAAa,GAAG,GAAG,CAAC,CAAC,CAAC;IAChE,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC5B,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,oBAAoB;IAC/B,aAAa,CAAC,QAAqB;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,OAAO,eAAe,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;IACvD,CAAC;IAED,YAAY,CAAC,QAAqB;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG;YAAE,OAAO,IAAI,CAAC;QACtB,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAClD,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC7C,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC9C,CAAC;IAED,OAAO,CAAC,QAAqB;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QACvB,OAAO,eAAe,CAAC,GAAG,EAAE,aAAa,CAAC,KAAK,MAAM,CAAC;IACxD,CAAC;IAED,gBAAgB,CACd,QAAgB,EAChB,OAAuB,EACvB,MAAc;QAEd,OAAO;YACL,QAAQ;YACR,OAAO,EAAE;gBACP,GAAG,OAAO;gBACV,KAAK,EAAE;oBACL,GAAG,OAAO,CAAC,KAAK;oBAChB,oBAAoB,EAAE,MAAM;iBAC7B;aACF;SACF,CAAC;IACJ,CAAC;IAEO,SAAS,CAAC,QAAqB;QACrC,IAAI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACrF,OAAO,QAAQ,CAAC,IAAI,CAAC;QACvB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface SigV4Credentials {
|
|
2
|
+
accessKeyId: string;
|
|
3
|
+
secretAccessKey: string;
|
|
4
|
+
region: string;
|
|
5
|
+
service?: string;
|
|
6
|
+
sessionToken?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SigV4SignInput {
|
|
9
|
+
method: string;
|
|
10
|
+
url: URL;
|
|
11
|
+
headers: Record<string, string>;
|
|
12
|
+
body?: string;
|
|
13
|
+
credentials: SigV4Credentials;
|
|
14
|
+
/** Override the signing instant — primarily for deterministic tests. */
|
|
15
|
+
date?: Date;
|
|
16
|
+
}
|
|
17
|
+
export interface SigV4SignedRequest {
|
|
18
|
+
headers: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Signs a request per AWS Signature Version 4 (the scheme used by S3, R2, and
|
|
22
|
+
* other S3-compatible object stores). Returns the headers to attach — including
|
|
23
|
+
* `Authorization`, `x-amz-date`, `x-amz-content-sha256`, and `host` — that make
|
|
24
|
+
* the request authenticate as the given credentials.
|
|
25
|
+
*
|
|
26
|
+
* Reference: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
|
27
|
+
*/
|
|
28
|
+
export declare function signSigV4(input: SigV4SignInput): SigV4SignedRequest;
|
|
29
|
+
//# sourceMappingURL=sigv4.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sigv4.d.ts","sourceRoot":"","sources":["../../../src/providers/s3/sigv4.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,GAAG,CAAC;IACT,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,gBAAgB,CAAC;IAC9B,wEAAwE;IACxE,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AA4DD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,kBAAkB,CAuDnE"}
|