@beam-network/sdk 0.2.15 → 0.2.17
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 +7 -1
- package/dist/client.d.ts +11 -6
- package/dist/client.js +273 -427
- package/dist/models.d.ts +14 -40
- package/dist/nats-control.d.ts +72 -0
- package/dist/nats-control.js +227 -0
- package/dist/provider-signing.d.ts +0 -16
- package/dist/provider-signing.js +0 -301
- package/package.json +35 -33
package/dist/models.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
export type SignedUrlFlow = "signed_url_v1" | "signed_url_v2";
|
|
2
2
|
export interface BeamClientOptions {
|
|
3
3
|
apiKey?: string;
|
|
4
|
-
|
|
4
|
+
natsUrl?: string;
|
|
5
|
+
natsWsUrl?: string;
|
|
6
|
+
environment?: string;
|
|
7
|
+
transferClientSubjectPrefix?: string;
|
|
8
|
+
transferRuntimeShardCount?: number;
|
|
9
|
+
requestTimeoutMs?: number;
|
|
10
|
+
maxPayloadBytes?: number;
|
|
5
11
|
fetch?: typeof fetch;
|
|
6
12
|
}
|
|
7
13
|
export interface SourceConfig {
|
|
@@ -44,7 +50,6 @@ export interface TransferCreateRequest {
|
|
|
44
50
|
chunk_hashes?: string[];
|
|
45
51
|
callbacks?: CallbackConfig[];
|
|
46
52
|
test_mode?: boolean;
|
|
47
|
-
experimental?: boolean;
|
|
48
53
|
progressive_mode?: boolean;
|
|
49
54
|
signed_url_flow?: SignedUrlFlow;
|
|
50
55
|
}
|
|
@@ -61,17 +66,13 @@ export interface RawTransferCreateInput {
|
|
|
61
66
|
* Maps to BeamCore test_mode.
|
|
62
67
|
*/
|
|
63
68
|
testMode?: boolean;
|
|
64
|
-
/**
|
|
65
|
-
* Experimental transfers keep positive evidence but exclude failures and overseer interventions from PRISM.
|
|
66
|
-
*/
|
|
67
|
-
experimental?: boolean;
|
|
68
69
|
progressiveMode?: boolean;
|
|
69
70
|
signedUrlFlow?: SignedUrlFlow;
|
|
70
71
|
}
|
|
71
72
|
export interface TransferCreateResponse {
|
|
72
73
|
success: boolean;
|
|
73
74
|
transfer_id: string;
|
|
74
|
-
|
|
75
|
+
transfer_key?: string;
|
|
75
76
|
total_chunks: number;
|
|
76
77
|
total_sources: number;
|
|
77
78
|
total_destinations: number;
|
|
@@ -113,11 +114,15 @@ export interface DestinationStatusInfo {
|
|
|
113
114
|
}
|
|
114
115
|
export interface TransferStatusInfo {
|
|
115
116
|
transfer_id: string;
|
|
117
|
+
name?: string;
|
|
116
118
|
status: string;
|
|
117
119
|
error_message: string | null;
|
|
118
|
-
experimental?: boolean;
|
|
119
120
|
started_at: string | null;
|
|
120
121
|
completed_at: string | null;
|
|
122
|
+
total_bytes?: number;
|
|
123
|
+
total_size?: number;
|
|
124
|
+
total_chunks?: number;
|
|
125
|
+
chunks_completed?: number;
|
|
121
126
|
}
|
|
122
127
|
export interface S3ProviderConfig {
|
|
123
128
|
provider: "s3";
|
|
@@ -164,26 +169,6 @@ export interface HippiusProviderConfig {
|
|
|
164
169
|
}
|
|
165
170
|
export type ProviderConfig = S3ProviderConfig | R2ProviderConfig | S3CompatibleProviderConfig | HippiusProviderConfig;
|
|
166
171
|
export type ProviderSourceConfig = ProviderConfig;
|
|
167
|
-
export interface ChunkChecksumProviderGetInput {
|
|
168
|
-
source: ProviderSourceConfig;
|
|
169
|
-
chunk: ChunkSigningPlanItem;
|
|
170
|
-
algorithm: "content-md5";
|
|
171
|
-
}
|
|
172
|
-
export interface ChunkChecksumProviderSetInput extends ChunkChecksumProviderGetInput {
|
|
173
|
-
contentMd5: string;
|
|
174
|
-
}
|
|
175
|
-
export interface ChunkChecksumProvider {
|
|
176
|
-
getContentMd5(input: ChunkChecksumProviderGetInput): Promise<string | null | undefined>;
|
|
177
|
-
setContentMd5?(input: ChunkChecksumProviderSetInput): Promise<void>;
|
|
178
|
-
}
|
|
179
|
-
export interface ChunkChecksumEvent {
|
|
180
|
-
event: "checksum_warmup_started" | "checksum_warmup_completed" | "checksum_cache_hit" | "checksum_cache_miss" | "checksum_cold_chunk_cached" | "checksum_cold_group_completed";
|
|
181
|
-
sourceId: string;
|
|
182
|
-
sourceChunkIndex?: number;
|
|
183
|
-
chunkCount?: number;
|
|
184
|
-
bytes?: number;
|
|
185
|
-
durationMs?: number;
|
|
186
|
-
}
|
|
187
172
|
export type ProviderDestinationConfig = ProviderConfig;
|
|
188
173
|
export type S3ProviderConfigInput = Omit<S3ProviderConfig, "provider">;
|
|
189
174
|
export type R2ProviderConfigInput = Omit<R2ProviderConfig, "provider">;
|
|
@@ -209,25 +194,15 @@ export interface ProviderTransferCreateInput {
|
|
|
209
194
|
* Maps to BeamCore test_mode.
|
|
210
195
|
*/
|
|
211
196
|
testMode?: boolean;
|
|
212
|
-
/**
|
|
213
|
-
* Experimental transfers keep positive evidence but exclude failures and overseer interventions from PRISM.
|
|
214
|
-
*/
|
|
215
|
-
experimental?: boolean;
|
|
216
197
|
expiresIn?: number;
|
|
217
198
|
/**
|
|
218
|
-
* Defaults to true. Set to false to only prepare and
|
|
199
|
+
* Defaults to true. Set to false to only prepare and stream signed routes without distribution.
|
|
219
200
|
*/
|
|
220
201
|
distribute?: boolean;
|
|
221
|
-
onPlanned?: (plan: TransferPlanResponse) => void | Promise<void>;
|
|
222
202
|
onBeforeTransferPrepare?: () => void | Promise<void>;
|
|
223
203
|
onPrepared?: (prepared: TransferPrepareResponse) => void | Promise<void>;
|
|
224
204
|
throwIfCancelled?: (transferId?: string) => void | Promise<void>;
|
|
225
205
|
signedUrlFlow?: SignedUrlFlow;
|
|
226
|
-
checksumProvider?: ChunkChecksumProvider;
|
|
227
|
-
checksumReadConcurrency?: number;
|
|
228
|
-
checksumGroupSizeBytes?: number;
|
|
229
|
-
checksumReadTimeoutMs?: number;
|
|
230
|
-
onChecksumEvent?: (event: ChunkChecksumEvent) => void | Promise<void>;
|
|
231
206
|
}
|
|
232
207
|
export interface PlanningHttpSource {
|
|
233
208
|
source_id: string;
|
|
@@ -296,7 +271,6 @@ export interface TransferPrepareResponse {
|
|
|
296
271
|
transfer_id: string;
|
|
297
272
|
transfer_key?: string;
|
|
298
273
|
test_mode?: boolean;
|
|
299
|
-
experimental?: boolean;
|
|
300
274
|
chunk_size?: number;
|
|
301
275
|
total_size?: number;
|
|
302
276
|
total_sources?: number;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export declare const TRANSFER_CLIENT_CONTROL_SCHEMA_VERSION = "transfer-client-control/v1";
|
|
2
|
+
export declare const BEAM_DEFAULT_NATS_URL = "tls://nats.b1m.ai:4222";
|
|
3
|
+
export declare const BEAM_DEFAULT_NATS_WS_URL = "wss://nats.b1m.ai:443";
|
|
4
|
+
export declare const BEAM_DEFAULT_MAX_PAYLOAD_BYTES: number;
|
|
5
|
+
export declare const ROUTE_RECOVERY_SIGN_MESSAGE_TYPE = "transfer.route_recovery.sign";
|
|
6
|
+
export type TransferClientMessageType = "transfer.plan" | "transfer.create" | "transfer.prepare" | "transfer.route_stream.begin" | "transfer.route_stream.batch" | "transfer.route_stream.complete" | "transfer.distribute" | "transfer.status" | "transfer.cancel";
|
|
7
|
+
export interface RouteRecoverySignChunk {
|
|
8
|
+
source_id: string;
|
|
9
|
+
destination_id: string;
|
|
10
|
+
chunk_index: number;
|
|
11
|
+
delivery_index: number;
|
|
12
|
+
source_offset: number;
|
|
13
|
+
chunk_size: number;
|
|
14
|
+
logical_attempt_index: number;
|
|
15
|
+
attempt_slot: 0 | 1 | 2;
|
|
16
|
+
part_number: number;
|
|
17
|
+
route_generation_id: string;
|
|
18
|
+
multipart_group_id: string;
|
|
19
|
+
final_object_key: string;
|
|
20
|
+
upload_id?: string;
|
|
21
|
+
urls_expires_at?: string;
|
|
22
|
+
multipart_created_at?: string;
|
|
23
|
+
source_metadata?: Record<string, unknown>;
|
|
24
|
+
destination_metadata?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export interface RouteRecoverySignRequestPayload {
|
|
27
|
+
transfer_id: string;
|
|
28
|
+
route_generation_id: string;
|
|
29
|
+
requested_at?: string;
|
|
30
|
+
chunks: RouteRecoverySignChunk[];
|
|
31
|
+
}
|
|
32
|
+
export interface RouteRecoverySignReplyPayload {
|
|
33
|
+
transfer_id: string;
|
|
34
|
+
route_generation_id: string;
|
|
35
|
+
signed_at?: string;
|
|
36
|
+
chunk_routes: unknown[];
|
|
37
|
+
}
|
|
38
|
+
export interface TransferControlOptions {
|
|
39
|
+
apiKey: string;
|
|
40
|
+
natsUrl?: string;
|
|
41
|
+
natsWsUrl?: string;
|
|
42
|
+
environment?: string;
|
|
43
|
+
subjectPrefix?: string;
|
|
44
|
+
transferRuntimeShardCount?: number;
|
|
45
|
+
requestTimeoutMs?: number;
|
|
46
|
+
maxPayloadBytes?: number;
|
|
47
|
+
}
|
|
48
|
+
export declare class BeamTransferControl {
|
|
49
|
+
readonly environment: string;
|
|
50
|
+
readonly keyPrefix: string;
|
|
51
|
+
readonly shardCount: number;
|
|
52
|
+
readonly maxPayloadBytes: number;
|
|
53
|
+
private readonly subjectPrefix;
|
|
54
|
+
private readonly requestTimeoutMs;
|
|
55
|
+
private readonly natsUrl;
|
|
56
|
+
private readonly apiKey;
|
|
57
|
+
private nc;
|
|
58
|
+
private authToken;
|
|
59
|
+
private authTokenExpiresAt;
|
|
60
|
+
constructor(options: TransferControlOptions);
|
|
61
|
+
serveRouteRecoverySigner(transferId: string, handler: (payload: RouteRecoverySignRequestPayload) => Promise<RouteRecoverySignReplyPayload>): Promise<() => void>;
|
|
62
|
+
close(): Promise<void>;
|
|
63
|
+
request<T>(messageType: TransferClientMessageType, payload: Record<string, unknown>, transferId?: string): Promise<T>;
|
|
64
|
+
splitRoutesForPayload(messageType: TransferClientMessageType, basePayload: Record<string, unknown>, routes: unknown[]): unknown[][];
|
|
65
|
+
private connection;
|
|
66
|
+
private resolveAuthToken;
|
|
67
|
+
private authSubject;
|
|
68
|
+
private routeRecoverySignSubject;
|
|
69
|
+
private buildRouteRecoveryReply;
|
|
70
|
+
private requestSubject;
|
|
71
|
+
}
|
|
72
|
+
export declare function transferShardId(transferId: string, shardCount: number): number;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { encode, decode } from "@msgpack/msgpack";
|
|
2
|
+
import { connect } from "nats";
|
|
3
|
+
export const TRANSFER_CLIENT_CONTROL_SCHEMA_VERSION = "transfer-client-control/v1";
|
|
4
|
+
export const BEAM_DEFAULT_NATS_URL = "tls://nats.b1m.ai:4222";
|
|
5
|
+
export const BEAM_DEFAULT_NATS_WS_URL = "wss://nats.b1m.ai:443";
|
|
6
|
+
// NATS enforces max_payload per message. This guard splits signed-route control
|
|
7
|
+
// messages before the broker rejects them; transfer bytes never flow through NATS.
|
|
8
|
+
export const BEAM_DEFAULT_MAX_PAYLOAD_BYTES = 24 * 1024 * 1024;
|
|
9
|
+
export const ROUTE_RECOVERY_SIGN_MESSAGE_TYPE = "transfer.route_recovery.sign";
|
|
10
|
+
export class BeamTransferControl {
|
|
11
|
+
environment;
|
|
12
|
+
keyPrefix;
|
|
13
|
+
shardCount;
|
|
14
|
+
maxPayloadBytes;
|
|
15
|
+
subjectPrefix;
|
|
16
|
+
requestTimeoutMs;
|
|
17
|
+
natsUrl;
|
|
18
|
+
apiKey;
|
|
19
|
+
nc = null;
|
|
20
|
+
authToken = null;
|
|
21
|
+
authTokenExpiresAt = 0;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.apiKey = options.apiKey;
|
|
24
|
+
this.keyPrefix = options.apiKey.slice(0, 12);
|
|
25
|
+
this.environment = options.environment ?? "prod";
|
|
26
|
+
this.subjectPrefix = normalizeSubjectPrefix(options.subjectPrefix ?? "beam.transfer.client");
|
|
27
|
+
this.shardCount = options.transferRuntimeShardCount ?? 1;
|
|
28
|
+
this.requestTimeoutMs = options.requestTimeoutMs ?? 30_000;
|
|
29
|
+
this.maxPayloadBytes = options.maxPayloadBytes ?? BEAM_DEFAULT_MAX_PAYLOAD_BYTES;
|
|
30
|
+
this.natsUrl = options.natsUrl ?? options.natsWsUrl ?? BEAM_DEFAULT_NATS_URL;
|
|
31
|
+
if (/^https?:\/\//i.test(this.natsUrl) || /^wss?:\/\//i.test(this.natsUrl) && !options.natsWsUrl) {
|
|
32
|
+
throw new Error("Beam SDK lifecycle endpoint must be nats://, tls://, or configured as natsWsUrl.");
|
|
33
|
+
}
|
|
34
|
+
if (!Number.isInteger(this.shardCount) || this.shardCount < 1) {
|
|
35
|
+
throw new Error("transferRuntimeShardCount must be a positive integer.");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async serveRouteRecoverySigner(transferId, handler) {
|
|
39
|
+
const nc = await this.connection();
|
|
40
|
+
const subject = this.routeRecoverySignSubject(transferId);
|
|
41
|
+
const sub = nc.subscribe(subject);
|
|
42
|
+
let active = true;
|
|
43
|
+
void (async () => {
|
|
44
|
+
for await (const msg of sub) {
|
|
45
|
+
if (!active)
|
|
46
|
+
break;
|
|
47
|
+
let request = null;
|
|
48
|
+
try {
|
|
49
|
+
request = decode(msg.data);
|
|
50
|
+
if (request.schema_version !== TRANSFER_CLIENT_CONTROL_SCHEMA_VERSION ||
|
|
51
|
+
request.environment !== this.environment ||
|
|
52
|
+
request.key_prefix !== this.keyPrefix ||
|
|
53
|
+
request.transfer_id !== transferId ||
|
|
54
|
+
request.message_type !== ROUTE_RECOVERY_SIGN_MESSAGE_TYPE ||
|
|
55
|
+
request.producer !== "transfer-runtime") {
|
|
56
|
+
throw new Error("route recovery request envelope mismatch");
|
|
57
|
+
}
|
|
58
|
+
const payload = await handler(request.payload);
|
|
59
|
+
msg.respond(encode(this.buildRouteRecoveryReply(request, true, 200, payload)));
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
const fallback = request ?? {
|
|
63
|
+
message_id: "unknown",
|
|
64
|
+
request_id: "unknown",
|
|
65
|
+
transfer_id: transferId
|
|
66
|
+
};
|
|
67
|
+
msg.respond(encode(this.buildRouteRecoveryReply(fallback, false, 500, undefined, {
|
|
68
|
+
code: "route_recovery_sign_failed",
|
|
69
|
+
message: error instanceof Error ? error.message : String(error)
|
|
70
|
+
})));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
})();
|
|
74
|
+
return () => {
|
|
75
|
+
active = false;
|
|
76
|
+
sub.unsubscribe();
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
async close() {
|
|
80
|
+
if (!this.nc)
|
|
81
|
+
return;
|
|
82
|
+
await this.nc.drain();
|
|
83
|
+
this.nc = null;
|
|
84
|
+
}
|
|
85
|
+
async request(messageType, payload, transferId) {
|
|
86
|
+
const nc = await this.connection();
|
|
87
|
+
const authToken = await this.resolveAuthToken();
|
|
88
|
+
const shardId = transferId ? transferShardId(transferId, this.shardCount) : 0;
|
|
89
|
+
const requestId = randomId();
|
|
90
|
+
const envelope = {
|
|
91
|
+
message_id: `${TRANSFER_CLIENT_CONTROL_SCHEMA_VERSION}:${this.environment}:${this.keyPrefix}:${messageType}:${requestId}`,
|
|
92
|
+
schema_version: TRANSFER_CLIENT_CONTROL_SCHEMA_VERSION,
|
|
93
|
+
environment: this.environment,
|
|
94
|
+
key_prefix: this.keyPrefix,
|
|
95
|
+
shard_id: shardId,
|
|
96
|
+
message_type: messageType,
|
|
97
|
+
request_id: requestId,
|
|
98
|
+
auth_token: authToken,
|
|
99
|
+
occurred_at: new Date().toISOString(),
|
|
100
|
+
producer: "sdk",
|
|
101
|
+
payload
|
|
102
|
+
};
|
|
103
|
+
const bytes = encode(envelope);
|
|
104
|
+
if (bytes.byteLength > this.maxPayloadBytes) {
|
|
105
|
+
throw new Error(`NATS lifecycle request is ${bytes.byteLength} bytes, above maxPayloadBytes=${this.maxPayloadBytes}`);
|
|
106
|
+
}
|
|
107
|
+
const subject = this.requestSubject(messageType, shardId);
|
|
108
|
+
const response = await nc.request(subject, bytes, { timeout: this.requestTimeoutMs });
|
|
109
|
+
const decoded = decode(response.data);
|
|
110
|
+
if (!decoded.ok) {
|
|
111
|
+
const body = JSON.stringify(decoded.error ?? {});
|
|
112
|
+
throw new Error(`Beam lifecycle request failed with ${decoded.status}: ${body}`);
|
|
113
|
+
}
|
|
114
|
+
return (decoded.payload ?? {});
|
|
115
|
+
}
|
|
116
|
+
splitRoutesForPayload(messageType, basePayload, routes) {
|
|
117
|
+
const chunks = [];
|
|
118
|
+
let current = [];
|
|
119
|
+
for (const route of routes) {
|
|
120
|
+
const candidate = [...current, route];
|
|
121
|
+
const encoded = encode({
|
|
122
|
+
schema_version: TRANSFER_CLIENT_CONTROL_SCHEMA_VERSION,
|
|
123
|
+
environment: this.environment,
|
|
124
|
+
key_prefix: this.keyPrefix,
|
|
125
|
+
shard_id: 0,
|
|
126
|
+
message_type: messageType,
|
|
127
|
+
request_id: randomId(),
|
|
128
|
+
auth_token: "x".repeat(512),
|
|
129
|
+
occurred_at: new Date().toISOString(),
|
|
130
|
+
producer: "sdk",
|
|
131
|
+
payload: { ...basePayload, chunk_routes: candidate }
|
|
132
|
+
});
|
|
133
|
+
if (current.length > 0 && encoded.byteLength > this.maxPayloadBytes) {
|
|
134
|
+
chunks.push(current);
|
|
135
|
+
current = [route];
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
current = candidate;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (current.length > 0)
|
|
142
|
+
chunks.push(current);
|
|
143
|
+
return chunks;
|
|
144
|
+
}
|
|
145
|
+
async connection() {
|
|
146
|
+
if (this.nc && !this.nc.isClosed())
|
|
147
|
+
return this.nc;
|
|
148
|
+
this.nc = await connect({
|
|
149
|
+
servers: this.natsUrl,
|
|
150
|
+
user: this.keyPrefix,
|
|
151
|
+
pass: this.apiKey,
|
|
152
|
+
name: `beam-sdk-${this.keyPrefix}`
|
|
153
|
+
});
|
|
154
|
+
return this.nc;
|
|
155
|
+
}
|
|
156
|
+
async resolveAuthToken() {
|
|
157
|
+
const now = Math.floor(Date.now() / 1000);
|
|
158
|
+
if (this.authToken && this.authTokenExpiresAt - 5 > now)
|
|
159
|
+
return this.authToken;
|
|
160
|
+
const nc = await this.connection();
|
|
161
|
+
const response = await nc.request(this.authSubject(), new TextEncoder().encode("{}"), { timeout: this.requestTimeoutMs });
|
|
162
|
+
const parsed = JSON.parse(new TextDecoder().decode(response.data));
|
|
163
|
+
if (!parsed.ok || !parsed.token) {
|
|
164
|
+
throw new Error(`Beam SDK NATS auth resolve failed: ${parsed.error ?? "unknown_error"}`);
|
|
165
|
+
}
|
|
166
|
+
const claims = decodeJwtPayload(parsed.token);
|
|
167
|
+
this.authToken = parsed.token;
|
|
168
|
+
this.authTokenExpiresAt = claims.exp;
|
|
169
|
+
return parsed.token;
|
|
170
|
+
}
|
|
171
|
+
authSubject() {
|
|
172
|
+
return `${this.subjectPrefix}.${this.environment}.auth.${this.keyPrefix}.resolve`;
|
|
173
|
+
}
|
|
174
|
+
routeRecoverySignSubject(transferId) {
|
|
175
|
+
return `${this.subjectPrefix}.${this.environment}.sdk.${this.keyPrefix}.transfer.${transferId}.route_recovery_sign`;
|
|
176
|
+
}
|
|
177
|
+
buildRouteRecoveryReply(request, ok, status, payload, error) {
|
|
178
|
+
return {
|
|
179
|
+
message_id: request.message_id,
|
|
180
|
+
schema_version: TRANSFER_CLIENT_CONTROL_SCHEMA_VERSION,
|
|
181
|
+
environment: this.environment,
|
|
182
|
+
key_prefix: this.keyPrefix,
|
|
183
|
+
transfer_id: request.transfer_id,
|
|
184
|
+
message_type: ROUTE_RECOVERY_SIGN_MESSAGE_TYPE,
|
|
185
|
+
request_id: request.request_id,
|
|
186
|
+
occurred_at: new Date().toISOString(),
|
|
187
|
+
producer: "sdk",
|
|
188
|
+
ok,
|
|
189
|
+
status,
|
|
190
|
+
...(payload ? { payload } : {}),
|
|
191
|
+
...(error ? { error } : {})
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
requestSubject(messageType, shardId) {
|
|
195
|
+
return `${this.subjectPrefix}.${this.environment}.sdk.${this.keyPrefix}.shard.${shardId}.${messageType.replace(/\./g, "_")}`;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
export function transferShardId(transferId, shardCount) {
|
|
199
|
+
let hash = 2166136261;
|
|
200
|
+
for (let i = 0; i < transferId.length; i += 1) {
|
|
201
|
+
hash ^= transferId.charCodeAt(i);
|
|
202
|
+
hash = Math.imul(hash, 16777619) >>> 0;
|
|
203
|
+
}
|
|
204
|
+
return hash % shardCount;
|
|
205
|
+
}
|
|
206
|
+
function decodeJwtPayload(jwt) {
|
|
207
|
+
const parts = jwt.split(".");
|
|
208
|
+
if (parts.length < 2)
|
|
209
|
+
throw new Error("invalid JWT");
|
|
210
|
+
return JSON.parse(base64UrlDecode(parts[1]));
|
|
211
|
+
}
|
|
212
|
+
function base64UrlDecode(value) {
|
|
213
|
+
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
214
|
+
const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "=");
|
|
215
|
+
if (typeof Buffer !== "undefined")
|
|
216
|
+
return Buffer.from(padded, "base64").toString("utf8");
|
|
217
|
+
return atob(padded);
|
|
218
|
+
}
|
|
219
|
+
function normalizeSubjectPrefix(value) {
|
|
220
|
+
return value.replace(/^\.+|\.+$/g, "");
|
|
221
|
+
}
|
|
222
|
+
function randomId() {
|
|
223
|
+
const cryptoApi = globalThis.crypto;
|
|
224
|
+
if (cryptoApi?.randomUUID)
|
|
225
|
+
return cryptoApi.randomUUID();
|
|
226
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
227
|
+
}
|
|
@@ -46,7 +46,6 @@ export declare function signDestinationRoute(input: {
|
|
|
46
46
|
multipartGroupId?: string;
|
|
47
47
|
multipartCreatedAt?: string;
|
|
48
48
|
commitMethod?: "upload_part" | "upload_part_copy";
|
|
49
|
-
contentMd5?: string;
|
|
50
49
|
partVerifyUrl?: string;
|
|
51
50
|
listPageUrl?: string;
|
|
52
51
|
stagingObjectKey?: string;
|
|
@@ -57,21 +56,6 @@ export declare function signDestinationRoute(input: {
|
|
|
57
56
|
deleteUrl?: string;
|
|
58
57
|
fetchImpl?: typeof fetch;
|
|
59
58
|
}): Promise<SignedChunkRoute>;
|
|
60
|
-
export declare function computeChunksContentMd5(input: {
|
|
61
|
-
source: ProviderSourceConfig;
|
|
62
|
-
chunks: ChunkSigningPlanItem[];
|
|
63
|
-
expiresIn: number;
|
|
64
|
-
fetchImpl?: typeof fetch;
|
|
65
|
-
groupSizeBytes?: number;
|
|
66
|
-
readTimeoutMs?: number;
|
|
67
|
-
}): Promise<Map<number, string>>;
|
|
68
|
-
export declare function computeChunkContentMd5(input: {
|
|
69
|
-
source: ProviderSourceConfig;
|
|
70
|
-
chunk: ChunkSigningPlanItem;
|
|
71
|
-
expiresIn: number;
|
|
72
|
-
fetchImpl?: typeof fetch;
|
|
73
|
-
readTimeoutMs?: number;
|
|
74
|
-
}): Promise<string>;
|
|
75
59
|
export declare function isS3CompatibleProvider(config: ProviderSourceConfig | ProviderDestinationConfig): config is AnyS3CompatibleProviderConfig;
|
|
76
60
|
export declare function s3CompatibleEndpoint(source: AnyS3CompatibleProviderConfig): string | undefined;
|
|
77
61
|
export declare function s3CompatibleRegion(source: AnyS3CompatibleProviderConfig): string;
|