@reventlessdev/reventless-spec 3.0.0-alpha.116 → 3.0.0-alpha.118

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 (67) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/package.json +4 -4
  3. package/schema/platform-api.graphql +11 -2
  4. package/src/components/CapabilityManifest.res +1 -1
  5. package/src/components/CapabilityManifest.res.mjs +13 -12
  6. package/src/components/DcbDecode.res +8 -8
  7. package/src/components/DcbDecode.res.mjs +9 -8
  8. package/src/components/DcbTag.res +43 -42
  9. package/src/components/DcbTag.res.mjs +90 -87
  10. package/src/components/DcbValidation.res +6 -6
  11. package/src/components/DcbValidation.res.mjs +6 -6
  12. package/src/components/DisplayName.res.mjs +3 -3
  13. package/src/components/Owner.res +1 -1
  14. package/src/components/Owner.res.mjs +7 -7
  15. package/src/components/Plugin.res +28 -11
  16. package/src/components/Plugin.res.mjs +134 -134
  17. package/src/components/Reference.res.mjs +5 -5
  18. package/src/components/StateAnnotations.res +44 -0
  19. package/src/components/StateAnnotations.res.mjs +3 -3
  20. package/src/generator/PlatformCodegen.res +17 -14
  21. package/src/generator/PlatformCodegen.res.mjs +1 -1
  22. package/src/generator/PlatformGenerator.res +1 -1
  23. package/src/semantic/Bytes.res.mjs +2 -2
  24. package/src/semantic/Color.res.mjs +2 -2
  25. package/src/semantic/Currency.res.mjs +167 -167
  26. package/src/semantic/DateRange.res.mjs +2 -2
  27. package/src/semantic/Duration.res.mjs +2 -2
  28. package/src/semantic/Email.res +2 -2
  29. package/src/semantic/Email.res.mjs +3 -2
  30. package/src/semantic/FileRef.res +28 -0
  31. package/src/semantic/FileRef.res.mjs +17 -0
  32. package/src/semantic/GeoPoint.res +14 -10
  33. package/src/semantic/GeoPoint.res.mjs +10 -17
  34. package/src/semantic/ImageRef.res +51 -0
  35. package/src/semantic/ImageRef.res.mjs +17 -0
  36. package/src/semantic/Media_Ref.res +33 -0
  37. package/src/semantic/Media_Ref.res.mjs +37 -0
  38. package/src/semantic/Money.res +7 -5
  39. package/src/semantic/Money.res.mjs +6 -9
  40. package/src/semantic/Offload.res +29 -43
  41. package/src/semantic/Offload.res.mjs +18 -49
  42. package/src/semantic/Percent.res.mjs +2 -2
  43. package/src/semantic/Phone.res.mjs +2 -2
  44. package/src/semantic/Semantic.res +24 -6
  45. package/src/semantic/Semantic.res.mjs +13 -12
  46. package/src/semantic/StorageRef.res +33 -19
  47. package/src/semantic/StorageRef.res.mjs +14 -14
  48. package/src/semantic/UploadableFile.res +30 -0
  49. package/src/semantic/UploadableFile.res.mjs +23 -0
  50. package/src/semantic/UploadableImage.res +56 -0
  51. package/src/semantic/UploadableImage.res.mjs +23 -0
  52. package/src/semantic/Url.res +8 -2
  53. package/src/semantic/Url.res.mjs +3 -2
  54. package/src/types/Authorization.res.mjs +7 -7
  55. package/src/types/DateTime.res.mjs +2 -2
  56. package/src/types/Id.res.mjs +6 -4
  57. package/src/types/Identity.res +0 -1
  58. package/src/types/Identity.res.mjs +12 -14
  59. package/src/types/Message.res +29 -10
  60. package/src/types/Message.res.mjs +56 -37
  61. package/src/types/ReadConsistency.res.mjs +5 -5
  62. package/src/types/Schedule.res.mjs +37 -37
  63. package/src/types/StoredEvent.res +2 -2
  64. package/src/types/StoredEvent.res.mjs +11 -10
  65. package/src/types/Visibility.res.mjs +4 -4
  66. package/src/util/Util_Sury.res +32 -0
  67. package/src/util/Util_Sury.res.mjs +39 -0
@@ -105,13 +105,12 @@ type apiTarget = Domain | Platform
105
105
  // Sury's nullableAsOption creates T | undefined | null which fails jsonableValidation
106
106
  // inside union variant payloads. js_nullable creates T | null (no undefined) which is
107
107
  // JSON-safe and passes jsonableValidation in all contexts.
