@reventlessdev/reventless-spec 3.0.0-alpha.117 → 3.0.0-alpha.119

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.
Files changed (68) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/package.json +3 -3
  3. package/src/components/CapabilityManifest.res +1 -1
  4. package/src/components/CapabilityManifest.res.mjs +13 -12
  5. package/src/components/DcbDecode.res +8 -8
  6. package/src/components/DcbDecode.res.mjs +9 -8
  7. package/src/components/DcbTag.res +43 -42
  8. package/src/components/DcbTag.res.mjs +90 -87
  9. package/src/components/DcbValidation.res +6 -6
  10. package/src/components/DcbValidation.res.mjs +6 -6
  11. package/src/components/DisplayName.res.mjs +3 -3
  12. package/src/components/Owner.res +1 -1
  13. package/src/components/Owner.res.mjs +7 -7
  14. package/src/components/Plugin.res +8 -11
  15. package/src/components/Plugin.res.mjs +133 -134
  16. package/src/components/Reference.res.mjs +5 -5
  17. package/src/components/StateAnnotations.res +23 -0
  18. package/src/components/StateAnnotations.res.mjs +3 -3
  19. package/src/components/TaggedUnion.res +238 -0
  20. package/src/components/TaggedUnion.res.mjs +193 -0
  21. package/src/generator/PlatformCodegen.res +17 -14
  22. package/src/generator/PlatformCodegen.res.mjs +1 -1
  23. package/src/generator/PlatformGenerator.res +1 -1
  24. package/src/semantic/Bytes.res.mjs +2 -2
  25. package/src/semantic/Color.res.mjs +2 -2
  26. package/src/semantic/Currency.res.mjs +167 -167
  27. package/src/semantic/DateRange.res.mjs +2 -2
  28. package/src/semantic/Duration.res.mjs +2 -2
  29. package/src/semantic/Email.res +2 -2
  30. package/src/semantic/Email.res.mjs +3 -2
  31. package/src/semantic/FileRef.res +28 -0
  32. package/src/semantic/FileRef.res.mjs +17 -0
  33. package/src/semantic/GeoPoint.res +14 -10
  34. package/src/semantic/GeoPoint.res.mjs +10 -17
  35. package/src/semantic/ImageRef.res +51 -0
  36. package/src/semantic/ImageRef.res.mjs +17 -0
  37. package/src/semantic/Media_Ref.res +33 -0
  38. package/src/semantic/Media_Ref.res.mjs +37 -0
  39. package/src/semantic/Money.res +7 -5
  40. package/src/semantic/Money.res.mjs +6 -9
  41. package/src/semantic/Offload.res +29 -43
  42. package/src/semantic/Offload.res.mjs +18 -49
  43. package/src/semantic/Percent.res.mjs +2 -2
  44. package/src/semantic/Phone.res.mjs +2 -2
  45. package/src/semantic/Semantic.res +24 -6
  46. package/src/semantic/Semantic.res.mjs +13 -12
  47. package/src/semantic/StorageRef.res +33 -19
  48. package/src/semantic/StorageRef.res.mjs +14 -14
  49. package/src/semantic/UploadableFile.res +30 -0
  50. package/src/semantic/UploadableFile.res.mjs +23 -0
  51. package/src/semantic/UploadableImage.res +56 -0
  52. package/src/semantic/UploadableImage.res.mjs +23 -0
  53. package/src/semantic/Url.res +8 -2
  54. package/src/semantic/Url.res.mjs +3 -2
  55. package/src/types/Authorization.res.mjs +7 -7
  56. package/src/types/DateTime.res.mjs +2 -2
  57. package/src/types/Id.res.mjs +6 -4
  58. package/src/types/Identity.res +0 -1
  59. package/src/types/Identity.res.mjs +12 -14
  60. package/src/types/Message.res +29 -10
  61. package/src/types/Message.res.mjs +56 -37
  62. package/src/types/ReadConsistency.res.mjs +5 -5
  63. package/src/types/Schedule.res.mjs +37 -37
  64. package/src/types/StoredEvent.res +2 -2
  65. package/src/types/StoredEvent.res.mjs +11 -10
  66. package/src/types/Visibility.res.mjs +4 -4
  67. package/src/util/Util_Sury.res +32 -0
  68. package/src/util/Util_Sury.res.mjs +39 -0
