Skip to content

Commit 9a13069

Browse files
feat: Allow external images
1 parent e21d3a3 commit 9a13069

File tree

6 files changed

+47
-37
lines changed

6 files changed

+47
-37
lines changed

packages/snaps-sdk/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Only internals that are used by other Snaps packages should be exported here.
22
export type { EnumToUnion } from './internals';
3+
export type { UriOptions } from './internals';
34
export {
45
getErrorData,
56
getErrorMessage,
@@ -13,6 +14,7 @@ export {
1314
selectiveUnion,
1415
nonEmptyRecord,
1516
ISO8601DateStruct,
17+
uri,
1618
} from './internals';
1719

1820
// Re-exported from `@metamask/utils` for convenience.

packages/snaps-sdk/src/internals/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export * from './structs';
55
export * from './jsx';
66
export * from './svg';
77
export * from './time';
8+
export * from './uri';
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {
2+
refine,
3+
string,
4+
type,
5+
assert as assertSuperstruct,
6+
StructError,
7+
} from '@metamask/superstruct';
8+
import type { Struct } from '@metamask/superstruct';
9+
10+
import { getErrorMessage } from '@metamask/snaps-sdk';
11+
12+
export type UriOptions<Type extends string> = {
13+
protocol?: Struct<Type>;
14+
hash?: Struct<Type>;
15+
port?: Struct<Type>;
16+
hostname?: Struct<Type>;
17+
pathname?: Struct<Type>;
18+
search?: Struct<Type>;
19+
};
20+
21+
export const uri = (opts: UriOptions<any> = {}) =>
22+
refine(string(), 'uri', (value) => {
23+
try {
24+
const url = new URL(value);
25+
26+
const UrlStruct = type(opts);
27+
assertSuperstruct(url, UrlStruct);
28+
return true;
29+
} catch (error) {
30+
if (error instanceof StructError) {
31+
return getErrorMessage(error);
32+
}
33+
return `Expected URL, got "${value.toString()}"`;
34+
}
35+
});

packages/snaps-sdk/src/jsx/validation.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,7 @@ describe('ImageStruct', () => {
13051305
<Image src="<svg />" alt="alt" />,
13061306
<Image src="<svg />" />,
13071307
<Image src="<svg />" alt="alt" borderRadius="medium" />,
1308+
<Image src="https://example.com/foo.png" />,
13081309
])('validates an image element', (value) => {
13091310
expect(is(value, ImageStruct)).toBe(true);
13101311
});
@@ -1322,6 +1323,7 @@ describe('ImageStruct', () => {
13221323
<Image src="<svg />" alt={42} />,
13231324
// @ts-expect-error - Invalid props.
13241325
<Image src="<svg />" borderRadius="52px" />,
1326+
<Image src="http://example.com/foo.png" />,
13251327
<Text>foo</Text>,
13261328
<Box>
13271329
<Text>foo</Text>

packages/snaps-sdk/src/jsx/validation.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ import {
9191
svg,
9292
typedUnion,
9393
ISO8601DateStruct,
94+
uri,
9495
} from '../internals';
9596
import {
9697
NonEip155AssetTypeStruct,
@@ -238,7 +239,7 @@ export const BorderRadiusStruct = nullUnion([
238239
* A struct for the {@link ImageElement} type.
239240
*/
240241
export const ImageStruct: Describe<ImageElement> = element('Image', {
241-
src: svg(),
242+
src: nullUnion([svg(), uri({ protocol: literal('https:') })]),
242243
alt: optional(string()),
243244
borderRadius: optional(BorderRadiusStruct),
244245
});

packages/snaps-utils/src/types.ts

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
1-
import { getErrorMessage } from '@metamask/snaps-sdk';
2-
import {
3-
is,
4-
optional,
5-
refine,
6-
size,
7-
string,
8-
type,
9-
assert as assertSuperstruct,
10-
StructError,
11-
} from '@metamask/superstruct';
12-
import type { Infer, Struct } from '@metamask/superstruct';
1+
import type { UriOptions } from '@metamask/snaps-sdk';
2+
import { uri } from '@metamask/snaps-sdk';
3+
import { is, optional, size, string, type } from '@metamask/superstruct';
4+
import type { Infer } from '@metamask/superstruct';
135
import type { Json } from '@metamask/utils';
146
import { definePattern, VersionStruct } from '@metamask/utils';
157

@@ -109,30 +101,7 @@ type ObjectParameters<
109101

110102
export type SnapExportsParameters = ObjectParameters<SnapFunctionExports>;
111103

112-
type UriOptions<Type extends string> = {
113-
protocol?: Struct<Type>;
114-
hash?: Struct<Type>;
115-
port?: Struct<Type>;
116-
hostname?: Struct<Type>;
117-
pathname?: Struct<Type>;
118-
search?: Struct<Type>;
119-
};
120-
121-
export const uri = (opts: UriOptions<any> = {}) =>
122-
refine(string(), 'uri', (value) => {
123-
try {
124-
const url = new URL(value);
125-
126-
const UrlStruct = type(opts);
127-
assertSuperstruct(url, UrlStruct);
128-
return true;
129-
} catch (error) {
130-
if (error instanceof StructError) {
131-
return getErrorMessage(error);
132-
}
133-
return `Expected URL, got "${value.toString()}"`;
134-
}
135-
});
104+
export { uri } from '@metamask/snaps-sdk';
136105

137106
/**
138107
* Returns whether a given value is a valid URL.

0 commit comments

Comments
 (0)