@stackshift-cloud/sdk 0.1.4 → 1.1.0
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 +63 -3
- package/dist/asset-media-v2.d.ts +65 -0
- package/dist/asset-workflows.d.ts +269 -0
- package/dist/asset-workflows.js +69 -0
- package/dist/assets-platform-types.d.ts +218 -0
- package/dist/assets-platform-types.js +1 -0
- package/dist/assets-platform.d.ts +55 -0
- package/dist/assets-platform.js +90 -0
- package/dist/assets.d.ts +16 -0
- package/dist/assets.js +74 -130
- package/dist/client.d.ts +6 -0
- package/dist/client.js +15 -6
- package/dist/generated/assets-contract.d.ts +267 -2
- package/dist/generated/assets-contract.js +53 -0
- package/dist/index.d.ts +17 -5
- package/dist/index.js +5 -1
- package/dist/mail-advanced-types.d.ts +25 -3
- package/dist/mail-advanced.d.ts +8 -1
- package/dist/mail-advanced.js +9 -0
- package/dist/mail-campaigns.d.ts +76 -0
- package/dist/mail-campaigns.js +42 -0
- package/dist/mail-delivery-types.js +1 -0
- package/dist/mail-diagnostics.d.ts +23 -0
- package/dist/mail-diagnostics.js +1 -0
- package/dist/mail-events-webhooks.d.ts +3 -2
- package/dist/mail-events-webhooks.js +10 -2
- package/dist/mail-exports.d.ts +32 -0
- package/dist/mail-exports.js +18 -0
- package/dist/mail-streams.d.ts +27 -0
- package/dist/mail-streams.js +12 -0
- package/dist/mail-webhook-types.d.ts +12 -1
- package/dist/mail.d.ts +14 -2
- package/dist/mail.js +22 -2
- package/dist/types.d.ts +56 -3
- package/dist/upload-controller.d.ts +70 -0
- package/dist/upload-controller.js +223 -0
- package/package.json +2 -2
- /package/dist/{mail-phase4-types.js → asset-media-v2.js} +0 -0
- /package/dist/{mail-phase4-types.d.ts → mail-delivery-types.d.ts} +0 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import type { Asset, AssetBucket, JsonValue } from './types.js';
|
|
2
|
+
export type AssetConnectionProvider = 'aws_s3' | 'r2' | 'wasabi' | 'minio' | 's3' | 'stackshift_s2' | 'cloudinary';
|
|
3
|
+
export type AssetConnectionStatus = 'unverified' | 'verified' | 'failed' | 'revoked';
|
|
4
|
+
export type AssetStorageMode = 'managed' | 'byob' | 'stackshift_s2';
|
|
5
|
+
export type AssetMigrationStatus = 'queued' | 'running' | 'completed' | 'failed' | 'canceled';
|
|
6
|
+
export type AssetMigrationItemStatus = 'queued' | 'running' | 'imported' | 'skipped' | 'failed' | 'canceled';
|
|
7
|
+
export interface AssetConnection {
|
|
8
|
+
id: string;
|
|
9
|
+
provider: AssetConnectionProvider;
|
|
10
|
+
name: string;
|
|
11
|
+
configuration: Record<string, JsonValue>;
|
|
12
|
+
external_id: string;
|
|
13
|
+
s2_bucket_id?: string;
|
|
14
|
+
status: AssetConnectionStatus;
|
|
15
|
+
last_verified_at?: string;
|
|
16
|
+
verification_error?: string;
|
|
17
|
+
created_at: string;
|
|
18
|
+
updated_at: string;
|
|
19
|
+
}
|
|
20
|
+
export interface AssetS3ConnectionConfiguration {
|
|
21
|
+
bucket: string;
|
|
22
|
+
region?: string;
|
|
23
|
+
endpoint?: string;
|
|
24
|
+
prefix?: string;
|
|
25
|
+
role_arn?: string;
|
|
26
|
+
auth_type: 'assume_role' | 'static';
|
|
27
|
+
path_style?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface AssetS3StaticCredentials {
|
|
30
|
+
access_key_id: string;
|
|
31
|
+
secret_access_key: string;
|
|
32
|
+
session_token?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface AssetCloudinaryConfiguration {
|
|
35
|
+
cloud_name: string;
|
|
36
|
+
api_key: string;
|
|
37
|
+
}
|
|
38
|
+
export interface AssetCloudinaryCredentials {
|
|
39
|
+
api_secret: string;
|
|
40
|
+
}
|
|
41
|
+
interface AssetConnectionInputBase {
|
|
42
|
+
name: string;
|
|
43
|
+
}
|
|
44
|
+
export type AssetConnectionInput = AssetConnectionInputBase & ({
|
|
45
|
+
provider: 'aws_s3';
|
|
46
|
+
configuration: AssetS3ConnectionConfiguration;
|
|
47
|
+
credentials?: AssetS3StaticCredentials;
|
|
48
|
+
} | {
|
|
49
|
+
provider: 'r2' | 'wasabi' | 'minio' | 's3';
|
|
50
|
+
configuration: AssetS3ConnectionConfiguration;
|
|
51
|
+
credentials: AssetS3StaticCredentials;
|
|
52
|
+
} | {
|
|
53
|
+
provider: 'cloudinary';
|
|
54
|
+
configuration: AssetCloudinaryConfiguration;
|
|
55
|
+
credentials: AssetCloudinaryCredentials;
|
|
56
|
+
} | {
|
|
57
|
+
provider: 'stackshift_s2';
|
|
58
|
+
s2_bucket_id: string;
|
|
59
|
+
configuration?: never;
|
|
60
|
+
credentials?: never;
|
|
61
|
+
});
|
|
62
|
+
export interface AssetStorageConfiguration {
|
|
63
|
+
storage_mode: AssetStorageMode;
|
|
64
|
+
connection_id?: string;
|
|
65
|
+
s2_bucket_id?: string;
|
|
66
|
+
object_prefix?: string;
|
|
67
|
+
derivative_prefix?: string;
|
|
68
|
+
auto_extract_text?: boolean;
|
|
69
|
+
expected_revision?: number;
|
|
70
|
+
}
|
|
71
|
+
export interface AssetS2Bucket {
|
|
72
|
+
id: string;
|
|
73
|
+
name: string;
|
|
74
|
+
workspace_id?: string;
|
|
75
|
+
project_id?: string;
|
|
76
|
+
region: string;
|
|
77
|
+
visibility: string;
|
|
78
|
+
versioning_enabled: boolean;
|
|
79
|
+
quota_bytes?: number;
|
|
80
|
+
object_count: number;
|
|
81
|
+
size_bytes: number;
|
|
82
|
+
created_at: string;
|
|
83
|
+
updated_at: string;
|
|
84
|
+
}
|
|
85
|
+
export interface AssetMigrationInput {
|
|
86
|
+
kind?: 'import' | 'relocate';
|
|
87
|
+
source_connection_id?: string;
|
|
88
|
+
destination_bucket_id: string;
|
|
89
|
+
source_prefix?: string;
|
|
90
|
+
conflict_policy?: 'skip' | 'new_version' | 'rename';
|
|
91
|
+
dry_run?: boolean;
|
|
92
|
+
}
|
|
93
|
+
export interface AssetMigration {
|
|
94
|
+
id: string;
|
|
95
|
+
kind: 'import' | 'relocate';
|
|
96
|
+
source_connection_id?: string;
|
|
97
|
+
destination_bucket_id: string;
|
|
98
|
+
source_prefix: string;
|
|
99
|
+
conflict_policy: 'skip' | 'new_version' | 'rename';
|
|
100
|
+
dry_run: boolean;
|
|
101
|
+
status: AssetMigrationStatus;
|
|
102
|
+
phase: 'inventory' | 'transfer' | 'complete' | string;
|
|
103
|
+
total_items: number;
|
|
104
|
+
processed_items: number;
|
|
105
|
+
imported_items: number;
|
|
106
|
+
skipped_items: number;
|
|
107
|
+
failed_items: number;
|
|
108
|
+
total_bytes: number;
|
|
109
|
+
processed_bytes: number;
|
|
110
|
+
report: Record<string, JsonValue>;
|
|
111
|
+
cancel_requested_at?: string;
|
|
112
|
+
started_at?: string;
|
|
113
|
+
completed_at?: string;
|
|
114
|
+
created_at: string;
|
|
115
|
+
updated_at: string;
|
|
116
|
+
}
|
|
117
|
+
export interface AssetMigrationItem {
|
|
118
|
+
id: string;
|
|
119
|
+
migration_id: string;
|
|
120
|
+
source_identity: string;
|
|
121
|
+
source_key: string;
|
|
122
|
+
destination_key: string;
|
|
123
|
+
content_type?: string;
|
|
124
|
+
size?: number;
|
|
125
|
+
checksum_sha256?: string;
|
|
126
|
+
checksum_state: 'known' | 'pending_execution' | 'verified';
|
|
127
|
+
source_metadata: Record<string, JsonValue>;
|
|
128
|
+
source_tags: string[];
|
|
129
|
+
status: AssetMigrationItemStatus;
|
|
130
|
+
attempt_count: number;
|
|
131
|
+
max_attempts: number;
|
|
132
|
+
mapped_asset_id?: string;
|
|
133
|
+
warning_code?: string;
|
|
134
|
+
error_code?: string;
|
|
135
|
+
error_message?: string;
|
|
136
|
+
created_at: string;
|
|
137
|
+
updated_at: string;
|
|
138
|
+
finished_at?: string;
|
|
139
|
+
}
|
|
140
|
+
export interface AssetTextBlock {
|
|
141
|
+
text: string;
|
|
142
|
+
type: string;
|
|
143
|
+
confidence: number;
|
|
144
|
+
box: [number, number, number, number];
|
|
145
|
+
}
|
|
146
|
+
export interface AssetTextPage {
|
|
147
|
+
number: number;
|
|
148
|
+
width: number;
|
|
149
|
+
height: number;
|
|
150
|
+
blocks: AssetTextBlock[];
|
|
151
|
+
}
|
|
152
|
+
export interface AssetTextExtraction {
|
|
153
|
+
id: string;
|
|
154
|
+
checksum_sha256: string;
|
|
155
|
+
provider: string;
|
|
156
|
+
engine_version: string;
|
|
157
|
+
language: string;
|
|
158
|
+
options_hash: string;
|
|
159
|
+
status: 'pending' | 'processing' | 'ready' | 'failed';
|
|
160
|
+
plain_text?: string;
|
|
161
|
+
pages: AssetTextPage[];
|
|
162
|
+
page_count: number;
|
|
163
|
+
error_code?: string;
|
|
164
|
+
error_message?: string;
|
|
165
|
+
created_at: string;
|
|
166
|
+
updated_at: string;
|
|
167
|
+
completed_at?: string;
|
|
168
|
+
}
|
|
169
|
+
export interface AssetUploadCapabilityInput {
|
|
170
|
+
bucket: string;
|
|
171
|
+
key_prefix?: string;
|
|
172
|
+
fixed_key?: string;
|
|
173
|
+
allowed_mime_types?: string[];
|
|
174
|
+
allowed_origins: string[];
|
|
175
|
+
max_bytes: number;
|
|
176
|
+
allow_remote_url?: boolean;
|
|
177
|
+
expires_in: string;
|
|
178
|
+
}
|
|
179
|
+
export interface AssetUploadCapability {
|
|
180
|
+
id: string;
|
|
181
|
+
bucket: string;
|
|
182
|
+
key_prefix: string;
|
|
183
|
+
fixed_key?: string;
|
|
184
|
+
allowed_mime_types: string[];
|
|
185
|
+
allowed_origins: string[];
|
|
186
|
+
max_bytes: number;
|
|
187
|
+
allow_remote_url: boolean;
|
|
188
|
+
session_id?: string;
|
|
189
|
+
expires_at: string;
|
|
190
|
+
created_at: string;
|
|
191
|
+
}
|
|
192
|
+
export interface CreatedAssetUploadCapability {
|
|
193
|
+
capability: AssetUploadCapability;
|
|
194
|
+
token: string;
|
|
195
|
+
}
|
|
196
|
+
export interface AssetMigrationListResult {
|
|
197
|
+
migrations: AssetMigration[];
|
|
198
|
+
}
|
|
199
|
+
export interface AssetConnectionListResult {
|
|
200
|
+
connections: AssetConnection[];
|
|
201
|
+
}
|
|
202
|
+
export interface AssetS2BucketListResult {
|
|
203
|
+
buckets: AssetS2Bucket[];
|
|
204
|
+
}
|
|
205
|
+
export interface AssetRelocationInput {
|
|
206
|
+
dry_run?: boolean;
|
|
207
|
+
}
|
|
208
|
+
export interface AssetTextExtractionInput {
|
|
209
|
+
language?: string;
|
|
210
|
+
options?: Record<string, JsonValue>;
|
|
211
|
+
}
|
|
212
|
+
export type AssetMigrationReport = {
|
|
213
|
+
migration: AssetMigration;
|
|
214
|
+
items: AssetMigrationItem[];
|
|
215
|
+
} | Record<string, JsonValue>;
|
|
216
|
+
export type AssetCapabilityUploadResult = Asset;
|
|
217
|
+
export type AssetStorageBucket = AssetBucket;
|
|
218
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { StackShift } from './client.js';
|
|
2
|
+
import type { AssetBucket } from './types.js';
|
|
3
|
+
import type { AssetConnection, AssetConnectionInput, AssetConnectionListResult, AssetMigration, AssetMigrationInput, AssetMigrationListResult, AssetMigrationReport, AssetRelocationInput, AssetS2Bucket, AssetS2BucketListResult, AssetStorageConfiguration, AssetTextExtraction, AssetTextExtractionInput, AssetUploadCapabilityInput, CreatedAssetUploadCapability } from './assets-platform-types.js';
|
|
4
|
+
export declare class AssetConnectionsClient {
|
|
5
|
+
private readonly client;
|
|
6
|
+
constructor(client: StackShift);
|
|
7
|
+
list(): Promise<AssetConnectionListResult>;
|
|
8
|
+
get(connectionId: string): Promise<AssetConnection>;
|
|
9
|
+
create(input: AssetConnectionInput): Promise<AssetConnection>;
|
|
10
|
+
update(connectionId: string, input: Partial<AssetConnectionInput>): Promise<AssetConnection>;
|
|
11
|
+
verify(connectionId: string): Promise<AssetConnection>;
|
|
12
|
+
delete(connectionId: string): Promise<{
|
|
13
|
+
deleted: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export declare class AssetStorageClient {
|
|
17
|
+
private readonly client;
|
|
18
|
+
constructor(client: StackShift);
|
|
19
|
+
configure(bucketId: string, revision: number, input: AssetStorageConfiguration): Promise<AssetBucket>;
|
|
20
|
+
listS2Buckets(): Promise<AssetS2BucketListResult>;
|
|
21
|
+
createS2Bucket(input: {
|
|
22
|
+
name: string;
|
|
23
|
+
region: string;
|
|
24
|
+
}): Promise<AssetS2Bucket>;
|
|
25
|
+
relocate(bucketId: string, input?: AssetRelocationInput): Promise<AssetMigration>;
|
|
26
|
+
}
|
|
27
|
+
export declare class AssetMigrationsClient {
|
|
28
|
+
private readonly client;
|
|
29
|
+
constructor(client: StackShift);
|
|
30
|
+
start(input: AssetMigrationInput): Promise<AssetMigration>;
|
|
31
|
+
list(options?: {
|
|
32
|
+
limit?: number;
|
|
33
|
+
}): Promise<AssetMigrationListResult>;
|
|
34
|
+
get(migrationId: string): Promise<AssetMigration>;
|
|
35
|
+
cancel(migrationId: string): Promise<{
|
|
36
|
+
canceled: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
retryItem(migrationId: string, itemId: string): Promise<{
|
|
39
|
+
queued: boolean;
|
|
40
|
+
}>;
|
|
41
|
+
report(migrationId: string, format?: 'json'): Promise<AssetMigrationReport>;
|
|
42
|
+
downloadReport(migrationId: string, format?: 'json' | 'csv'): Promise<Blob>;
|
|
43
|
+
}
|
|
44
|
+
export declare class AssetTextClient {
|
|
45
|
+
private readonly client;
|
|
46
|
+
constructor(client: StackShift);
|
|
47
|
+
start(assetId: string, input?: AssetTextExtractionInput): Promise<AssetTextExtraction>;
|
|
48
|
+
get(assetId: string): Promise<AssetTextExtraction>;
|
|
49
|
+
retry(extractionId: string): Promise<AssetTextExtraction>;
|
|
50
|
+
}
|
|
51
|
+
export declare class AssetUploadCapabilitiesClient {
|
|
52
|
+
private readonly client;
|
|
53
|
+
constructor(client: StackShift);
|
|
54
|
+
create(input: AssetUploadCapabilityInput): Promise<CreatedAssetUploadCapability>;
|
|
55
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const encoded = encodeURIComponent;
|
|
2
|
+
export class AssetConnectionsClient {
|
|
3
|
+
client;
|
|
4
|
+
constructor(client) {
|
|
5
|
+
this.client = client;
|
|
6
|
+
}
|
|
7
|
+
list() { return this.client.request('/assets/connections'); }
|
|
8
|
+
get(connectionId) { return this.client.request(`/assets/connections/${encoded(connectionId)}`); }
|
|
9
|
+
create(input) {
|
|
10
|
+
return this.client.request('/assets/connections', { method: 'POST', body: input });
|
|
11
|
+
}
|
|
12
|
+
update(connectionId, input) {
|
|
13
|
+
return this.client.request(`/assets/connections/${encoded(connectionId)}`, { method: 'PATCH', body: input });
|
|
14
|
+
}
|
|
15
|
+
verify(connectionId) {
|
|
16
|
+
return this.client.request(`/assets/connections/${encoded(connectionId)}/verify`, { method: 'POST' });
|
|
17
|
+
}
|
|
18
|
+
delete(connectionId) {
|
|
19
|
+
return this.client.request(`/assets/connections/${encoded(connectionId)}`, { method: 'DELETE' });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class AssetStorageClient {
|
|
23
|
+
client;
|
|
24
|
+
constructor(client) {
|
|
25
|
+
this.client = client;
|
|
26
|
+
}
|
|
27
|
+
configure(bucketId, revision, input) {
|
|
28
|
+
return this.client.request(`/assets/buckets/${encoded(bucketId)}/storage`, {
|
|
29
|
+
method: 'PUT', body: input, headers: { 'If-Match': `"${revision}"` },
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
listS2Buckets() { return this.client.request('/assets/s2-buckets'); }
|
|
33
|
+
createS2Bucket(input) {
|
|
34
|
+
return this.client.request('/assets/s2-buckets', { method: 'POST', body: input });
|
|
35
|
+
}
|
|
36
|
+
relocate(bucketId, input = {}) {
|
|
37
|
+
return this.client.request(`/assets/buckets/${encoded(bucketId)}/relocations`, { method: 'POST', body: input });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export class AssetMigrationsClient {
|
|
41
|
+
client;
|
|
42
|
+
constructor(client) {
|
|
43
|
+
this.client = client;
|
|
44
|
+
}
|
|
45
|
+
start(input) {
|
|
46
|
+
return this.client.request('/assets/migrations', { method: 'POST', body: input });
|
|
47
|
+
}
|
|
48
|
+
list(options = {}) {
|
|
49
|
+
const query = new URLSearchParams();
|
|
50
|
+
if (options.limit !== undefined)
|
|
51
|
+
query.set('limit', String(options.limit));
|
|
52
|
+
const suffix = query.toString();
|
|
53
|
+
return this.client.request(`/assets/migrations${suffix ? `?${suffix}` : ''}`);
|
|
54
|
+
}
|
|
55
|
+
get(migrationId) { return this.client.request(`/assets/migrations/${encoded(migrationId)}`); }
|
|
56
|
+
cancel(migrationId) {
|
|
57
|
+
return this.client.request(`/assets/migrations/${encoded(migrationId)}/cancel`, { method: 'POST' });
|
|
58
|
+
}
|
|
59
|
+
retryItem(migrationId, itemId) {
|
|
60
|
+
return this.client.request(`/assets/migrations/${encoded(migrationId)}/items/${encoded(itemId)}/retry`, { method: 'POST' });
|
|
61
|
+
}
|
|
62
|
+
report(migrationId, format = 'json') {
|
|
63
|
+
return this.client.request(`/assets/migrations/${encoded(migrationId)}/report?format=${format}`);
|
|
64
|
+
}
|
|
65
|
+
async downloadReport(migrationId, format = 'json') {
|
|
66
|
+
return this.client.requestRaw(`/assets/migrations/${encoded(migrationId)}/report?format=${format}`).then((response) => response.blob());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export class AssetTextClient {
|
|
70
|
+
client;
|
|
71
|
+
constructor(client) {
|
|
72
|
+
this.client = client;
|
|
73
|
+
}
|
|
74
|
+
start(assetId, input = {}) {
|
|
75
|
+
return this.client.request(`/assets/${encoded(assetId)}/text-extraction`, { method: 'POST', body: input });
|
|
76
|
+
}
|
|
77
|
+
get(assetId) { return this.client.request(`/assets/${encoded(assetId)}/text-extraction`); }
|
|
78
|
+
retry(extractionId) {
|
|
79
|
+
return this.client.request(`/assets/text-extractions/${encoded(extractionId)}/retry`, { method: 'POST' });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export class AssetUploadCapabilitiesClient {
|
|
83
|
+
client;
|
|
84
|
+
constructor(client) {
|
|
85
|
+
this.client = client;
|
|
86
|
+
}
|
|
87
|
+
create(input) {
|
|
88
|
+
return this.client.request('/assets/upload-capabilities', { method: 'POST', body: input });
|
|
89
|
+
}
|
|
90
|
+
}
|
package/dist/assets.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { StackShift } from './client.js';
|
|
2
|
+
import { AssetConnectionsClient, AssetMigrationsClient, AssetStorageClient, AssetTextClient, AssetUploadCapabilitiesClient } from './assets-platform.js';
|
|
3
|
+
import { AssetWorkflowsClient } from './asset-workflows.js';
|
|
4
|
+
import type { AssetDerivedAsset, AssetImageGenerationInput, AssetTransformDefinition, AssetTransformMaterializeInput } from './asset-media-v2.js';
|
|
2
5
|
import type { Asset, AssetBucket, AssetBucketInput, AssetAIAccountConfig, AssetPatchInput, AssetCustomDomain, AssetEvent, AssetJob, AssetJobSubmission, AssetLifecycleRule, AssetUsageSummary, AssetWebhook, AssetWebhookDelivery, AssetAIInfo, AssetCollection, AssetContentPolicy, AssetNamedTransformInput, AssetListOptions, AssetListResult, AssetSavedSearch, AssetTranscript, AssetUploadProgressCallbacks, AssetVersion, AssetSignedUploadUrl, AssetSignedUploadUrlOptions, AssetSignedTransformOptions, AssetSignedUrl, AssetSignedUrlOptions, AssetTransformOptions, AssetTransformPreset, AssetUploadOptions } from './types.js';
|
|
3
6
|
export declare const assetTransformPresets: AssetTransformPreset[];
|
|
4
7
|
export declare function getAssetTransformPreset(name: string): AssetTransformPreset | undefined;
|
|
@@ -6,6 +9,12 @@ export declare function assetTransformOptions(preset: AssetTransformPreset): Ass
|
|
|
6
9
|
export declare function assetTransformSpec(options: AssetTransformOptions): string;
|
|
7
10
|
export declare class AssetsClient {
|
|
8
11
|
private readonly client;
|
|
12
|
+
readonly connections: AssetConnectionsClient;
|
|
13
|
+
readonly storage: AssetStorageClient;
|
|
14
|
+
readonly migrations: AssetMigrationsClient;
|
|
15
|
+
readonly text: AssetTextClient;
|
|
16
|
+
readonly uploadCapabilities: AssetUploadCapabilitiesClient;
|
|
17
|
+
readonly workflows: AssetWorkflowsClient;
|
|
9
18
|
constructor(client: StackShift);
|
|
10
19
|
upload(file: Blob, options?: AssetUploadOptions): Promise<Asset>;
|
|
11
20
|
list(options?: AssetListOptions): Promise<AssetListResult>;
|
|
@@ -95,6 +104,13 @@ export declare class AssetsClient {
|
|
|
95
104
|
getPolicy(): Promise<AssetContentPolicy>;
|
|
96
105
|
updatePolicy(policy: AssetContentPolicy): Promise<AssetContentPolicy>;
|
|
97
106
|
createTransformation(input: AssetNamedTransformInput): Promise<unknown>;
|
|
107
|
+
createTransformationV2(name: string, definition: AssetTransformDefinition, eager?: boolean): Promise<unknown>;
|
|
108
|
+
materializeTransform(assetId: string, input: AssetTransformMaterializeInput, idempotencyKey?: string): Promise<AssetJobSubmission>;
|
|
109
|
+
derivatives(assetId: string): Promise<{
|
|
110
|
+
derivatives: AssetDerivedAsset[];
|
|
111
|
+
}>;
|
|
112
|
+
generate(input: AssetImageGenerationInput, idempotencyKey: string): Promise<AssetJobSubmission>;
|
|
113
|
+
automation(): Promise<import("./asset-workflows.js").AssetAutomationOverview>;
|
|
98
114
|
listTransformations(): Promise<unknown>;
|
|
99
115
|
deleteTransformation(name: string): Promise<{
|
|
100
116
|
deleted: boolean;
|
package/dist/assets.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { AssetConnectionsClient, AssetMigrationsClient, AssetStorageClient, AssetTextClient, AssetUploadCapabilitiesClient } from './assets-platform.js';
|
|
2
|
+
import { AssetWorkflowsClient } from './asset-workflows.js';
|
|
3
|
+
import { ChunkedUploadController, putBlob, sha256Blob } from './upload-controller.js';
|
|
1
4
|
export const assetTransformPresets = [
|
|
2
5
|
preset('web-thumbnail', 'responsive-web', 'Compact grid thumbnail for libraries and dashboards.', 320, 180, 'fill', 'webp', 78),
|
|
3
6
|
preset('web-card', 'responsive-web', 'Balanced card image for product and content listings.', 640, 360, 'fill', 'webp', 82),
|
|
@@ -41,8 +44,20 @@ export function assetTransformSpec(options) {
|
|
|
41
44
|
}
|
|
42
45
|
export class AssetsClient {
|
|
43
46
|
client;
|
|
47
|
+
connections;
|
|
48
|
+
storage;
|
|
49
|
+
migrations;
|
|
50
|
+
text;
|
|
51
|
+
uploadCapabilities;
|
|
52
|
+
workflows;
|
|
44
53
|
constructor(client) {
|
|
45
54
|
this.client = client;
|
|
55
|
+
this.connections = new AssetConnectionsClient(client);
|
|
56
|
+
this.storage = new AssetStorageClient(client);
|
|
57
|
+
this.migrations = new AssetMigrationsClient(client);
|
|
58
|
+
this.text = new AssetTextClient(client);
|
|
59
|
+
this.uploadCapabilities = new AssetUploadCapabilitiesClient(client);
|
|
60
|
+
this.workflows = new AssetWorkflowsClient(client);
|
|
46
61
|
}
|
|
47
62
|
upload(file, options = {}) {
|
|
48
63
|
return this.client.request('/assets/upload', {
|
|
@@ -130,7 +145,13 @@ export class AssetsClient {
|
|
|
130
145
|
const target = uploadUrlOrToken.startsWith('http')
|
|
131
146
|
? `${uploadUrlOrToken.replace(/\/$/, '')}/parts/${partNumber}`
|
|
132
147
|
: `${this.originBaseUrl()}/uploads/${encodeURIComponent(uploadUrlOrToken)}/parts/${partNumber}`;
|
|
133
|
-
return
|
|
148
|
+
return putBlob(target, chunk, {
|
|
149
|
+
signal: callbacks.signal,
|
|
150
|
+
onProgress: (progress) => {
|
|
151
|
+
callbacks.onProgress?.(progress);
|
|
152
|
+
callbacks.onPartProgress?.(partNumber, progress);
|
|
153
|
+
},
|
|
154
|
+
}, { 'X-Content-SHA256': await sha256Blob(chunk) });
|
|
134
155
|
}
|
|
135
156
|
resumeUploadSession(sessionId) {
|
|
136
157
|
return this.client.request(`/assets/upload-sessions/${encodeURIComponent(sessionId)}`);
|
|
@@ -190,56 +211,22 @@ export class AssetsClient {
|
|
|
190
211
|
fileName: options.fileName ?? blobName(file),
|
|
191
212
|
mimeType: options.mimeType ?? file.type,
|
|
192
213
|
});
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
};
|
|
209
|
-
reportProgress();
|
|
210
|
-
const concurrency = boundedInteger(options.concurrency, 4, 1, 8);
|
|
211
|
-
const attempts = boundedInteger(options.retryAttempts, 4, 1, 8);
|
|
212
|
-
let next = 0;
|
|
213
|
-
const worker = async () => {
|
|
214
|
-
while (next < tasks.length) {
|
|
215
|
-
throwIfAborted(callbacks.signal);
|
|
216
|
-
const task = tasks[next++];
|
|
217
|
-
await retryWithBackoff(async () => {
|
|
218
|
-
throwIfAborted(callbacks.signal);
|
|
219
|
-
await this.uploadChunk(session.upload_session_id, task.part, task.chunk, {
|
|
220
|
-
signal: callbacks.signal,
|
|
221
|
-
onProgress: (progress) => {
|
|
222
|
-
loadedByPart.set(task.part, progress.loaded);
|
|
223
|
-
callbacks.onPartProgress?.(task.part, progress);
|
|
224
|
-
reportProgress();
|
|
225
|
-
},
|
|
226
|
-
});
|
|
227
|
-
loadedByPart.set(task.part, task.chunk.size);
|
|
228
|
-
reportProgress();
|
|
229
|
-
}, attempts, callbacks.signal);
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
try {
|
|
233
|
-
await Promise.all(Array.from({ length: Math.min(concurrency, tasks.length || 1) }, worker));
|
|
234
|
-
throwIfAborted(callbacks.signal);
|
|
235
|
-
return await retryWithBackoff(() => this.completeUploadSession(sessionId), attempts, callbacks.signal);
|
|
236
|
-
}
|
|
237
|
-
catch (error) {
|
|
238
|
-
if (isAbortError(error)) {
|
|
239
|
-
await this.cancelUploadSession(sessionId).catch(() => undefined);
|
|
240
|
-
}
|
|
241
|
-
throw error;
|
|
242
|
-
}
|
|
214
|
+
const controller = new ChunkedUploadController({
|
|
215
|
+
create: async () => toControllerSession(session),
|
|
216
|
+
resume: async (sessionId) => toControllerSession(await this.resumeUploadSession(sessionId)),
|
|
217
|
+
uploadPart: async (current, partNumber, chunk, checksum, progress) => {
|
|
218
|
+
const target = `${this.originBaseUrl()}/uploads/${encodeURIComponent(current.uploadToken)}/parts/${partNumber}`;
|
|
219
|
+
await putBlob(target, chunk, progress, { 'X-Content-SHA256': checksum });
|
|
220
|
+
},
|
|
221
|
+
complete: (current) => this.completeUploadSession(current.id),
|
|
222
|
+
cancel: (current) => this.cancelUploadSession(current.id).then(() => undefined),
|
|
223
|
+
});
|
|
224
|
+
return controller.upload(file, {
|
|
225
|
+
key: options.key ?? options.fileName ?? blobName(file) ?? 'upload',
|
|
226
|
+
fileName: options.fileName ?? blobName(file) ?? 'upload',
|
|
227
|
+
mimeType: options.mimeType ?? file.type,
|
|
228
|
+
metadata: options.metadata,
|
|
229
|
+
}, { ...callbacks, concurrency: options.concurrency, retryAttempts: options.retryAttempts, cancelOnAbort: true });
|
|
243
230
|
}
|
|
244
231
|
url(assetId, options) {
|
|
245
232
|
return `${this.client.cdnBaseUrl}/assets/${encodeURIComponent(assetId)}/tr/${encodeURIComponent(transformSpec(options))}`;
|
|
@@ -346,6 +333,28 @@ export class AssetsClient {
|
|
|
346
333
|
body: input,
|
|
347
334
|
});
|
|
348
335
|
}
|
|
336
|
+
createTransformationV2(name, definition, eager = false) {
|
|
337
|
+
return this.client.request('/assets/transformations', {
|
|
338
|
+
method: 'POST', body: { name, definition, eager },
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
materializeTransform(assetId, input, idempotencyKey) {
|
|
342
|
+
return this.client.request(`/assets/${encodeURIComponent(assetId)}/transforms`, {
|
|
343
|
+
method: 'POST', body: input,
|
|
344
|
+
headers: idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : undefined,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
derivatives(assetId) {
|
|
348
|
+
return this.client.request(`/assets/${encodeURIComponent(assetId)}/derivatives`);
|
|
349
|
+
}
|
|
350
|
+
generate(input, idempotencyKey) {
|
|
351
|
+
return this.client.request('/assets/generations', {
|
|
352
|
+
method: 'POST', body: input, headers: { 'Idempotency-Key': idempotencyKey },
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
automation() {
|
|
356
|
+
return this.client.request('/assets/automation');
|
|
357
|
+
}
|
|
349
358
|
listTransformations() {
|
|
350
359
|
return this.client.request('/assets/transformations');
|
|
351
360
|
}
|
|
@@ -441,7 +450,7 @@ export class AssetsClient {
|
|
|
441
450
|
mode: 'single',
|
|
442
451
|
maxBytes: options.maxBytes ?? file.size,
|
|
443
452
|
});
|
|
444
|
-
await
|
|
453
|
+
await putBlob(session.url, file, callbacks);
|
|
445
454
|
return session;
|
|
446
455
|
}
|
|
447
456
|
}
|
|
@@ -495,82 +504,6 @@ const defaultPartSize = 5 * 1024 * 1024;
|
|
|
495
504
|
function blobName(file) {
|
|
496
505
|
return file.name;
|
|
497
506
|
}
|
|
498
|
-
function uploadBlob(url, blob, callbacks, partNumber, headers = {}) {
|
|
499
|
-
if (typeof XMLHttpRequest === 'undefined') {
|
|
500
|
-
return fetch(url, { method: 'PUT', body: blob, signal: callbacks.signal, headers }).then((response) => {
|
|
501
|
-
if (!response.ok)
|
|
502
|
-
throw new Error(`Upload failed with ${response.status}`);
|
|
503
|
-
const progress = { loaded: blob.size, total: blob.size, percent: 100 };
|
|
504
|
-
callbacks.onProgress?.(progress);
|
|
505
|
-
if (partNumber)
|
|
506
|
-
callbacks.onPartProgress?.(partNumber, progress);
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
return new Promise((resolve, reject) => {
|
|
510
|
-
const xhr = new XMLHttpRequest();
|
|
511
|
-
xhr.open('PUT', url);
|
|
512
|
-
for (const [name, value] of Object.entries(headers))
|
|
513
|
-
xhr.setRequestHeader(name, value);
|
|
514
|
-
const abort = () => xhr.abort();
|
|
515
|
-
callbacks.signal?.addEventListener('abort', abort, { once: true });
|
|
516
|
-
xhr.upload.onprogress = (event) => {
|
|
517
|
-
const total = event.total || blob.size;
|
|
518
|
-
const progress = { loaded: event.loaded, total, percent: total ? Math.round((event.loaded / total) * 100) : 0 };
|
|
519
|
-
callbacks.onProgress?.(progress);
|
|
520
|
-
if (partNumber)
|
|
521
|
-
callbacks.onPartProgress?.(partNumber, progress);
|
|
522
|
-
};
|
|
523
|
-
const cleanup = () => callbacks.signal?.removeEventListener('abort', abort);
|
|
524
|
-
xhr.onload = () => {
|
|
525
|
-
cleanup();
|
|
526
|
-
if (xhr.status >= 200 && xhr.status < 300)
|
|
527
|
-
resolve();
|
|
528
|
-
else
|
|
529
|
-
reject(new Error(`Upload failed with ${xhr.status}`));
|
|
530
|
-
};
|
|
531
|
-
xhr.onerror = () => { cleanup(); reject(new Error('Upload failed')); };
|
|
532
|
-
xhr.onabort = () => { cleanup(); reject(abortError()); };
|
|
533
|
-
xhr.send(blob);
|
|
534
|
-
});
|
|
535
|
-
}
|
|
536
|
-
async function sha256Blob(blob) {
|
|
537
|
-
if (!globalThis.crypto?.subtle)
|
|
538
|
-
throw new Error('Web Crypto SHA-256 is required for multipart uploads');
|
|
539
|
-
const digest = await globalThis.crypto.subtle.digest('SHA-256', await blob.arrayBuffer());
|
|
540
|
-
return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
541
|
-
}
|
|
542
|
-
function boundedInteger(value, fallback, minimum, maximum) {
|
|
543
|
-
if (value === undefined)
|
|
544
|
-
return fallback;
|
|
545
|
-
if (!Number.isSafeInteger(value))
|
|
546
|
-
throw new Error('Upload concurrency and retry attempts must be integers');
|
|
547
|
-
return Math.min(maximum, Math.max(minimum, value));
|
|
548
|
-
}
|
|
549
|
-
async function retryWithBackoff(operation, attempts, signal) {
|
|
550
|
-
let lastError;
|
|
551
|
-
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
552
|
-
try {
|
|
553
|
-
return await operation();
|
|
554
|
-
}
|
|
555
|
-
catch (error) {
|
|
556
|
-
if (isAbortError(error) || signal?.aborted)
|
|
557
|
-
throw abortError();
|
|
558
|
-
lastError = error;
|
|
559
|
-
if (attempt + 1 < attempts)
|
|
560
|
-
await abortableDelay(250 * 2 ** attempt, signal);
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
throw lastError;
|
|
564
|
-
}
|
|
565
|
-
function abortableDelay(milliseconds, signal) {
|
|
566
|
-
throwIfAborted(signal);
|
|
567
|
-
return new Promise((resolve, reject) => {
|
|
568
|
-
const timer = setTimeout(() => { cleanup(); resolve(); }, milliseconds);
|
|
569
|
-
const abort = () => { clearTimeout(timer); cleanup(); reject(abortError()); };
|
|
570
|
-
const cleanup = () => signal?.removeEventListener('abort', abort);
|
|
571
|
-
signal?.addEventListener('abort', abort, { once: true });
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
507
|
function throwIfAborted(signal) {
|
|
575
508
|
if (signal?.aborted)
|
|
576
509
|
throw abortError();
|
|
@@ -578,6 +511,17 @@ function throwIfAborted(signal) {
|
|
|
578
511
|
function abortError() {
|
|
579
512
|
return typeof DOMException === 'undefined' ? Object.assign(new Error('Upload cancelled'), { name: 'AbortError' }) : new DOMException('Upload cancelled', 'AbortError');
|
|
580
513
|
}
|
|
581
|
-
function
|
|
582
|
-
|
|
514
|
+
function toControllerSession(session) {
|
|
515
|
+
const id = session.session_id;
|
|
516
|
+
if (!id)
|
|
517
|
+
throw new Error('Chunked upload session did not include a resumable session id');
|
|
518
|
+
return {
|
|
519
|
+
id,
|
|
520
|
+
uploadToken: session.upload_session_id,
|
|
521
|
+
expiresAt: session.expires_at,
|
|
522
|
+
maxBytes: session.max_bytes,
|
|
523
|
+
partSize: session.part_size ?? defaultPartSize,
|
|
524
|
+
parts: (session.parts ?? []).map((part) => ({ partNumber: part.part_number, size: part.size, checksumSHA256: part.checksum_sha256 })),
|
|
525
|
+
resumeContext: id,
|
|
526
|
+
};
|
|
583
527
|
}
|
package/dist/client.d.ts
CHANGED
|
@@ -17,12 +17,18 @@ export declare class StackShift {
|
|
|
17
17
|
body?: unknown;
|
|
18
18
|
headers?: Record<string, string>;
|
|
19
19
|
}): Promise<T>;
|
|
20
|
+
requestRaw(path: string, init?: {
|
|
21
|
+
method?: string;
|
|
22
|
+
body?: unknown;
|
|
23
|
+
headers?: Record<string, string>;
|
|
24
|
+
}): Promise<Response>;
|
|
20
25
|
mailRequest<T>(path: string, init?: {
|
|
21
26
|
method?: string;
|
|
22
27
|
body?: unknown;
|
|
23
28
|
headers?: Record<string, string>;
|
|
24
29
|
}): Promise<T>;
|
|
25
30
|
private requestFrom;
|
|
31
|
+
private fetchFrom;
|
|
26
32
|
}
|
|
27
33
|
export declare class StackShiftAPIError extends Error {
|
|
28
34
|
readonly status: number;
|