108
- @module("sury/src/Sury.res.mjs") external _jsNullable: (S.t<'a>, unit) => S.t<option<'a>> = "js_nullable"
109
108
  let apiSchemaFragmentOffloadSchema = Offload.optionSchema(~store="pluginApiFragments", apiSchemaFragmentSchema)
110
- let dcbEventLogOptionSchema = _jsNullable(dcbEventLogDefinitionSchema, ())
109
+ let dcbEventLogOptionSchema = dcbEventLogDefinitionSchema->S.nullAsOption
111
110
  // js_nullable creates T | null which passes sury's jsonableValidation inside union variant payloads.
112
- let stringOptionSchema = _jsNullable(S.string, ())
113
- let stringArrayOptionSchema = _jsNullable(S.array(S.string), ())
114
- let boolOptionSchema = _jsNullable(S.bool, ())
111
+ let stringOptionSchema = S.string->S.nullAsOption
112
+ let stringArrayOptionSchema = S.array(S.string)->S.nullAsOption
113
+ let boolOptionSchema = S.bool->S.nullAsOption
115
114
 
116
115
  // ── UI fragment manifest types ────────────────────────────────────────────────
117
116
 
@@ -147,7 +146,7 @@ type uiFragmentManifest = {
147
146
  pages: array<pageManifestEntry>,
148
147
  }
149
148
 
150
- let uiFragmentManifestOptionSchema = _jsNullable(uiFragmentManifestSchema, ())
149
+ let uiFragmentManifestOptionSchema = uiFragmentManifestSchema->S.nullAsOption
151
150
 
152
151
  // ── Plugin structure types (component metadata for Auto UI and event graph) ──
153
152
 
@@ -325,6 +324,26 @@ type queryableDef = {
325
324
  */
326
325
  retiredValues: @s.matches(stringArrayOptionSchema) option<array<string>>,
327
326
  /**
327
+ Whether this view publishes a **reference door**: the by-ids read that names a
328
+ retired row for any caller holding a pointer to it, projected to the row's id,
329
+ its `labelField` and the value of `retiredField`. Declared with
330
+ `@namedWhenRetired` on the state record.
331
+
332
+ Published so a client knows the door exists without probing for it — a query
333
+ against a field the schema does not have is a validation error, not an empty
334
+ answer, so "ask and see" is not a usable fallback here.
335
+
336
+ Nullable rather than a bare required bool, which is the rule this schema's own
337
+ tripwire enforces: a definition stored before the field existed would otherwise
338
+ decode with an invented value and a runtime warning. Absent and `false` mean the
339
+ same thing to every reader — the archive stays shut — but only one of them is
340
+ something the platform actually said.
341
+
342
+ It is never `true` without `retiredField`: the PPX refuses the annotation on a
343
+ record with no retirement.
344
+ */
345
+ namedWhenRetired: @s.matches(boolOptionSchema) option<bool>,
346
+ /**
328
347
  Component visibility hint (`@@reventless.visibility`). `Some("Internal")` marks a
329
348
  ReadModel / StateViewSlice that the deployed AutoUI hides from its menu, drill-down
330
349
  pages, web event graph and cross-plugin edges. `None` (absent) means Public. Internal
@@ -546,7 +565,7 @@ type extensionPointDef = {
546
565
 
547
566
  // js_nullable creates `array | null` (not `| undefined`), which passes sury's
548
567
  // jsonableValidation inside the pluginStructure union variant payload.
549
- let extensionPointDefArrayOptionSchema = _jsNullable(S.array(extensionPointDefSchema), ())
568
+ let extensionPointDefArrayOptionSchema = S.array(extensionPointDefSchema)->S.nullAsOption
550
569
 
551
570
  /**
552
571
  One field's store requirement, with its provenance.
@@ -584,10 +603,8 @@ type requiredStoreDeclaration = {
584
603
  annotation: @s.matches(stringOptionSchema) option<string>,
585
604
  }
586
605
 
587
- let requiredStoreDeclarationArrayOptionSchema = _jsNullable(
588
- S.array(requiredStoreDeclarationSchema),
589
- (),
590
- )
606
+ let requiredStoreDeclarationArrayOptionSchema =
607
+ S.array(requiredStoreDeclarationSchema)->S.nullAsOption
591
608
 
592
609
  /**
593
610
  Adding a field here? It has to be a shape a stale event can be healed into.
@@ -1,107 +1,110 @@
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 Offload$Reventless from "../semantic/Offload.res.mjs";
5
- import * as SuryResMjs from "sury/src/Sury.res.mjs";
6
5
 
7
- let pluginKindSchema = S.union([
8
- S.literal("Domain"),
9
- S.literal("PlatformInfrastructure"),
10
- S.literal("Commercial"),
11
- S.literal("Marketplace")
6
+ let nameSchema = Sury.string;
7
+
8
+ let versionSchema = Sury.string;
9
+
10
+ let pluginKindSchema = Sury.union([
11
+ Sury.literal("Domain"),
12
+ Sury.literal("PlatformInfrastructure"),
13
+ Sury.literal("Commercial"),
14
+ Sury.literal("Marketplace")
12
15
  ]);
13
16
 
14
- let extensionPointDefinitionSchema = S.schema(s => ({
15
- name: s.m(S.string),
16
- commandTopic: s.m(S.string),
17
- eventTopic: s.m(S.string)
17
+ let extensionPointDefinitionSchema = Sury.$schema(s => ({
18
+ name: s.m(Sury.string),
19
+ commandTopic: s.m(Sury.string),
20
+ eventTopic: s.m(Sury.string)
18
21
  }));
19
22
 
20
- let extensionDefinitionSchema = S.schema(s => ({
21
- name: s.m(S.string),
22
- extensionPointName: s.m(S.string),
23
- dcbSources: s.m(S.array(S.string))
23
+ let extensionDefinitionSchema = Sury.$schema(s => ({
24
+ name: s.m(Sury.string),
25
+ extensionPointName: s.m(Sury.string),
26
+ dcbSources: s.m(Sury.array(Sury.string))
24
27
  }));
25
28
 
26
- let dcbEventLogDefinitionSchema = S.schema(s => ({
27
- name: s.m(S.string),
28
- eventTopicArn: s.m(S.string)
29
+ let dcbEventLogDefinitionSchema = Sury.$schema(s => ({
30
+ name: s.m(Sury.string),
31
+ eventTopicArn: s.m(Sury.string)
29
32
  }));
30
33
 
31
- let extensionProtocolSchema = S.schema(s => ({
32
- extensionPointName: s.m(S.string),
33
- commandVersion: s.m(S.string),
34
- eventVersion: s.m(S.string)
34
+ let extensionProtocolSchema = Sury.$schema(s => ({
35
+ extensionPointName: s.m(Sury.string),
36
+ commandVersion: s.m(Sury.string),
37
+ eventVersion: s.m(Sury.string)
35
38
  }));
36
39
 
37
- let apiSchemaFragmentSchema = S.schema(s => ({
38
- encoded: s.m(S.string),
39
- protocol: s.m(S.string)
40
+ let apiSchemaFragmentSchema = Sury.$schema(s => ({
41
+ encoded: s.m(Sury.string),
42
+ protocol: s.m(Sury.string)
40
43
  }));
41
44
 
42
- let apiTargetSchema = S.union([
43
- S.literal("Domain"),
44
- S.literal("Platform")
45
+ let apiTargetSchema = Sury.union([
46
+ Sury.literal("Domain"),
47
+ Sury.literal("Platform")
45
48
  ]);
46
49
 
47
50
  let apiSchemaFragmentOffloadSchema = Offload$Reventless.optionSchema(undefined, "pluginApiFragments", undefined, apiSchemaFragmentSchema);
48
51
 
49
- let dcbEventLogOptionSchema = SuryResMjs.js_nullable(dcbEventLogDefinitionSchema);
52
+ let dcbEventLogOptionSchema = Sury.$nullAsOption(dcbEventLogDefinitionSchema);
50
53
 
51
- let stringOptionSchema = SuryResMjs.js_nullable(S.string);
54
+ let stringOptionSchema = Sury.$nullAsOption(Sury.string);
52
55
 
53
- let stringArrayOptionSchema = SuryResMjs.js_nullable(S.array(S.string));
56
+ let stringArrayOptionSchema = Sury.$nullAsOption(Sury.array(Sury.string));
54
57
 
55
- let boolOptionSchema = SuryResMjs.js_nullable(S.bool);
58
+ let boolOptionSchema = Sury.$nullAsOption(Sury.bool);
56
59
 
57
- let panelManifestEntrySchema = S.schema(s => ({
58
- fragmentId: s.m(S.string),
59
- title: s.m(S.string),
60
- description: s.m(S.string),
61
- positions: s.m(S.array(S.string)),
60
+ let panelManifestEntrySchema = Sury.$schema(s => ({
61
+ fragmentId: s.m(Sury.string),
62
+ title: s.m(Sury.string),
63
+ description: s.m(Sury.string),
64
+ positions: s.m(Sury.array(Sury.string)),
62
65
  requiredAccess: s.m(stringOptionSchema)
63
66
  }));
64
67
 
65
- let menuEntrySchema = S.schema(s => ({
66
- label: s.m(S.string),
68
+ let menuEntrySchema = Sury.$schema(s => ({
69
+ label: s.m(Sury.string),
67
70
  icon: s.m(stringOptionSchema),
68
71
  group: s.m(stringOptionSchema),
69
- sortOrder: s.m(S.int)
72
+ sortOrder: s.m(Sury.int)
70
73
  }));
71
74
 
72
- let pageManifestEntrySchema = S.schema(s => ({
73
- fragmentId: s.m(S.string),
74
- title: s.m(S.string),
75
+ let pageManifestEntrySchema = Sury.$schema(s => ({
76
+ fragmentId: s.m(Sury.string),
77
+ title: s.m(Sury.string),
75
78
  menuEntry: s.m(menuEntrySchema),
76
79
  requiredAccess: s.m(stringOptionSchema)
77
80
  }));
78
81
 
79
- let uiFragmentManifestSchema = S.schema(s => ({
80
- remoteEntryUrl: s.m(S.string),
81
- panels: s.m(S.array(panelManifestEntrySchema)),
82
- pages: s.m(S.array(pageManifestEntrySchema))
82
+ let uiFragmentManifestSchema = Sury.$schema(s => ({
83
+ remoteEntryUrl: s.m(Sury.string),
84
+ panels: s.m(Sury.array(panelManifestEntrySchema)),
85
+ pages: s.m(Sury.array(pageManifestEntrySchema))
83
86
  }));
84
87
 
85
- let uiFragmentManifestOptionSchema = SuryResMjs.js_nullable(uiFragmentManifestSchema);
88
+ let uiFragmentManifestOptionSchema = Sury.$nullAsOption(uiFragmentManifestSchema);
86
89
 
87
- let commandLevelSchema = S.union([
88
- S.literal("Collection"),
89
- S.literal("Instance")
90
+ let commandLevelSchema = Sury.union([
91
+ Sury.literal("Collection"),
92
+ Sury.literal("Instance")
90
93
  ]);
91
94
 
92
- let fieldReferenceSchema = S.schema(s => ({
93
- fieldName: s.m(S.string),
94
- entity: s.m(S.string),
95
+ let fieldReferenceSchema = Sury.$schema(s => ({
96
+ fieldName: s.m(Sury.string),
97
+ entity: s.m(Sury.string),
95
98
  plugin: s.m(stringOptionSchema)
96
99
  }));
97
100
 
98
- let commandDefSchema = S.schema(s => ({
99
- name: s.m(S.string),
100
- schema: s.m(S.string),
101
+ let commandDefSchema = Sury.$schema(s => ({
102
+ name: s.m(Sury.string),
103
+ schema: s.m(Sury.string),
101
104
  level: s.m(commandLevelSchema),
102
105
  aggregateIdField: s.m(stringOptionSchema),
103
- mutationField: s.m(S.string),
104
- references: s.m(S.array(fieldReferenceSchema)),
106
+ mutationField: s.m(Sury.string),
107
+ references: s.m(Sury.array(fieldReferenceSchema)),
105
108
  allowedStates: s.m(stringArrayOptionSchema),
106
109
  targetState: s.m(stringOptionSchema),
107
110
  apiExposed: s.m(boolOptionSchema),
@@ -109,19 +112,20 @@ let commandDefSchema = S.schema(s => ({
109
112
  ownerField: s.m(stringOptionSchema)
110
113
  }));
111
114
 
112
- let queryableDefSchema = S.schema(s => ({
113
- name: s.m(S.string),
114
- queryField: s.m(S.string),
115
- schema: s.m(S.string),
116
- consumedEventTypes: s.m(S.array(S.string)),
117
- linkedWriteSide: s.m(S.array(S.string)),
118
- labelField: s.m(S.string),
119
- searchableFields: s.m(S.array(S.string)),
115
+ let queryableDefSchema = Sury.$schema(s => ({
116
+ name: s.m(Sury.string),
117
+ queryField: s.m(Sury.string),
118
+ schema: s.m(Sury.string),
119
+ consumedEventTypes: s.m(Sury.array(Sury.string)),
120
+ linkedWriteSide: s.m(Sury.array(Sury.string)),
121
+ labelField: s.m(Sury.string),
122
+ searchableFields: s.m(Sury.array(Sury.string)),
120
123
  labelFieldSource: s.m(stringOptionSchema),
121
124
  lifecycleField: s.m(stringOptionSchema),
122
125
  ownerField: s.m(stringOptionSchema),
123
126
  retiredField: s.m(stringOptionSchema),
124
127
  retiredValues: s.m(stringArrayOptionSchema),
128
+ namedWhenRetired: s.m(boolOptionSchema),
125
129
  visibility: s.m(stringOptionSchema),
126
130
  chapter: s.m(stringOptionSchema),
127
131
  singleQueryField: s.m(stringOptionSchema),
@@ -130,89 +134,89 @@ let queryableDefSchema = S.schema(s => ({
130
134
  requiredAccess: s.m(stringArrayOptionSchema)
131
135
  }));
132
136
 
133
- let eventDefSchema = S.schema(s => ({
134
- name: s.m(S.string),
135
- schema: s.m(S.string),
136
- references: s.m(S.array(fieldReferenceSchema))
137
+ let eventDefSchema = Sury.$schema(s => ({
138
+ name: s.m(Sury.string),
139
+ schema: s.m(Sury.string),
140
+ references: s.m(Sury.array(fieldReferenceSchema))
137
141
  }));
138
142
 
139
- let errorDefSchema = S.schema(s => ({
140
- name: s.m(S.string),
141
- schema: s.m(S.string),
142
- references: s.m(S.array(fieldReferenceSchema))
143
+ let errorDefSchema = Sury.$schema(s => ({
144
+ name: s.m(Sury.string),
145
+ schema: s.m(Sury.string),
146
+ references: s.m(Sury.array(fieldReferenceSchema))
143
147
  }));
144
148
 
145
- let writableDefSchema = S.schema(s => ({
146
- name: s.m(S.string),
147
- commands: s.m(S.array(commandDefSchema)),
148
- producedEventTypes: s.m(S.array(S.string)),
149
- consumedEventTypes: s.m(S.array(S.string)),
150
- linkedViews: s.m(S.array(S.string)),
149
+ let writableDefSchema = Sury.$schema(s => ({
150
+ name: s.m(Sury.string),
151
+ commands: s.m(Sury.array(commandDefSchema)),
152
+ producedEventTypes: s.m(Sury.array(Sury.string)),
153
+ consumedEventTypes: s.m(Sury.array(Sury.string)),
154
+ linkedViews: s.m(Sury.array(Sury.string)),
151
155
  consistencyRead: s.m(stringOptionSchema),
152
- events: s.m(S.array(eventDefSchema)),
153
- errors: s.m(S.array(errorDefSchema)),
156
+ events: s.m(Sury.array(eventDefSchema)),
157
+ errors: s.m(Sury.array(errorDefSchema)),
154
158
  chapter: s.m(stringOptionSchema)
155
159
  }));
156
160
 
157
- let automationSliceDefSchema = S.schema(s => ({
158
- name: s.m(S.string),
159
- consumedEventTypes: s.m(S.array(S.string)),
160
- producedCommandTypes: s.m(S.array(S.string)),
161
- targetName: s.m(S.string),
161
+ let automationSliceDefSchema = Sury.$schema(s => ({
162
+ name: s.m(Sury.string),
163
+ consumedEventTypes: s.m(Sury.array(Sury.string)),
164
+ producedCommandTypes: s.m(Sury.array(Sury.string)),
165
+ targetName: s.m(Sury.string),
162
166
  chapter: s.m(stringOptionSchema)
163
167
  }));
164
168
 
165
- let outboundTranslationSliceDefSchema = S.schema(s => ({
166
- name: s.m(S.string),
167
- consumedEventTypes: s.m(S.array(S.string)),
168
- inboundCommandTypes: s.m(S.array(S.string)),
169
+ let outboundTranslationSliceDefSchema = Sury.$schema(s => ({
170
+ name: s.m(Sury.string),
171
+ consumedEventTypes: s.m(Sury.array(Sury.string)),
172
+ inboundCommandTypes: s.m(Sury.array(Sury.string)),
169
173
  targetName: s.m(stringOptionSchema),
170
174
  externalSystem: s.m(stringOptionSchema),
171
175
  chapter: s.m(stringOptionSchema)
172
176
  }));
173
177
 
174
- let inboundTranslationSliceDefSchema = S.schema(s => ({
175
- name: s.m(S.string),
176
- commandTypes: s.m(S.array(S.string)),
177
- targetName: s.m(S.string),
178
+ let inboundTranslationSliceDefSchema = Sury.$schema(s => ({
179
+ name: s.m(Sury.string),
180
+ commandTypes: s.m(Sury.array(Sury.string)),
181
+ targetName: s.m(Sury.string),
178
182
  externalSystem: s.m(stringOptionSchema),
179
183
  chapter: s.m(stringOptionSchema)
180
184
  }));
181
185
 
182
- let extensionDefSchema = S.schema(s => ({
183
- name: s.m(S.string),
184
- delegateNames: s.m(S.array(S.string)),
185
- eventTypes: s.m(S.array(S.string)),
186
- commandTypes: s.m(S.array(S.string))
186
+ let extensionDefSchema = Sury.$schema(s => ({
187
+ name: s.m(Sury.string),
188
+ delegateNames: s.m(Sury.array(Sury.string)),
189
+ eventTypes: s.m(Sury.array(Sury.string)),
190
+ commandTypes: s.m(Sury.array(Sury.string))
187
191
  }));
188
192
 
189
- let extensionPointDefSchema = S.schema(s => ({
190
- name: s.m(S.string),
191
- delegateNames: s.m(S.array(S.string)),
192
- sourceEventTypes: s.m(S.array(S.string)),
193
+ let extensionPointDefSchema = Sury.$schema(s => ({
194
+ name: s.m(Sury.string),
195
+ delegateNames: s.m(Sury.array(Sury.string)),
196
+ sourceEventTypes: s.m(Sury.array(Sury.string)),
193
197
  commandTypes: s.m(stringArrayOptionSchema)
194
198
  }));
195
199
 
196
- let extensionPointDefArrayOptionSchema = SuryResMjs.js_nullable(S.array(extensionPointDefSchema));
200
+ let extensionPointDefArrayOptionSchema = Sury.$nullAsOption(Sury.array(extensionPointDefSchema));
197
201
 
198
- let requiredStoreDeclarationSchema = S.schema(s => ({
199
- store: s.m(S.string),
200
- component: s.m(S.string),
201
- field: s.m(S.string),
202
+ let requiredStoreDeclarationSchema = Sury.$schema(s => ({
203
+ store: s.m(Sury.string),
204
+ component: s.m(Sury.string),
205
+ field: s.m(Sury.string),
202
206
  annotation: s.m(stringOptionSchema)
203
207
  }));
204
208
 
205
- let requiredStoreDeclarationArrayOptionSchema = SuryResMjs.js_nullable(S.array(requiredStoreDeclarationSchema));
206
-
207
- let pluginStructureSchema = S.schema(s => ({
208
- readModels: s.m(S.array(queryableDefSchema)),
209
- stateViewSlices: s.m(S.array(queryableDefSchema)),
210
- stateChangeSlices: s.m(S.array(writableDefSchema)),
211
- aggregates: s.m(S.array(writableDefSchema)),
212
- automationSlices: s.m(S.array(automationSliceDefSchema)),
213
- outboundTranslationSlices: s.m(S.array(outboundTranslationSliceDefSchema)),
214
- inboundTranslationSlices: s.m(S.array(inboundTranslationSliceDefSchema)),
215
- extensions: s.m(S.array(extensionDefSchema)),
209
+ let requiredStoreDeclarationArrayOptionSchema = Sury.$nullAsOption(Sury.array(requiredStoreDeclarationSchema));
210
+
211
+ let pluginStructureSchema = Sury.$schema(s => ({
212
+ readModels: s.m(Sury.array(queryableDefSchema)),
213
+ stateViewSlices: s.m(Sury.array(queryableDefSchema)),
214
+ stateChangeSlices: s.m(Sury.array(writableDefSchema)),
215
+ aggregates: s.m(Sury.array(writableDefSchema)),
216
+ automationSlices: s.m(Sury.array(automationSliceDefSchema)),
217
+ outboundTranslationSlices: s.m(Sury.array(outboundTranslationSliceDefSchema)),
218
+ inboundTranslationSlices: s.m(Sury.array(inboundTranslationSliceDefSchema)),
219
+ extensions: s.m(Sury.array(extensionDefSchema)),
216
220
  extensionPoints: s.m(extensionPointDefArrayOptionSchema),
217
221
  requiredStores: s.m(stringArrayOptionSchema),
218
222
  requiredStoreDeclarations: s.m(requiredStoreDeclarationArrayOptionSchema)
@@ -220,14 +224,14 @@ let pluginStructureSchema = S.schema(s => ({
220
224
 
221
225
  let pluginStructureOffloadSchema = Offload$Reventless.optionSchema(undefined, "pluginStructures", undefined, pluginStructureSchema);
222
226
 
223
- let pluginDefinitionSchema = S.schema(s => ({
224
- id: s.m(S.string),
225
- name: s.m(S.string),
226
- version: s.m(S.string),
227
- extensionPoints: s.m(S.array(extensionPointDefinitionSchema)),
228
- extensions: s.m(S.array(extensionDefinitionSchema)),
229
- eventCollector: s.m(S.string),
230
- extensionProtocols: s.m(S.array(extensionProtocolSchema)),
227
+ let pluginDefinitionSchema = Sury.$schema(s => ({
228
+ id: s.m(Sury.string),
229
+ name: s.m(nameSchema),
230
+ version: s.m(versionSchema),
231
+ extensionPoints: s.m(Sury.array(extensionPointDefinitionSchema)),
232
+ extensions: s.m(Sury.array(extensionDefinitionSchema)),
233
+ eventCollector: s.m(Sury.string),
234
+ extensionProtocols: s.m(Sury.array(extensionProtocolSchema)),
231
235
  apiSchemaFragment: s.m(apiSchemaFragmentOffloadSchema),
232
236
  apiTarget: s.m(stringOptionSchema),
233
237
  structure: s.m(pluginStructureOffloadSchema),
@@ -235,10 +239,6 @@ let pluginDefinitionSchema = S.schema(s => ({
235
239
  kind: s.m(pluginKindSchema)
236
240
  }));
237
241
 
238
- let nameSchema = S.string;
239
-
240
- let versionSchema = S.string;
241
-
242
242
  export {
243
243
  nameSchema,
244
244
  versionSchema,
@@ -278,4 +278,4 @@ export {
278
278
  pluginStructureOffloadSchema,
279
279
  pluginDefinitionSchema,
280
280
  }
281
- /* pluginKindSchema Not a pure module */
281
+ /* nameSchema Not a pure module */
@@ -1,12 +1,12 @@
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 Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
5
  import * as DcbTag$Reventless from "./DcbTag.res.mjs";
6
6
  import * as Semantic$Reventless from "../semantic/Semantic.res.mjs";
7
7
 
8
8
  function to_(plugin, key, entity) {
9
- let base = Semantic$Reventless.mark(S.Metadata.set(S.string, DcbTag$Reventless.dcbTagId, true), Semantic$Reventless.Id.reference, {
9
+ let base = Semantic$Reventless.mark(Sury.$Metadata_set(Sury.string, DcbTag$Reventless.dcbTagId, true), Semantic$Reventless.Id.reference, {
10
10
  TAG: "ReferenceTo",
11
11
  _0: {
12
12
  entity: entity,
@@ -14,7 +14,7 @@ function to_(plugin, key, entity) {
14
14
  }
15
15
  });
16
16
  if (key !== undefined) {
17
- return S.Metadata.set(base, DcbTag$Reventless.dcbTagKeyOverrideId, key);
17
+ return Sury.$Metadata_set(base, DcbTag$Reventless.dcbTagKeyOverrideId, key);
18
18
  } else {
19
19
  return base;
20
20
  }
@@ -54,7 +54,7 @@ function getFieldTarget(_schema) {
54
54
  }
55
55
 
56
56
  function toWithoutDcbTag(plugin, entity) {
57
- return Semantic$Reventless.mark(S.string, Semantic$Reventless.Id.reference, {
57
+ return Semantic$Reventless.mark(Sury.string, Semantic$Reventless.Id.reference, {
58
58
  TAG: "ReferenceTo",
59
59
  _0: {
60
60
  entity: entity,
@@ -69,4 +69,4 @@ export {
69
69
  getFieldTarget,
70
70
  toWithoutDcbTag,
71
71
  }
72
- /* S Not a pure module */
72
+ /* sury Not a pure module */
@@ -15,6 +15,8 @@ Each list contains the source field names; `indexes` carries `(fieldName,
15
15
  indexName)` pairs where `indexName` is `""` for unnamed `@index` annotations.
16
16
  `hidden` lists fields the UI should suppress from summary/list views;
17
17
  `summary` lists fields the UI should always include in summary/list views.
18
+ `internal` lists fields that are not on the GraphQL surface at all — see the
19
+ field's own note below; it is a different kind of claim from `hidden`.
18
20
  `drillTargets` carries `(fieldName, sliceName)` pairs naming the slice/view
19
21
  the UI should navigate to instead of expanding the field inline;
20
22
  `drillTargetKeys` carries `(fieldName, keyPath)` pairs for fields whose
@@ -81,6 +83,27 @@ type retiredSpec = {
81
83
  most visibly — would stop firing on a value that looks merely empty.
82
84
  */
83
85
  values: option<array<string>>,
86
+ /**
87
+ Whether a reference to a retired row of this record still resolves — the
88
+ `@namedWhenRetired` opt-in on the `@schema type state` declaration.
89
+
90
+ Retirement withholds a row from every door at once, which is the right answer
91
+ to "what may this caller browse" and an unasked answer to "what is the row this
92
+ caller is already holding a reference to called". An order names a product it
93
+ bought; archiving the product should not unname it on the order.
94
+
95
+ `true` opens exactly one door: a retired row answers a by-ids reference read
96
+ with its id, its label field and the value of `field` — and nothing else, for
97
+ any caller. It does not widen the list, the single-entity read, the index reads
98
+ or the live frame, and it does not touch the owner rule: a retired row that is
99
+ owner-scoped still resolves for its owner alone.
100
+
101
+ Inside `retiredSpec` rather than beside it, because it is a rule about withheld
102
+ rows and there are none without a retirement — the PPX errors on the annotation
103
+ when the record declares no `@retired`, so the nesting states a guarantee rather
104
+ than a convention.
105
+ */
106
+ namedWhenRetired: bool,
84
107
  }
85
108
 
86
109
  type stateAnnotationSpec = {
@@ -91,6 +114,27 @@ type stateAnnotationSpec = {
91
114
  indexes: array<(string, string)>,
92
115
  hidden: array<string>,
93
116
  summary: array<string>,
117
+ /**
118
+ Fields annotated `@internal` — present in the record and in storage, absent
119
+ from the generated SDL type and from the published state schema.
120
+
121
+ A different claim from `hidden`, and the distinction is the point. `hidden`
122
+ says "do not show this": the field is on the API and any client may ask for
123
+ it. `internal` says "this is not on the API", so nothing can ask and nothing
124
+ needs to be told not to show it. That is why the two are separate lists rather
125
+ than one flag with a mode — a consumer reading `hidden` is deciding what to
126
+ render, and a consumer reading this is deciding what exists.
127
+
128
+ **Not a security boundary** — the same caveat `visibility` carries. It shapes
129
+ the generated surface; `@owner` and `@retired` remain the enforcement markers.
130
+ The PPX rejects `@internal` beside either of them, and beside every other
131
+ marker that keys a door, because a door cannot be keyed on a field the SDL
132
+ does not have.
133
+
134
+ Optional so a state schema annotated by a PPX that predates the marker still
135
+ reads: absent and empty mean the same thing to every consumer.
136
+ */
137
+ internal?: array<string>,
94
138
  drillTargets: array<(string, string)>,
95
139
  drillTargetKeys: array<(string, string)>,
96
140
  collapsed: array<string>,
@@ -1,11 +1,11 @@
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 stateAnnotationsId = S.Metadata.Id.make("reventless", "stateAnnotations");
5
+ let stateAnnotationsId = Sury.$Metadata_Id_make("reventless", "stateAnnotations");
6
6
 
7
7
  function getSpec(schema) {
8
- return S.Metadata.get(schema, stateAnnotationsId);
8
+ return Sury.$Metadata_get(schema, stateAnnotationsId);
9
9
  }
10
10
 
11
11
  export {
@@ -73,17 +73,16 @@ let splitKey = (key: string): option<(string, string)> =>
73
73
  key->String.slice(~start=i + 1),
74
74
  ))
75
75
 
76
- // The provenance comment quotes the annotation as its author wrote it — taken
77
- // from the manifest, which recorded it at the one place the owning plugin was
76
+ // The provenance comment names the store as the field spells it — taken from
77
+ // the manifest, which recorded it at the one place the owning plugin was
78
78
  // unambiguous. Inferring it here is what this replaced: the manifest carries a
79
79
  // deploy-manifest entry name and the key carries the registered name, and no
80
80
  // rule relates the two (`platform-inspector` against `PlatformInspector` is an
81
- // ordinary pairing), so any comparison here eventually quotes a string that is
81
+ // ordinary pairing), so any comparison here eventually names a string that is
82
82
  // in no source file.
83
83
  //
84
- // A site with no recorded annotation predates the recording. It still names the
85
- // field, which is the comment's job; it just makes no claim about the source
86
- // text it cannot see.
84
+ // A site with no recorded store predates the recording. It still names the
85
+ // field, which is the comment's job; it just makes no claim it cannot support.
87
86
  let renderEntry = (entry: unionEntry): result<array<string>, string> =>
88
87
  switch splitKey(entry.key) {
89
88
  | None =>
@@ -94,8 +93,13 @@ let renderEntry = (entry: unionEntry): result<array<string>, string> =>
94
93
  let comments =
95
94
  entry.declaredBy->Array.map(site => {
96
95
  let site_ = ` // ${site.pluginName}: ${site.component}.${site.field}`
96
+ // `→ store` rather than `@storageRef("store")`: a field may name its
97
+ // store by annotation *or* by being named, and the manifest carries
98
+ // the store either way without saying which. Naming the annotation
99
+ // would send a reader looking for source text a derived field has not
100
+ // got.
97
101
  switch site.annotation {
98
- | Some(annotation) => `${site_} @storageRef(${quote(annotation)})`
102
+ | Some(annotation) => `${site_} → ${annotation}`
99
103
  | None => site_
100
104
  }
101
105
  })
@@ -115,13 +119,12 @@ aggregate is keyed by the registered name — so a second plugin registering an
115
119
  existing name is not rejected but read as a **new version of the first**, and
116
120
  silently supersedes it in the registry.
117
121
 
118
- Ownership is read from the annotation as authored, which is the one signal that
119
- separates a duplicate from legitimate sharing: an **unqualified**
120
- `@storageRef("productImages")` means "a store of my own plugin", so the
121
- deployable that wrote it is the plugin the key names. A **qualified**
122
- `@storageRef("Catalog.productImages")` points at someone else's store and says
123
- nothing about who owns it — that is the sanctioned cross-plugin form and must not
124
- trip this.
122
+ Ownership is read from the store as the field states it, which is the one signal
123
+ that separates a duplicate from legitimate sharing: an **unqualified**
124
+ `productImages` means "a store of my own plugin", so the deployable that stated
125
+ it is the plugin the key names. A **qualified** `Catalog.productImages` points at
126
+ someone else's store and says nothing about who owns it — that is the sanctioned
127
+ cross-plugin form and must not trip this.
125
128
 
126
129
  Partial by construction: it can only see plugins that declare a store, because
127
130
  capability manifests are the only per-plugin input the generator reads. A
@@ -59,7 +59,7 @@ function renderEntry(entry) {
59
59
  let site_ = ` // ` + site.pluginName + `: ` + site.component + `.` + site.field;
60
60
  let annotation = site.annotation;
61
61
  if (annotation !== undefined) {
62
- return site_ + ` @storageRef(` + JSON.stringify(annotation) + `)`;
62
+ return site_ + ` → ` + annotation;
63
63
  } else {
64
64
  return site_;
65
65
  }
@@ -95,7 +95,7 @@ let () = {
95
95
  )
96
96
  let manifest = try NodeFs.readFileSync(path)
97
97
  ->JSON.parseOrThrow
98
- ->S.parseOrThrow(CapabilityManifest.schema) catch {
98
+ ->S.parseOrThrow(~to=CapabilityManifest.schema) catch {
99
99
  | _ => {
100
100
  fail(`could not parse ${path} as a capability manifest`)
101
101
  ({capabilities: []}: CapabilityManifest.t)