@@ -1,173 +1,173 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as S from "sury/src/S.res.mjs";
3
+ import * as Sury from "sury";
4
4
 
5
- let schema = S.union([
6
- S.literal("AED"),
7
- S.literal("AFN"),
8
- S.literal("ALL"),
9
- S.literal("AMD"),
10
- S.literal("AOA"),
11
- S.literal("ARS"),
12
- S.literal("AUD"),
13
- S.literal("AWG"),
14
- S.literal("AZN"),
15
- S.literal("BAM"),
16
- S.literal("BBD"),
17
- S.literal("BDT"),
18
- S.literal("BHD"),
19
- S.literal("BIF"),
20
- S.literal("BMD"),
21
- S.literal("BND"),
22
- S.literal("BOB"),
23
- S.literal("BOV"),
24
- S.literal("BRL"),
25
- S.literal("BSD"),
26
- S.literal("BTN"),
27
- S.literal("BWP"),
28
- S.literal("BYN"),
29
- S.literal("BZD"),
30
- S.literal("CAD"),
31
- S.literal("CDF"),
32
- S.literal("CHE"),
33
- S.literal("CHF"),
34
- S.literal("CHW"),
35
- S.literal("CLF"),
36
- S.literal("CLP"),
37
- S.literal("CNY"),
38
- S.literal("COP"),
39
- S.literal("COU"),
40
- S.literal("CRC"),
41
- S.literal("CUP"),
42
- S.literal("CVE"),
43
- S.literal("CZK"),
44
- S.literal("DJF"),
45
- S.literal("DKK"),
46
- S.literal("DOP"),
47
- S.literal("DZD"),
48
- S.literal("EGP"),
49
- S.literal("ERN"),
50
- S.literal("ETB"),
51
- S.literal("EUR"),
52
- S.literal("FJD"),
53
- S.literal("FKP"),
54
- S.literal("GBP"),
55
- S.literal("GEL"),
56
- S.literal("GHS"),
57
- S.literal("GIP"),
58
- S.literal("GMD"),
59
- S.literal("GNF"),
60
- S.literal("GTQ"),
61
- S.literal("GYD"),
62
- S.literal("HKD"),
63
- S.literal("HNL"),
64
- S.literal("HTG"),
65
- S.literal("HUF"),
66
- S.literal("IDR"),
67
- S.literal("ILS"),
68
- S.literal("INR"),
69
- S.literal("IQD"),
70
- S.literal("IRR"),
71
- S.literal("ISK"),
72
- S.literal("JMD"),
73
- S.literal("JOD"),
74
- S.literal("JPY"),
75
- S.literal("KES"),
76
- S.literal("KGS"),
77
- S.literal("KHR"),
78
- S.literal("KMF"),
79
- S.literal("KPW"),
80
- S.literal("KRW"),
81
- S.literal("KWD"),
82
- S.literal("KYD"),
83
- S.literal("KZT"),
84
- S.literal("LAK"),
85
- S.literal("LBP"),
86
- S.literal("LKR"),
87
- S.literal("LRD"),
88
- S.literal("LSL"),
89
- S.literal("LYD"),
90
- S.literal("MAD"),
91
- S.literal("MDL"),
92
- S.literal("MGA"),
93
- S.literal("MKD"),
94
- S.literal("MMK"),
95
- S.literal("MNT"),
96
- S.literal("MOP"),
97
- S.literal("MRU"),
98
- S.literal("MUR"),
99
- S.literal("MVR"),
100
- S.literal("MWK"),
101
- S.literal("MXN"),
102
- S.literal("MXV"),
103
- S.literal("MYR"),
104
- S.literal("MZN"),
105
- S.literal("NAD"),
106
- S.literal("NGN"),
107
- S.literal("NIO"),
108
- S.literal("NOK"),
109
- S.literal("NPR"),
110
- S.literal("NZD"),
111
- S.literal("OMR"),
112
- S.literal("PAB"),
113
- S.literal("PEN"),
114
- S.literal("PGK"),
115
- S.literal("PHP"),
116
- S.literal("PKR"),
117
- S.literal("PLN"),
118
- S.literal("PYG"),
119
- S.literal("QAR"),
120
- S.literal("RON"),
121
- S.literal("RSD"),
122
- S.literal("RUB"),
123
- S.literal("RWF"),
124
- S.literal("SAR"),
125
- S.literal("SBD"),
126
- S.literal("SCR"),
127
- S.literal("SDG"),
128
- S.literal("SEK"),
129
- S.literal("SGD"),
130
- S.literal("SHP"),
131
- S.literal("SLE"),
132
- S.literal("SOS"),
133
- S.literal("SRD"),
134
- S.literal("SSP"),
135
- S.literal("STN"),
136
- S.literal("SVC"),
137
- S.literal("SYP"),
138
- S.literal("SZL"),
139
- S.literal("THB"),
140
- S.literal("TJS"),
141
- S.literal("TMT"),
142
- S.literal("TND"),
143
- S.literal("TOP"),
144
- S.literal("TRY"),
145
- S.literal("TTD"),
146
- S.literal("TWD"),
147
- S.literal("TZS"),
148
- S.literal("UAH"),
149
- S.literal("UGX"),
150
- S.literal("USD"),
151
- S.literal("USN"),
152
- S.literal("UYI"),
153
- S.literal("UYU"),
154
- S.literal("UYW"),
155
- S.literal("UZS"),
156
- S.literal("VED"),
157
- S.literal("VES"),
158
- S.literal("VND"),
159
- S.literal("VUV"),
160
- S.literal("WST"),
161
- S.literal("XAD"),
162
- S.literal("XAF"),
163
- S.literal("XCD"),
164
- S.literal("XCG"),
165
- S.literal("XOF"),
166
- S.literal("XPF"),
167
- S.literal("YER"),
168
- S.literal("ZAR"),
169
- S.literal("ZMW"),
170
- S.literal("ZWG")
5
+ let schema = Sury.union([
6
+ Sury.literal("AED"),
7
+ Sury.literal("AFN"),
8
+ Sury.literal("ALL"),
9
+ Sury.literal("AMD"),
10
+ Sury.literal("AOA"),
11
+ Sury.literal("ARS"),
12
+ Sury.literal("AUD"),
13
+ Sury.literal("AWG"),
14
+ Sury.literal("AZN"),
15
+ Sury.literal("BAM"),
16
+ Sury.literal("BBD"),
17
+ Sury.literal("BDT"),
18
+ Sury.literal("BHD"),
19
+ Sury.literal("BIF"),
20
+ Sury.literal("BMD"),
21
+ Sury.literal("BND"),
22
+ Sury.literal("BOB"),
23
+ Sury.literal("BOV"),
24
+ Sury.literal("BRL"),
25
+ Sury.literal("BSD"),
26
+ Sury.literal("BTN"),
27
+ Sury.literal("BWP"),
28
+ Sury.literal("BYN"),
29
+ Sury.literal("BZD"),
30
+ Sury.literal("CAD"),
31
+ Sury.literal("CDF"),
32
+ Sury.literal("CHE"),
33
+ Sury.literal("CHF"),
34
+ Sury.literal("CHW"),
35
+ Sury.literal("CLF"),
36
+ Sury.literal("CLP"),
37
+ Sury.literal("CNY"),
38
+ Sury.literal("COP"),
39
+ Sury.literal("COU"),
40
+ Sury.literal("CRC"),
41
+ Sury.literal("CUP"),
42
+ Sury.literal("CVE"),
43
+ Sury.literal("CZK"),
44
+ Sury.literal("DJF"),
45
+ Sury.literal("DKK"),
46
+ Sury.literal("DOP"),
47
+ Sury.literal("DZD"),
48
+ Sury.literal("EGP"),
49
+ Sury.literal("ERN"),
50
+ Sury.literal("ETB"),
51
+ Sury.literal("EUR"),
52
+ Sury.literal("FJD"),
53
+ Sury.literal("FKP"),
54
+ Sury.literal("GBP"),
55
+ Sury.literal("GEL"),
56
+ Sury.literal("GHS"),
57
+ Sury.literal("GIP"),
58
+ Sury.literal("GMD"),
59
+ Sury.literal("GNF"),
60
+ Sury.literal("GTQ"),
61
+ Sury.literal("GYD"),
62
+ Sury.literal("HKD"),
63
+ Sury.literal("HNL"),
64
+ Sury.literal("HTG"),
65
+ Sury.literal("HUF"),
66
+ Sury.literal("IDR"),
67
+ Sury.literal("ILS"),
68
+ Sury.literal("INR"),
69
+ Sury.literal("IQD"),
70
+ Sury.literal("IRR"),
71
+ Sury.literal("ISK"),
72
+ Sury.literal("JMD"),
73
+ Sury.literal("JOD"),
74
+ Sury.literal("JPY"),
75
+ Sury.literal("KES"),
76
+ Sury.literal("KGS"),
77
+ Sury.literal("KHR"),
78
+ Sury.literal("KMF"),
79
+ Sury.literal("KPW"),
80
+ Sury.literal("KRW"),
81
+ Sury.literal("KWD"),
82
+ Sury.literal("KYD"),
83
+ Sury.literal("KZT"),
84
+ Sury.literal("LAK"),
85
+ Sury.literal("LBP"),
86
+ Sury.literal("LKR"),
87
+ Sury.literal("LRD"),
88
+ Sury.literal("LSL"),
89
+ Sury.literal("LYD"),
90
+ Sury.literal("MAD"),
91
+ Sury.literal("MDL"),
92
+ Sury.literal("MGA"),
93
+ Sury.literal("MKD"),
94
+ Sury.literal("MMK"),
95
+ Sury.literal("MNT"),
96
+ Sury.literal("MOP"),
97
+ Sury.literal("MRU"),
98
+ Sury.literal("MUR"),
99
+ Sury.literal("MVR"),
100
+ Sury.literal("MWK"),
101
+ Sury.literal("MXN"),
102
+ Sury.literal("MXV"),
103
+ Sury.literal("MYR"),
104
+ Sury.literal("MZN"),
105
+ Sury.literal("NAD"),
106
+ Sury.literal("NGN"),
107
+ Sury.literal("NIO"),
108
+ Sury.literal("NOK"),
109
+ Sury.literal("NPR"),
110
+ Sury.literal("NZD"),
111
+ Sury.literal("OMR"),
112
+ Sury.literal("PAB"),
113
+ Sury.literal("PEN"),
114
+ Sury.literal("PGK"),
115
+ Sury.literal("PHP"),
116
+ Sury.literal("PKR"),
117
+ Sury.literal("PLN"),
118
+ Sury.literal("PYG"),
119
+ Sury.literal("QAR"),
120
+ Sury.literal("RON"),
121
+ Sury.literal("RSD"),
122
+ Sury.literal("RUB"),
123
+ Sury.literal("RWF"),
124
+ Sury.literal("SAR"),
125
+ Sury.literal("SBD"),
126
+ Sury.literal("SCR"),
127
+ Sury.literal("SDG"),
128
+ Sury.literal("SEK"),
129
+ Sury.literal("SGD"),
130
+ Sury.literal("SHP"),
131
+ Sury.literal("SLE"),
132
+ Sury.literal("SOS"),
133
+ Sury.literal("SRD"),
134
+ Sury.literal("SSP"),
135
+ Sury.literal("STN"),
136
+ Sury.literal("SVC"),
137
+ Sury.literal("SYP"),
138
+ Sury.literal("SZL"),
139
+ Sury.literal("THB"),
140
+ Sury.literal("TJS"),
141
+ Sury.literal("TMT"),
142
+ Sury.literal("TND"),
143
+ Sury.literal("TOP"),
144
+ Sury.literal("TRY"),
145
+ Sury.literal("TTD"),
146
+ Sury.literal("TWD"),
147
+ Sury.literal("TZS"),
148
+ Sury.literal("UAH"),
149
+ Sury.literal("UGX"),
150
+ Sury.literal("USD"),
151
+ Sury.literal("USN"),
152
+ Sury.literal("UYI"),
153
+ Sury.literal("UYU"),
154
+ Sury.literal("UYW"),
155
+ Sury.literal("UZS"),
156
+ Sury.literal("VED"),
157
+ Sury.literal("VES"),
158
+ Sury.literal("VND"),
159
+ Sury.literal("VUV"),
160
+ Sury.literal("WST"),
161
+ Sury.literal("XAD"),
162
+ Sury.literal("XAF"),
163
+ Sury.literal("XCD"),
164
+ Sury.literal("XCG"),
165
+ Sury.literal("XOF"),
166
+ Sury.literal("XPF"),
167
+ Sury.literal("YER"),
168
+ Sury.literal("ZAR"),
169
+ Sury.literal("ZMW"),
170
+ Sury.literal("ZWG")
171
171
  ]);
172
172
 
173
173
  let all = [
@@ -1,10 +1,10 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as S from "sury/src/S.res.mjs";
3
+ import * as Sury from "sury";
4
4
  import * as DateTime$Reventless from "../types/DateTime.res.mjs";
5
5
  import * as Semantic$Reventless from "./Semantic.res.mjs";
6
6
 
7
- let schema = S.schema(s => ({
7
+ let schema = Sury.$schema(s => ({
8
8
  start: s.m(DateTime$Reventless.string),
9
9
  end: s.m(DateTime$Reventless.string)
10
10
  }));
@@ -1,6 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
- import * as S from "sury/src/S.res.mjs";
3
+ import * as Sury from "sury";
4
4
  import * as Semantic$Reventless from "./Semantic.res.mjs";
5
5
 
6
6
  function fromInt(raw) {
@@ -17,7 +17,7 @@ function fromInt(raw) {
17
17
  }
18
18
  }
19
19
 
20
- let schema = Semantic$Reventless.refined(S.int, Semantic$Reventless.Id.duration, fromInt);
20
+ let schema = Semantic$Reventless.refined(Sury.int, Semantic$Reventless.Id.duration, fromInt);
21
21
 
22
22
  export {
23
23
  fromInt,
@@ -38,11 +38,11 @@ external toString: t => string = "%identity"
38
38
 
39
39
  // Sury's check, held once. `fromString` runs it rather than restating it, and
40
40
  // `schema` is built from `fromString`, so there is exactly one grammar here.
41
- let grammar: S.t<string> = S.string->S.email
41
+ let grammar: S.t<string> = S.email
42
42
 
43
43
  /** Validate a raw string as an email address, saying why when it is not one. */
44
44
  let fromString = (raw: string): result<t, string> =>
45
- switch raw->S.parseOrThrow(grammar) {
45
+ switch raw->S.parseOrThrow(~to=grammar) {
46
46
  | value => Ok(value)
47
47
  | exception _ => Error(`expected an email address, got ${Semantic.showString(raw)}`)
48
48
  }
@@ -1,9 +1,10 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as S from "sury/src/S.res.mjs";
4
+ import * as Sury from "sury";
4
5
  import * as Semantic$Reventless from "./Semantic.res.mjs";
5
6
 
6
- let grammar = S.email(S.string, undefined);
7
+ let grammar = Sury.email;
7
8
 
8
9
  function fromString(raw) {
9
10
  let value;
@@ -21,7 +22,7 @@ function fromString(raw) {
21
22
  };
22
23
  }
23
24
 
24
- let schema = Semantic$Reventless.refined(S.string, Semantic$Reventless.Id.email, fromString);
25
+ let schema = Semantic$Reventless.refined(Sury.string, Semantic$Reventless.Id.email, fromString);
25
26
 
26
27
  export {
27
28
  grammar,
@@ -0,0 +1,28 @@
1
+ /**
2
+ A reference to a file the platform does **not** own.
3
+
4
+ The non-image arm of the unowned pair, and {!UploadableFile}'s counterpart: same
5
+ content fact, no store declared, nothing provisioned. See {!ImageRef} for why
6
+ the pair exists and what the grammar refuses.
7
+
8
+ @example
9
+ ```rescript
10
+ @schema type event =
11
+ | SupplierCatalogPublished({
12
+ supplierId: @s.matches(DcbTag.string) string,
13
+ priceList: @s.matches(Reventless.FileRef.schema) string,
14
+ })
15
+ ```
16
+ */
17
+
18
+ /** Transparent `string`; see `Email.t`. */
19
+ type t = string
20
+
21
+ external unsafe: string => t = "%identity"
22
+ external toString: t => string = "%identity"
23
+
24
+ let fromString = (raw: string): result<t, string> => Media_Ref.check(~what="file", raw)
25
+
26
+ /** The sury schema for a file-reference field.
27
+ Use with `@s.matches(Reventless.FileRef.schema)`. */
28
+ let schema: S.t<t> = S.string->Semantic.refined(~id=Semantic.Id.fileRef, ~check=fromString)
@@ -0,0 +1,17 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Sury from "sury";
4
+ import * as Semantic$Reventless from "./Semantic.res.mjs";
5
+ import * as Media_Ref$Reventless from "./Media_Ref.res.mjs";
6
+
7
+ function fromString(raw) {
8
+ return Media_Ref$Reventless.check("file", raw);
9
+ }
10
+
11
+ let schema = Semantic$Reventless.refined(Sury.string, Semantic$Reventless.Id.fileRef, fromString);
12
+
13
+ export {
14
+ fromString,
15
+ schema,
16
+ }
17
+ /* schema Not a pure module */
@@ -99,20 +99,24 @@ let validateLng = (raw: float): result<float, string> =>
99
99
  11-alpha miscompiles a refinement wrapping a *record* schema. Refining the
100
100
  field is both the honest placement and the one that works. */
101
101
  let latSchema: S.t<float> =
102
- S.float->S.refine(s => raw =>
103
- switch validateLat(raw) {
104
- | Ok(_) => ()
105
- | Error(why) => s.fail(why)
106
- }
102
+ S.float->S.refine(
103
+ raw =>
104
+ switch validateLat(raw) {
105
+ | Ok(_) => true
106
+ | Error(_) => false
107
+ },
108
+ ~error="expected a latitude in -90…90",
107
109
  )
108
110
 
109
111
  /** The longitude's own schema, for the same reason. */
110
112
  let lngSchema: S.t<float> =
111
- S.float->S.refine(s => raw =>
112
- switch validateLng(raw) {
113
- | Ok(_) => ()
114
- | Error(why) => s.fail(why)
115
- }
113
+ S.float->S.refine(
114
+ raw =>
115
+ switch validateLng(raw) {
116
+ | Ok(_) => true
117
+ | Error(_) => false
118
+ },
119
+ ~error="expected a longitude in -180…180",
116
120
  )
117
121
 
118
122
  @schema
@@ -1,6 +1,7 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as S from "sury/src/S.res.mjs";
4
+ import * as Sury from "sury";
4
5
  import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
5
6
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
7
  import * as Semantic$Reventless from "./Semantic.res.mjs";
@@ -47,25 +48,17 @@ function validateLng(raw) {
47
48
  }
48
49
  }
49
50
 
50
- let latSchema = S.refine(S.float, s => (raw => {
51
- let why = validateLat(raw);
52
- if (why.TAG === "Ok") {
53
- return;
54
- } else {
55
- return s.fail(why._0, undefined);
56
- }
57
- }));
51
+ let latSchema = S.refine(Sury.float, raw => {
52
+ let match = validateLat(raw);
53
+ return match.TAG === "Ok";
54
+ }, "expected a latitude in -90…90", undefined);
58
55
 
59
- let lngSchema = S.refine(S.float, s => (raw => {
60
- let why = validateLng(raw);
61
- if (why.TAG === "Ok") {
62
- return;
63
- } else {
64
- return s.fail(why._0, undefined);
65
- }
66
- }));
56
+ let lngSchema = S.refine(Sury.float, raw => {
57
+ let match = validateLng(raw);
58
+ return match.TAG === "Ok";
59
+ }, "expected a longitude in -180…180", undefined);
67
60
 
68
- let schema = S.schema(s => ({
61
+ let schema = Sury.$schema(s => ({
69
62
  lat: s.m(latSchema),
70
63
  lng: s.m(lngSchema)
71
64
  }));
@@ -0,0 +1,51 @@
1
+ /**
2
+ A reference to an image the platform does **not** own.
3
+
4
+ The counterpart of {!UploadableImage}, and the difference is provisioning: this
5
+ field states the same *content* fact — the value is a picture, and renders as
6
+ one — and states nothing about where it lives. No store is declared, none is
7
+ provisioned, no upload endpoint is bound, and the value arrives from wherever
8
+ its producer got it: a supplier's CDN, another system's asset host.
9
+
10
+ Use `UploadableImage.t` for a picture the deployment stores and serves. Use this
11
+ one where the platform is a reader of somebody else's image and could not
12
+ provision a store for it if it wanted to.
13
+
14
+ ## The grammar
15
+
16
+ An `http`/`https` URL, or an origin-relative path. Both are things a browser can
17
+ put in an `src`; nothing else is.
18
+
19
+ `data:` URIs are refused, and that is the rule worth stating: an event log is
20
+ append-only, so a megabyte inlined into an image field is permanent and
21
+ unfixable. That is the same hole {!StorageRef} exists to close, arriving through
22
+ a field that declares no store.
23
+
24
+ @example
25
+ ```rescript
26
+ @schema type event =
27
+ | SupplierProductListed({
28
+ supplierId: @s.matches(DcbTag.string) string,
29
+ thumbnail: @s.matches(Reventless.ImageRef.schema) string,
30
+ })
31
+ ```
32
+ */
33
+
34
+ /** Transparent `string`; see `Email.t`. */
35
+ type t = string
36
+
37
+ external unsafe: string => t = "%identity"
38
+ external toString: t => string = "%identity"
39
+
40
+ /**
41
+ Validate a raw string as a reference to an unowned image, saying why when it is
42
+ not one.
43
+
44
+ Shared by {!FileRef} through `Media_Ref.check`: the two differ in what they
45
+ depict, not in how a reference is written, so one grammar serves both.
46
+ */
47
+ let fromString = (raw: string): result<t, string> => Media_Ref.check(~what="image", raw)
48
+
49
+ /** The sury schema for an image-reference field.
50
+ Use with `@s.matches(Reventless.ImageRef.schema)`. */
51
+ let schema: S.t<t> = S.string->Semantic.refined(~id=Semantic.Id.imageRef, ~check=fromString)
@@ -0,0 +1,17 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Sury from "sury";
4
+ import * as Semantic$Reventless from "./Semantic.res.mjs";
5
+ import * as Media_Ref$Reventless from "./Media_Ref.res.mjs";
6
+
7
+ function fromString(raw) {
8
+ return Media_Ref$Reventless.check("image", raw);
9
+ }
10
+
11
+ let schema = Semantic$Reventless.refined(Sury.string, Semantic$Reventless.Id.imageRef, fromString);
12
+
13
+ export {
14
+ fromString,
15
+ schema,
16
+ }
17
+ /* schema Not a pure module */
@@ -0,0 +1,33 @@
1
+ // The grammar `ImageRef` and `FileRef` share. They differ in what the value
2
+ // depicts, not in how a reference to it is written, so the rule lives once here
3
+ // rather than twice with a chance to disagree.
4
+
5
+ /** Is this an absolute web address? Schemes fold case per RFC 3986. */
6
+ let hasWebScheme = (raw: string): bool => {
7
+ let lower = String.toLowerCase(raw)
8
+ String.startsWith(lower, "http://") || String.startsWith(lower, "https://")
9
+ }
10
+
11
+ /**
12
+ Validate a reference to a resource the platform does not own: an `http`/`https`
13
+ URL, or an origin-relative path. `~what` names the kind in the rejection so the
14
+ message reads as the field's own.
15
+
16
+ An origin-relative path is admitted because a value may legitimately have been
17
+ minted by this platform earlier and simply not be declared as stored here —
18
+ refusing it would make the unowned types unable to hold their own history.
19
+ */
20
+ let check = (~what: string, raw: string): result<string, string> =>
21
+ if raw === "" {
22
+ Error(`expected a ${what} reference, got an empty string`)
23
+ } else if hasWebScheme(raw) {
24
+ Ok(raw)
25
+ } else if String.startsWith(raw, "/") && !String.startsWith(raw, "//") {
26
+ Ok(raw)
27
+ } else {
28
+ Error(
29
+ `expected an http:// or https:// address, or an origin-relative path, got ${Semantic.showString(
30
+ raw,
31
+ )}. A data: URI is not a ${what} reference — it inlines the bytes into the event log, permanently.`,
32
+ )
33
+ }