@joycostudio/iris 0.0.0-stage → 0.0.1

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.
@@ -0,0 +1,147 @@
1
+ /** Metadata shared by asset providers. No framework or encoder dependencies. */
2
+ type IrisVariant = {
3
+ url: string;
4
+ width: number;
5
+ height: number;
6
+ bytes: number;
7
+ format?: string;
8
+ progressive?: boolean;
9
+ alpha?: boolean;
10
+ animated?: boolean;
11
+ };
12
+ type IrisPlaceholderOptions = {
13
+ blur?: number;
14
+ width?: number;
15
+ quality?: number;
16
+ };
17
+ type IrisPlaceholderVariant = {
18
+ width: number;
19
+ quality: number;
20
+ url: string;
21
+ };
22
+ type IrisCatalogAsset = Omit<IrisVariant, "url"> & {
23
+ id?: string;
24
+ src: string;
25
+ variants?: readonly IrisVariant[];
26
+ placeholder?: string;
27
+ placeholders?: readonly IrisPlaceholderVariant[];
28
+ };
29
+ type IrisAssetInput = string | {
30
+ src: string;
31
+ id?: string;
32
+ variants?: readonly (string | IrisVariant)[];
33
+ placeholder?: string;
34
+ placeholders?: readonly IrisPlaceholderVariant[];
35
+ };
36
+ type IrisPolicyUsage<Custom = Record<string, unknown>> = {
37
+ /** CSS/logical pixels; omit when the layout is not known yet. */
38
+ width?: number;
39
+ dpr?: number;
40
+ priority?: boolean;
41
+ tags?: readonly string[];
42
+ custom?: Custom;
43
+ };
44
+ type IrisPolicyContext<Custom = Record<string, unknown>> = {
45
+ src: string;
46
+ asset: Readonly<IrisCatalogAsset>;
47
+ variants: readonly IrisVariant[];
48
+ usage: Readonly<IrisPolicyUsage<Custom>>;
49
+ };
50
+ type IrisMatcher<Custom = Record<string, unknown>> = string | RegExp | ((context: IrisPolicyContext<Custom>) => boolean);
51
+ type IrisRange = {
52
+ min?: number;
53
+ max?: number;
54
+ };
55
+ type IrisConditions = {
56
+ sourceBytes?: IrisRange;
57
+ sourceWidth?: IrisRange;
58
+ renderedWidth?: IrisRange;
59
+ targetWidth?: IrisRange;
60
+ alpha?: boolean;
61
+ priority?: boolean;
62
+ format?: string;
63
+ };
64
+ type IrisRecipe = {
65
+ placeholder?: "none" | "blur" | IrisPlaceholderOptions;
66
+ preview?: "none" | {
67
+ /** Fraction of the final width selected by the browser, strictly between 0 and 1. */
68
+ ratio?: number;
69
+ /** Upper bound, also applied when ratio is supplied. */
70
+ maxWidth?: number;
71
+ /** Next image quality for a distinct, smaller preview file. */
72
+ quality?: number;
73
+ url?: string;
74
+ /** Load the final image after the preview has appeared. */
75
+ loadFirst?: boolean;
76
+ /** Minimum time to show the preview before starting the final request. */
77
+ minDisplayMs?: number;
78
+ };
79
+ };
80
+ type IrisPolicyRecipe<Custom = Record<string, unknown>> = IrisRecipe | ((context: IrisPolicyContext<Custom>) => IrisRecipe);
81
+ type IrisRule<Custom = Record<string, unknown>> = {
82
+ include?: IrisMatcher<Custom> | readonly IrisMatcher<Custom>[];
83
+ exclude?: IrisMatcher<Custom> | readonly IrisMatcher<Custom>[];
84
+ when?: IrisConditions | ((context: IrisPolicyContext<Custom>) => boolean);
85
+ recipe: string;
86
+ };
87
+ type IrisPolicyOptions<Custom = Record<string, unknown>> = {
88
+ assets?: readonly (IrisAssetInput | IrisCatalogAsset)[];
89
+ recipes: Readonly<Record<string, IrisPolicyRecipe<Custom>>>;
90
+ rules?: readonly IrisRule<Custom>[];
91
+ fallback: string;
92
+ };
93
+ type IrisPolicyDiagnostic = {
94
+ code: "missing_preview" | "missing_placeholder" | "missing_variant" | "undersized_final" | "unknown_target";
95
+ message: string;
96
+ };
97
+ type IrisResolvedPlan = {
98
+ src: string;
99
+ recipe: string;
100
+ /** null means explicit recipe or fallback; otherwise the matching rule index. */
101
+ ruleIndex: number | null;
102
+ targetWidth: number | null;
103
+ placeholder: {
104
+ url: string;
105
+ blur: number;
106
+ } | null;
107
+ preview: IrisVariant | null;
108
+ final: IrisVariant;
109
+ diagnostics: IrisPolicyDiagnostic[];
110
+ };
111
+ type IrisResult<T> = {
112
+ ok: true;
113
+ data: T;
114
+ } | {
115
+ ok: false;
116
+ error: {
117
+ code: string;
118
+ message: string;
119
+ };
120
+ };
121
+ type IrisResolveOptions<Custom = Record<string, unknown>> = {
122
+ asset: string | IrisCatalogAsset;
123
+ catalog?: readonly IrisCatalogAsset[];
124
+ usage?: IrisPolicyUsage<Custom>;
125
+ recipe?: string;
126
+ };
127
+ type IrisRecipeSelection = {
128
+ name: string;
129
+ ruleIndex: number | null;
130
+ recipe: IrisRecipe;
131
+ };
132
+ type IrisSelectOptions<Custom = Record<string, unknown>> = {
133
+ asset: IrisCatalogAsset;
134
+ usage?: IrisPolicyUsage<Custom>;
135
+ recipe?: string;
136
+ };
137
+ type IrisPolicy<Custom = Record<string, unknown>> = {
138
+ assets: readonly (IrisAssetInput | IrisCatalogAsset)[];
139
+ placeholderRequests: readonly {
140
+ width: number;
141
+ quality: number;
142
+ }[];
143
+ select: (options: IrisSelectOptions<Custom>) => IrisResult<IrisRecipeSelection>;
144
+ resolve: (options: IrisResolveOptions<Custom>) => IrisResult<IrisResolvedPlan>;
145
+ };
146
+
147
+ export type { IrisPolicyOptions as I, IrisPolicy as a, IrisAssetInput as b, IrisCatalogAsset as c, IrisConditions as d, IrisMatcher as e, IrisPlaceholderOptions as f, IrisPlaceholderVariant as g, IrisPolicyContext as h, IrisPolicyDiagnostic as i, IrisPolicyRecipe as j, IrisPolicyUsage as k, IrisRange as l, IrisRecipe as m, IrisRecipeSelection as n, IrisResolveOptions as o, IrisResolvedPlan as p, IrisResult as q, IrisRule as r, IrisSelectOptions as s, IrisVariant as t };
@@ -0,0 +1,147 @@
1
+ /** Metadata shared by asset providers. No framework or encoder dependencies. */
2
+ type IrisVariant = {
3
+ url: string;
4
+ width: number;
5
+ height: number;
6
+ bytes: number;
7
+ format?: string;
8
+ progressive?: boolean;
9
+ alpha?: boolean;
10
+ animated?: boolean;
11
+ };
12
+ type IrisPlaceholderOptions = {
13
+ blur?: number;
14
+ width?: number;
15
+ quality?: number;
16
+ };
17
+ type IrisPlaceholderVariant = {
18
+ width: number;
19
+ quality: number;
20
+ url: string;
21
+ };
22
+ type IrisCatalogAsset = Omit<IrisVariant, "url"> & {
23
+ id?: string;
24
+ src: string;
25
+ variants?: readonly IrisVariant[];
26
+ placeholder?: string;
27
+ placeholders?: readonly IrisPlaceholderVariant[];
28
+ };
29
+ type IrisAssetInput = string | {
30
+ src: string;
31
+ id?: string;
32
+ variants?: readonly (string | IrisVariant)[];
33
+ placeholder?: string;
34
+ placeholders?: readonly IrisPlaceholderVariant[];
35
+ };
36
+ type IrisPolicyUsage<Custom = Record<string, unknown>> = {
37
+ /** CSS/logical pixels; omit when the layout is not known yet. */
38
+ width?: number;
39
+ dpr?: number;
40
+ priority?: boolean;
41
+ tags?: readonly string[];
42
+ custom?: Custom;
43
+ };
44
+ type IrisPolicyContext<Custom = Record<string, unknown>> = {
45
+ src: string;
46
+ asset: Readonly<IrisCatalogAsset>;
47
+ variants: readonly IrisVariant[];
48
+ usage: Readonly<IrisPolicyUsage<Custom>>;
49
+ };
50
+ type IrisMatcher<Custom = Record<string, unknown>> = string | RegExp | ((context: IrisPolicyContext<Custom>) => boolean);
51
+ type IrisRange = {
52
+ min?: number;
53
+ max?: number;
54
+ };
55
+ type IrisConditions = {
56
+ sourceBytes?: IrisRange;
57
+ sourceWidth?: IrisRange;
58
+ renderedWidth?: IrisRange;
59
+ targetWidth?: IrisRange;
60
+ alpha?: boolean;
61
+ priority?: boolean;
62
+ format?: string;
63
+ };
64
+ type IrisRecipe = {
65
+ placeholder?: "none" | "blur" | IrisPlaceholderOptions;
66
+ preview?: "none" | {
67
+ /** Fraction of the final width selected by the browser, strictly between 0 and 1. */
68
+ ratio?: number;
69
+ /** Upper bound, also applied when ratio is supplied. */
70
+ maxWidth?: number;
71
+ /** Next image quality for a distinct, smaller preview file. */
72
+ quality?: number;
73
+ url?: string;
74
+ /** Load the final image after the preview has appeared. */
75
+ loadFirst?: boolean;
76
+ /** Minimum time to show the preview before starting the final request. */
77
+ minDisplayMs?: number;
78
+ };
79
+ };
80
+ type IrisPolicyRecipe<Custom = Record<string, unknown>> = IrisRecipe | ((context: IrisPolicyContext<Custom>) => IrisRecipe);
81
+ type IrisRule<Custom = Record<string, unknown>> = {
82
+ include?: IrisMatcher<Custom> | readonly IrisMatcher<Custom>[];
83
+ exclude?: IrisMatcher<Custom> | readonly IrisMatcher<Custom>[];
84
+ when?: IrisConditions | ((context: IrisPolicyContext<Custom>) => boolean);
85
+ recipe: string;
86
+ };
87
+ type IrisPolicyOptions<Custom = Record<string, unknown>> = {
88
+ assets?: readonly (IrisAssetInput | IrisCatalogAsset)[];
89
+ recipes: Readonly<Record<string, IrisPolicyRecipe<Custom>>>;
90
+ rules?: readonly IrisRule<Custom>[];
91
+ fallback: string;
92
+ };
93
+ type IrisPolicyDiagnostic = {
94
+ code: "missing_preview" | "missing_placeholder" | "missing_variant" | "undersized_final" | "unknown_target";
95
+ message: string;
96
+ };
97
+ type IrisResolvedPlan = {
98
+ src: string;
99
+ recipe: string;
100
+ /** null means explicit recipe or fallback; otherwise the matching rule index. */
101
+ ruleIndex: number | null;
102
+ targetWidth: number | null;
103
+ placeholder: {
104
+ url: string;
105
+ blur: number;
106
+ } | null;
107
+ preview: IrisVariant | null;
108
+ final: IrisVariant;
109
+ diagnostics: IrisPolicyDiagnostic[];
110
+ };
111
+ type IrisResult<T> = {
112
+ ok: true;
113
+ data: T;
114
+ } | {
115
+ ok: false;
116
+ error: {
117
+ code: string;
118
+ message: string;
119
+ };
120
+ };
121
+ type IrisResolveOptions<Custom = Record<string, unknown>> = {
122
+ asset: string | IrisCatalogAsset;
123
+ catalog?: readonly IrisCatalogAsset[];
124
+ usage?: IrisPolicyUsage<Custom>;
125
+ recipe?: string;
126
+ };
127
+ type IrisRecipeSelection = {
128
+ name: string;
129
+ ruleIndex: number | null;
130
+ recipe: IrisRecipe;
131
+ };
132
+ type IrisSelectOptions<Custom = Record<string, unknown>> = {
133
+ asset: IrisCatalogAsset;
134
+ usage?: IrisPolicyUsage<Custom>;
135
+ recipe?: string;
136
+ };
137
+ type IrisPolicy<Custom = Record<string, unknown>> = {
138
+ assets: readonly (IrisAssetInput | IrisCatalogAsset)[];
139
+ placeholderRequests: readonly {
140
+ width: number;
141
+ quality: number;
142
+ }[];
143
+ select: (options: IrisSelectOptions<Custom>) => IrisResult<IrisRecipeSelection>;
144
+ resolve: (options: IrisResolveOptions<Custom>) => IrisResult<IrisResolvedPlan>;
145
+ };
146
+
147
+ export type { IrisPolicyOptions as I, IrisPolicy as a, IrisAssetInput as b, IrisCatalogAsset as c, IrisConditions as d, IrisMatcher as e, IrisPlaceholderOptions as f, IrisPlaceholderVariant as g, IrisPolicyContext as h, IrisPolicyDiagnostic as i, IrisPolicyRecipe as j, IrisPolicyUsage as k, IrisRange as l, IrisRecipe as m, IrisRecipeSelection as n, IrisResolveOptions as o, IrisResolvedPlan as p, IrisResult as q, IrisRule as r, IrisSelectOptions as s, IrisVariant as t };