@ankhorage/contracts 7.3.0 → 7.4.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/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/dist/storage.d.ts +55 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js.map +1 -1
- package/package.json +1 -1
- package/src/storage-capabilities.test.ts +107 -0
- package/src/storage.ts +65 -0
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
# CONTRACTS
|
|
5
5
|
|
|
6
|
-
         
|
|
7
7
|
|
|
8
8
|
Serializable app, action, theme, auth, and secret-store contracts for Ankhorage.
|
|
9
9
|
|
package/dist/storage.d.ts
CHANGED
|
@@ -45,6 +45,46 @@ export interface StoragePublicUrlInput {
|
|
|
45
45
|
export interface StoragePublicUrlResult {
|
|
46
46
|
publicUrl: string;
|
|
47
47
|
}
|
|
48
|
+
export interface StorageObjectMetadata {
|
|
49
|
+
storageId?: string;
|
|
50
|
+
bucket: string;
|
|
51
|
+
path: string;
|
|
52
|
+
contentType?: string;
|
|
53
|
+
sizeBytes?: number;
|
|
54
|
+
createdAt?: string;
|
|
55
|
+
updatedAt?: string;
|
|
56
|
+
etag?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface StorageListInput {
|
|
59
|
+
storageId?: string;
|
|
60
|
+
bucket: string;
|
|
61
|
+
prefix?: string;
|
|
62
|
+
cursor?: string;
|
|
63
|
+
limit?: number;
|
|
64
|
+
}
|
|
65
|
+
export interface StorageListResult {
|
|
66
|
+
objects: readonly StorageObjectMetadata[];
|
|
67
|
+
nextCursor?: string;
|
|
68
|
+
}
|
|
69
|
+
export type StorageResolvedAccess = 'public' | 'signed';
|
|
70
|
+
export interface StorageResolveInput {
|
|
71
|
+
storageId?: string;
|
|
72
|
+
bucket: string;
|
|
73
|
+
path: string;
|
|
74
|
+
access?: StorageResolvedAccess;
|
|
75
|
+
expiresInSeconds?: number;
|
|
76
|
+
}
|
|
77
|
+
export interface StorageResolvedAsset {
|
|
78
|
+
storageId?: string;
|
|
79
|
+
bucket: string;
|
|
80
|
+
path: string;
|
|
81
|
+
url: string;
|
|
82
|
+
access: StorageResolvedAccess;
|
|
83
|
+
expiresAt?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface StorageResolveResult {
|
|
86
|
+
asset: StorageResolvedAsset;
|
|
87
|
+
}
|
|
48
88
|
export interface ImageMetadata {
|
|
49
89
|
fileName?: string;
|
|
50
90
|
sizeBytes?: number;
|
|
@@ -78,4 +118,19 @@ export interface StorageAdapter {
|
|
|
78
118
|
publicUrl(input: StoragePublicUrlInput): Promise<StorageResult<StoragePublicUrlResult>>;
|
|
79
119
|
getImageMetadata?(input: StorageAssetReference): Promise<StorageResult<ImageMetadata>>;
|
|
80
120
|
}
|
|
121
|
+
export interface StorageListAdapter {
|
|
122
|
+
list(input: StorageListInput): Promise<StorageResult<StorageListResult>>;
|
|
123
|
+
}
|
|
124
|
+
export interface StorageResolveAdapter {
|
|
125
|
+
resolve(input: StorageResolveInput): Promise<StorageResult<StorageResolveResult>>;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Storage capability required by the app-authoring media service.
|
|
129
|
+
*
|
|
130
|
+
* Remote URL import/ingest is intentionally not part of this low-level object-storage
|
|
131
|
+
* contract. It is a trusted service operation that can be implemented by reading the
|
|
132
|
+
* remote object and delegating to `upload` when ingestion is requested.
|
|
133
|
+
*/
|
|
134
|
+
export interface MediaStorageAdapter extends StorageAdapter, StorageListAdapter, StorageResolveAdapter {
|
|
135
|
+
}
|
|
81
136
|
//# sourceMappingURL=storage.d.ts.map
|
package/dist/storage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|
package/dist/storage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"","sourcesContent":["export interface StorageAdapterError {\n code: string;\n message: string;\n cause?: unknown;\n}\n\nexport type StorageOkResult<TData> = [TData] extends [void]\n ? { ok: true; data?: undefined }\n : { ok: true; data: TData };\n\nexport type StorageResult<TData = void> =\n | StorageOkResult<TData>\n | {\n ok: false;\n error: StorageAdapterError;\n };\n\nexport interface StorageAssetReference {\n storageId?: string;\n bucket: string;\n path: string;\n publicUrl?: string;\n}\n\nexport interface StorageUploadInput {\n storageId?: string;\n bucket: string;\n path: string;\n body: Uint8Array;\n contentType?: string;\n cacheControl?: string;\n upsert?: boolean;\n}\n\nexport interface StorageUploadResult {\n asset: StorageAssetReference;\n}\n\nexport interface StorageRemoveInput {\n storageId?: string;\n bucket: string;\n path: string;\n}\n\nexport interface StoragePublicUrlInput {\n storageId?: string;\n bucket: string;\n path: string;\n}\n\nexport interface StoragePublicUrlResult {\n publicUrl: string;\n}\n\nexport interface ImageMetadata {\n fileName?: string;\n sizeBytes?: number;\n createdAt?: string;\n}\n\nexport interface StorageImageAssetSource {\n kind: 'storage';\n storageId?: string;\n bucket: string;\n path: string;\n publicUrl?: string;\n alt?: string;\n width?: number;\n height?: number;\n contentType?: string;\n metadata?: ImageMetadata;\n}\n\nexport interface UrlImageAssetSource {\n kind: 'url';\n url: string;\n alt?: string;\n width?: number;\n height?: number;\n contentType?: string;\n metadata?: ImageMetadata;\n}\n\nexport type ImageAssetSource = StorageImageAssetSource | UrlImageAssetSource;\n\nexport interface StorageAdapter {\n upload(input: StorageUploadInput): Promise<StorageResult<StorageUploadResult>>;\n remove(input: StorageRemoveInput): Promise<StorageResult>;\n publicUrl(input: StoragePublicUrlInput): Promise<StorageResult<StoragePublicUrlResult>>;\n getImageMetadata?(input: StorageAssetReference): Promise<StorageResult<ImageMetadata>>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"","sourcesContent":["export interface StorageAdapterError {\n code: string;\n message: string;\n cause?: unknown;\n}\n\nexport type StorageOkResult<TData> = [TData] extends [void]\n ? { ok: true; data?: undefined }\n : { ok: true; data: TData };\n\nexport type StorageResult<TData = void> =\n | StorageOkResult<TData>\n | {\n ok: false;\n error: StorageAdapterError;\n };\n\nexport interface StorageAssetReference {\n storageId?: string;\n bucket: string;\n path: string;\n publicUrl?: string;\n}\n\nexport interface StorageUploadInput {\n storageId?: string;\n bucket: string;\n path: string;\n body: Uint8Array;\n contentType?: string;\n cacheControl?: string;\n upsert?: boolean;\n}\n\nexport interface StorageUploadResult {\n asset: StorageAssetReference;\n}\n\nexport interface StorageRemoveInput {\n storageId?: string;\n bucket: string;\n path: string;\n}\n\nexport interface StoragePublicUrlInput {\n storageId?: string;\n bucket: string;\n path: string;\n}\n\nexport interface StoragePublicUrlResult {\n publicUrl: string;\n}\n\nexport interface StorageObjectMetadata {\n storageId?: string;\n bucket: string;\n path: string;\n contentType?: string;\n sizeBytes?: number;\n createdAt?: string;\n updatedAt?: string;\n etag?: string;\n}\n\nexport interface StorageListInput {\n storageId?: string;\n bucket: string;\n prefix?: string;\n cursor?: string;\n limit?: number;\n}\n\nexport interface StorageListResult {\n objects: readonly StorageObjectMetadata[];\n nextCursor?: string;\n}\n\nexport type StorageResolvedAccess = 'public' | 'signed';\n\nexport interface StorageResolveInput {\n storageId?: string;\n bucket: string;\n path: string;\n access?: StorageResolvedAccess;\n expiresInSeconds?: number;\n}\n\nexport interface StorageResolvedAsset {\n storageId?: string;\n bucket: string;\n path: string;\n url: string;\n access: StorageResolvedAccess;\n expiresAt?: string;\n}\n\nexport interface StorageResolveResult {\n asset: StorageResolvedAsset;\n}\n\nexport interface ImageMetadata {\n fileName?: string;\n sizeBytes?: number;\n createdAt?: string;\n}\n\nexport interface StorageImageAssetSource {\n kind: 'storage';\n storageId?: string;\n bucket: string;\n path: string;\n publicUrl?: string;\n alt?: string;\n width?: number;\n height?: number;\n contentType?: string;\n metadata?: ImageMetadata;\n}\n\nexport interface UrlImageAssetSource {\n kind: 'url';\n url: string;\n alt?: string;\n width?: number;\n height?: number;\n contentType?: string;\n metadata?: ImageMetadata;\n}\n\nexport type ImageAssetSource = StorageImageAssetSource | UrlImageAssetSource;\n\nexport interface StorageAdapter {\n upload(input: StorageUploadInput): Promise<StorageResult<StorageUploadResult>>;\n remove(input: StorageRemoveInput): Promise<StorageResult>;\n publicUrl(input: StoragePublicUrlInput): Promise<StorageResult<StoragePublicUrlResult>>;\n getImageMetadata?(input: StorageAssetReference): Promise<StorageResult<ImageMetadata>>;\n}\n\nexport interface StorageListAdapter {\n list(input: StorageListInput): Promise<StorageResult<StorageListResult>>;\n}\n\nexport interface StorageResolveAdapter {\n resolve(input: StorageResolveInput): Promise<StorageResult<StorageResolveResult>>;\n}\n\n/**\n * Storage capability required by the app-authoring media service.\n *\n * Remote URL import/ingest is intentionally not part of this low-level object-storage\n * contract. It is a trusted service operation that can be implemented by reading the\n * remote object and delegating to `upload` when ingestion is requested.\n */\nexport interface MediaStorageAdapter\n extends StorageAdapter, StorageListAdapter, StorageResolveAdapter {}\n"]}
|
package/package.json
CHANGED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import type { MediaStorageAdapter } from './storage';
|
|
4
|
+
|
|
5
|
+
const adapter: MediaStorageAdapter = {
|
|
6
|
+
upload(input) {
|
|
7
|
+
return Promise.resolve({
|
|
8
|
+
ok: true,
|
|
9
|
+
data: {
|
|
10
|
+
asset: {
|
|
11
|
+
storageId: input.storageId,
|
|
12
|
+
bucket: input.bucket,
|
|
13
|
+
path: input.path,
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
remove() {
|
|
19
|
+
return Promise.resolve({ ok: true });
|
|
20
|
+
},
|
|
21
|
+
publicUrl(input) {
|
|
22
|
+
return Promise.resolve({
|
|
23
|
+
ok: true,
|
|
24
|
+
data: { publicUrl: `https://cdn.example.test/${input.bucket}/${input.path}` },
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
list(input) {
|
|
28
|
+
return Promise.resolve({
|
|
29
|
+
ok: true,
|
|
30
|
+
data: {
|
|
31
|
+
objects: [
|
|
32
|
+
{
|
|
33
|
+
storageId: input.storageId,
|
|
34
|
+
bucket: input.bucket,
|
|
35
|
+
path: `${input.prefix ?? ''}hero.png`,
|
|
36
|
+
contentType: 'image/png',
|
|
37
|
+
sizeBytes: 4096,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
resolve(input) {
|
|
44
|
+
return Promise.resolve({
|
|
45
|
+
ok: true,
|
|
46
|
+
data: {
|
|
47
|
+
asset: {
|
|
48
|
+
storageId: input.storageId,
|
|
49
|
+
bucket: input.bucket,
|
|
50
|
+
path: input.path,
|
|
51
|
+
url: `https://signed.example.test/${input.bucket}/${input.path}`,
|
|
52
|
+
access: input.access ?? 'signed',
|
|
53
|
+
expiresAt: '2026-08-12T10:00:00.000Z',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
describe('media storage capabilities', () => {
|
|
61
|
+
it('lists normalized provider-neutral object metadata', async () => {
|
|
62
|
+
const result = await adapter.list({
|
|
63
|
+
storageId: 'primary',
|
|
64
|
+
bucket: 'media',
|
|
65
|
+
prefix: 'authoring/',
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(result).toEqual({
|
|
69
|
+
ok: true,
|
|
70
|
+
data: {
|
|
71
|
+
objects: [
|
|
72
|
+
{
|
|
73
|
+
storageId: 'primary',
|
|
74
|
+
bucket: 'media',
|
|
75
|
+
path: 'authoring/hero.png',
|
|
76
|
+
contentType: 'image/png',
|
|
77
|
+
sizeBytes: 4096,
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('resolves a stable storage identity to a runtime-readable URL', async () => {
|
|
85
|
+
const result = await adapter.resolve({
|
|
86
|
+
storageId: 'primary',
|
|
87
|
+
bucket: 'media',
|
|
88
|
+
path: 'authoring/hero.png',
|
|
89
|
+
access: 'signed',
|
|
90
|
+
expiresInSeconds: 900,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
expect(result).toEqual({
|
|
94
|
+
ok: true,
|
|
95
|
+
data: {
|
|
96
|
+
asset: {
|
|
97
|
+
storageId: 'primary',
|
|
98
|
+
bucket: 'media',
|
|
99
|
+
path: 'authoring/hero.png',
|
|
100
|
+
url: 'https://signed.example.test/media/authoring/hero.png',
|
|
101
|
+
access: 'signed',
|
|
102
|
+
expiresAt: '2026-08-12T10:00:00.000Z',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
package/src/storage.ts
CHANGED
|
@@ -52,6 +52,53 @@ export interface StoragePublicUrlResult {
|
|
|
52
52
|
publicUrl: string;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
export interface StorageObjectMetadata {
|
|
56
|
+
storageId?: string;
|
|
57
|
+
bucket: string;
|
|
58
|
+
path: string;
|
|
59
|
+
contentType?: string;
|
|
60
|
+
sizeBytes?: number;
|
|
61
|
+
createdAt?: string;
|
|
62
|
+
updatedAt?: string;
|
|
63
|
+
etag?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface StorageListInput {
|
|
67
|
+
storageId?: string;
|
|
68
|
+
bucket: string;
|
|
69
|
+
prefix?: string;
|
|
70
|
+
cursor?: string;
|
|
71
|
+
limit?: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface StorageListResult {
|
|
75
|
+
objects: readonly StorageObjectMetadata[];
|
|
76
|
+
nextCursor?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type StorageResolvedAccess = 'public' | 'signed';
|
|
80
|
+
|
|
81
|
+
export interface StorageResolveInput {
|
|
82
|
+
storageId?: string;
|
|
83
|
+
bucket: string;
|
|
84
|
+
path: string;
|
|
85
|
+
access?: StorageResolvedAccess;
|
|
86
|
+
expiresInSeconds?: number;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface StorageResolvedAsset {
|
|
90
|
+
storageId?: string;
|
|
91
|
+
bucket: string;
|
|
92
|
+
path: string;
|
|
93
|
+
url: string;
|
|
94
|
+
access: StorageResolvedAccess;
|
|
95
|
+
expiresAt?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface StorageResolveResult {
|
|
99
|
+
asset: StorageResolvedAsset;
|
|
100
|
+
}
|
|
101
|
+
|
|
55
102
|
export interface ImageMetadata {
|
|
56
103
|
fileName?: string;
|
|
57
104
|
sizeBytes?: number;
|
|
@@ -89,3 +136,21 @@ export interface StorageAdapter {
|
|
|
89
136
|
publicUrl(input: StoragePublicUrlInput): Promise<StorageResult<StoragePublicUrlResult>>;
|
|
90
137
|
getImageMetadata?(input: StorageAssetReference): Promise<StorageResult<ImageMetadata>>;
|
|
91
138
|
}
|
|
139
|
+
|
|
140
|
+
export interface StorageListAdapter {
|
|
141
|
+
list(input: StorageListInput): Promise<StorageResult<StorageListResult>>;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface StorageResolveAdapter {
|
|
145
|
+
resolve(input: StorageResolveInput): Promise<StorageResult<StorageResolveResult>>;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Storage capability required by the app-authoring media service.
|
|
150
|
+
*
|
|
151
|
+
* Remote URL import/ingest is intentionally not part of this low-level object-storage
|
|
152
|
+
* contract. It is a trusted service operation that can be implemented by reading the
|
|
153
|
+
* remote object and delegating to `upload` when ingestion is requested.
|
|
154
|
+
*/
|
|
155
|
+
export interface MediaStorageAdapter
|
|
156
|
+
extends StorageAdapter, StorageListAdapter, StorageResolveAdapter {}
|