@paulhectork/aiiinotate 0.12.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.
Files changed (104) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +206 -0
  3. package/cli/export.js +118 -0
  4. package/cli/import.js +111 -0
  5. package/cli/index.js +45 -0
  6. package/cli/migrate.js +131 -0
  7. package/cli/serve.js +29 -0
  8. package/cli/utils/fastifyClient.js +86 -0
  9. package/cli/utils/io.js +225 -0
  10. package/cli/utils/mongoClient.js +21 -0
  11. package/cli/utils/progressbar.js +86 -0
  12. package/cli/xywhToInt.js +99 -0
  13. package/config/.env.template +48 -0
  14. package/docker/Dockerfile +39 -0
  15. package/docker/README.md +5 -0
  16. package/docker/docker-compose.yaml +49 -0
  17. package/docker/docker.sh +43 -0
  18. package/docker/docker_aiiinotate_import.sh +62 -0
  19. package/docs/api.md +381 -0
  20. package/docs/cli.md +132 -0
  21. package/docs/dev_documentation/dev_architecture.md +88 -0
  22. package/docs/dev_documentation/dev_db.md +58 -0
  23. package/docs/dev_documentation/dev_iiif_compatibility.md +43 -0
  24. package/docs/dev_documentation/dev_notes_quirks_and_troubleshooting.md +143 -0
  25. package/docs/docker.md +98 -0
  26. package/docs/includes/report_benchmark_aiiinotate_2026-05-28-02:50:48_7steps.png +0 -0
  27. package/docs/scalability.md +34 -0
  28. package/docs/specifications/0_w3c_open_annotations.md +332 -0
  29. package/docs/specifications/1_w3c_web_annotations.md +577 -0
  30. package/docs/specifications/2_iiif_apis.md +428 -0
  31. package/docs/specifications/3_iiif_annotations.md +103 -0
  32. package/docs/specifications/4_search_api.md +135 -0
  33. package/docs/specifications/5_sas.md +119 -0
  34. package/docs/specifications/6_mirador.md +119 -0
  35. package/docs/specifications/7_aikon.md +137 -0
  36. package/docs/specifications/include/presentation_2.0.webp +0 -0
  37. package/docs/specifications/include/presentation_2.0_white.png +0 -0
  38. package/docs/specifications/include/presentation_3.0.png +0 -0
  39. package/docs/specifications/include/presentation_3.0_resize.png +0 -0
  40. package/eslint.config.js +30 -0
  41. package/migrations/baseConfig.js +57 -0
  42. package/migrations/manageIndex.js +55 -0
  43. package/migrations/migrate-mongo-config-main.js +8 -0
  44. package/migrations/migrate-mongo-config-test.js +8 -0
  45. package/migrations/migrationScripts/20250825185706-collections.js +48 -0
  46. package/migrations/migrationScripts/20250826194832-annotations2-schema.js +42 -0
  47. package/migrations/migrationScripts/20250904080710-annotations2-indexes.js +69 -0
  48. package/migrations/migrationScripts/20251002141951-manifests2-schema.js +43 -0
  49. package/migrations/migrationScripts/20251006212110-manifests2-indexes.js +35 -0
  50. package/migrations/migrationTemplate.js +25 -0
  51. package/package.json +82 -0
  52. package/scripts/get_version.py +12 -0
  53. package/scripts/run.sh +36 -0
  54. package/scripts/setup_mongodb.sh +70 -0
  55. package/scripts/setup_node.sh +15 -0
  56. package/scripts/update_version.py +30 -0
  57. package/scripts/utils.sh +65 -0
  58. package/src/app.js +116 -0
  59. package/src/constants.js +73 -0
  60. package/src/data/annotations/annotations2.js +681 -0
  61. package/src/data/annotations/annotations3.js +28 -0
  62. package/src/data/annotations/routes.js +335 -0
  63. package/src/data/annotations/routes.test.js +271 -0
  64. package/src/data/collectionAbstract.js +283 -0
  65. package/src/data/index.js +29 -0
  66. package/src/data/manifests/manifests2.js +378 -0
  67. package/src/data/manifests/manifests2.test.js +53 -0
  68. package/src/data/manifests/manifests3.js +23 -0
  69. package/src/data/manifests/routes.js +122 -0
  70. package/src/data/manifests/routes.test.js +70 -0
  71. package/src/data/routes.js +181 -0
  72. package/src/data/routes.test.js +166 -0
  73. package/src/db/index.js +50 -0
  74. package/src/fixtures/annotations.js +41 -0
  75. package/src/fixtures/data/annotationList_aikon_wit9_man11_anno165_all.jsonld +827 -0
  76. package/src/fixtures/data/annotationList_vhs_wit250_man250_anno250_all.jsonld +37514 -0
  77. package/src/fixtures/data/annotationList_vhs_wit253_man253_anno253_all.jsonld +20111 -0
  78. package/src/fixtures/data/annotations2Invalid.jsonld +39 -0
  79. package/src/fixtures/data/annotations2SvgValid.jsonld +81 -0
  80. package/src/fixtures/data/annotations2Valid.jsonld +39 -0
  81. package/src/fixtures/data/bnf_invalid_manifest.json +2806 -0
  82. package/src/fixtures/data/bnf_valid_manifest.json +2817 -0
  83. package/src/fixtures/data/vhs_wit253_man253_anno253_anno-24.json +1 -0
  84. package/src/fixtures/generate.js +181 -0
  85. package/src/fixtures/index.js +69 -0
  86. package/src/fixtures/manifests.js +14 -0
  87. package/src/fixtures/utils.js +37 -0
  88. package/src/schemas/index.js +100 -0
  89. package/src/schemas/schemasBase.js +19 -0
  90. package/src/schemas/schemasPresentation2.js +410 -0
  91. package/src/schemas/schemasPresentation3.js +33 -0
  92. package/src/schemas/schemasResolver.js +71 -0
  93. package/src/schemas/schemasRoutes.js +318 -0
  94. package/src/server.js +25 -0
  95. package/src/types.js +97 -0
  96. package/src/utils/iiif2Utils.js +332 -0
  97. package/src/utils/iiif2Utils.test.js +146 -0
  98. package/src/utils/iiif3Utils.js +0 -0
  99. package/src/utils/iiifUtils.js +18 -0
  100. package/src/utils/logger.js +119 -0
  101. package/src/utils/routeUtils.js +137 -0
  102. package/src/utils/svg.js +417 -0
  103. package/src/utils/testUtils.js +289 -0
  104. package/src/utils/utils.js +403 -0
@@ -0,0 +1,332 @@
1
+ # Open annotations data model
2
+
3
+ [https://web.archive.org/web/20220119101135/http://www.openannotation.org/spec/core](https://web.archive.org/web/20220119101135/http://www.openannotation.org/spec/core)
4
+
5
+ [https://web.archive.org/web/20221225112722/http://www.openannotation.org/spec/core/core.html](https://web.archive.org/web/20221225112722/http://www.openannotation.org/spec/core/core.html)
6
+
7
+ [https://www.w3.org/TR/annotation-vocab/](https://www.w3.org/TR/annotation-vocab/)
8
+
9
+
10
+ The IIIF 2.x standard relies on the W3C Open annotations (OA) standard. Established in 2013, it has since been deprecated in favour of the W3C's Web annotations model, described in the next section. To make things fun, the site is not longer available and must be accessed through the wayback machine.
11
+
12
+ ---
13
+
14
+ ## In general
15
+
16
+ - an Annotation is **a set of interconnected resources**, made mostly of a `Body` and a `Target`
17
+ - the data model is **implementation independant** and can be implemented in JSON, RDF-XML, Turtle...
18
+ - the standard extamples are in RDF, while IIIF uses JSON-ld. In turn, keys vary from the IIIF standard. When there are differences, I indicate both what is in the OA examples, and what is used in IIIF.
19
+
20
+ ---
21
+
22
+ ## Vocabulary
23
+
24
+ - `Annotation`: a set of interconnected resources, with at its core a `Body` and a `Target`, where the `Body` is about the `Target`.
25
+ - `Target`: the object being annotated
26
+ - `Body`: the annotation's contents
27
+ - `Motivation`: the motivation further describes the relationship between `Body` and `Target`
28
+
29
+ ---
30
+
31
+ ## Namespaces
32
+
33
+ <table>
34
+ <tbody><tr><th>Prefix</th><th>Namespace</th><th>Description</th></tr>
35
+ <tr><td>oa</td><td>http://www.w3.org/ns/oa#</td> <td>The Open Annotation ontology</td></tr>
36
+
37
+ <tr><td>cnt</td><td>http://www.w3.org/2011/content#</td><td><a href="https://web.archive.org/web/20220119101135/http://www.w3.org/TR/Content-in-RDF10/">Representing Content in RDF</a></td></tr>
38
+ <tr><td>dc</td><td>http://purl.org/dc/elements/1.1/</td><td><a href="https://web.archive.org/web/20220119101135/http://dublincore.org/documents/dces/">Dublin Core Elements</a></td></tr>
39
+ <tr><td>dcterms</td><td>http://purl.org/dc/terms/</td><td><a href="https://web.archive.org/web/20220119101135/http://dublincore.org/documents/dcmi-terms/">Dublin Core Terms</a></td></tr>
40
+ <tr><td>dctypes</td><td>http://purl.org/dc/dcmitype/</td><td><a href="https://web.archive.org/web/20220119101135/http://dublincore.org/documents/dcmi-type-vocabulary/">Dublin Core Type Vocabulary</a></td></tr>
41
+ <tr><td>foaf</td><td>http://xmlns.com/foaf/0.1/</td><td><a href="https://web.archive.org/web/20220119101135/http://xmlns.com/foaf/spec/">Friend-of-a-Friend Vocabulary</a></td></tr>
42
+ <tr><td>prov</td><td>http://www.w3.org/ns/prov#</td><td><a href="https://web.archive.org/web/20220119101135/http://www.w3.org/TR/prov-o/">Provenance Ontology</a></td></tr>
43
+ <tr><td>rdf</td><td>http://www.w3.org/1999/02/22-rdf-syntax-ns#</td><td><a href="https://web.archive.org/web/20220119101135/http://www.w3.org/TR/rdf-syntax-grammar/">RDF</a></td></tr>
44
+ <tr><td>rdfs</td><td>http://www.w3.org/2000/01/rdf-schema#</td><td><a href="https://web.archive.org/web/20220119101135/http://www.w3.org/TR/rdf-schema/">RDF Schema</a></td></tr>
45
+ <tr><td>skos</td><td>http://www.w3.org/2004/02/skos/core#</td><td><a href="https://web.archive.org/web/20220119101135/http://www.w3.org/TR/skos-reference/">Simple Knowledge Organization System</a></td></tr>
46
+ <tr><td>trig</td><td>http://www.w3.org/2004/03/trix/rdfg-1/</td><td><a href="https://web.archive.org/web/20220119101135/http://www.w3.org/2004/03/trix/">TriG Named Graphs</a></td></tr>
47
+
48
+ </tbody></table>
49
+
50
+ ---
51
+
52
+ ## Annotations
53
+
54
+ An annotation has 1+ `Targets` and 0+ `Bodies`
55
+ - IIIF `@id`: `URI`
56
+ - is used to identify with an URI the `Annotation`, `Body` and `Target`
57
+ - in Turtle, there is no specific key because the standard is different.
58
+ - `a` (IIIF `@type`): `oa:Annotation`
59
+ - this indicates that the resource is an `Annotation`
60
+ - `oa:hasBody` (IIIF `resource`): `Body | Body[]`
61
+ - the relationship between `Annotation` and `Body`
62
+ - the body MAY be omitted if there is no content to annotate
63
+ - `oa:hasTarget` (IIIF `on`): `Target | Target[]`
64
+ - the relationship between `Annotation` and `Target`
65
+ - `oa:Motivation` (IIIF `motivation`): `string[]` (in IIIF, `oa:commenting | sc:painting` are frequent)
66
+ - the motivation, or role of the annotation
67
+ - `all allowed values are: `oa:bookmarking | oa:classifying | oa:commenting | oa:describing | oa:editing | oa:highlighting | oa:identifying | oa:linking | oa:moderating | oa:questionning | oa:replying | oa:tagging`
68
+ - in IIIF, `sc:painting` is also allowed to indicate a painting annotation. The most useful values are `sc:painting | oa:commenting`.
69
+
70
+ ```js
71
+ // basic structure
72
+ {
73
+ "@id": "<URI>",
74
+ "@type": "oa:Annotation",
75
+ "motivation": "sc:painting" || "oa:commenting", // or an array of values
76
+ "resource": {
77
+ "@id": "<URI?>",
78
+ "@type": "<dctype>",
79
+ // other keys
80
+ },
81
+ "on": "<URI>" || SpecificResource // `on` can be either specified as the URI to a canvas, or as a SpecificResource
82
+ }
83
+ ```
84
+ ### Bodies and targets
85
+
86
+ - `a` (IIIF `@type`): `dctypes:Dataset | dctypes:Image | dctypes:MovingImage | dctypes:Sound | dcTypes:Text`
87
+ - SHOULD be used to describe the type of a `Body` or `Target`
88
+ - IIIF `@id`: `URI`
89
+
90
+ Special cases:
91
+ - an annotation may have **no `Body`**
92
+ - an annotation may have **multiple `Bodies` or `Targets`**.
93
+ - in that case, **each body is related to each target individually**. If we have 2 bodies and 2 targets, we have the following situation:
94
+ ```
95
+ body1 <-> target1
96
+ body1 <-> target2
97
+ body2 <-> target1
98
+ body2 <-> target2
99
+ ```
100
+ - you may have 1 `Target` and N `Bodies` (several annotations apply to a single body), or N `Target` and 1 `Bodies` (1 annotation applies to several images) or an N to N relationship.
101
+
102
+ ### Embedded textual body (ETB)
103
+
104
+ ETBs are used to embed textual content directly in an annotation instead of referencing it by an `id`.
105
+ - `a` (IIIF `@type`): `cnt:ContentAsText | dctypes:Text`
106
+ - MUST be used to indicate that this is an ETB. MAY contain both values described above.
107
+ - `cnt:chars` (IIIF `chars`): `string`
108
+ - MUST Be used to contain the contents of the ETB.
109
+ - `dc:format` (SAS `format`): `mimetype`
110
+ - SHOULD be used to describe the mimetype of the ETB
111
+ - for example, it can distinguish plain text form HTML.
112
+ - `dc:language`: `string`
113
+ - the language the ETB is in
114
+ - language codes SHOULD follow [RFC 3066](https://www.ietf.org/rfc/rfc3066.txt)
115
+
116
+ ```js
117
+ {
118
+ "@type" : "dctypes:Text",
119
+ "format" : "text/html",
120
+ "chars" : "<p>This is en embedded textual content from SAS</p>",
121
+ }
122
+ ```
123
+
124
+ ### Tags
125
+
126
+ A tag is a specific type of `Body`: a keyword or label used to annotate a `Target`. There are 2 types of tags: "normal" and "semantic" tags
127
+ - `a` (IIIF `@type`): `oa:Tag | oa:SemanticTag`
128
+ - `oa:Tag` describes a non-semantic tag. In that case, the tag functions like an ETB
129
+ - `oa:SemanticTag` describes a semantic tag. Instead of containing the contents of the tag, the `Body` references an external URI.
130
+ - `oa:Motivation` (IIIF `motivation`): `oa:tagging`
131
+ - `oa:tagging` should be added to the `oa:Motivation` of the annotation to indicate it's a tag
132
+
133
+ ### Fragment URIs
134
+
135
+ Fragment URIs can be used to target part of a resource.
136
+ - fragments ARE NOT COMPATIBLE with `SpecificResources`. Either use one or the other.
137
+
138
+ ```js
139
+ {
140
+ "@id": "http://example.com/image.jpg#xywh=1,1,1,1"
141
+ }
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Specific Resources
147
+
148
+ [https://web.archive.org/web/20221225112722/http://www.openannotation.org/spec/core/specific.html](https://web.archive.org/web/20221225112722/http://www.openannotation.org/spec/core/specific.html)
149
+
150
+ `SpecificResources` are an extension of the core data model to reference part of a resource with more precision than Fragment URIs. They can be used either in `Bodies` or `Targets` (though in IIIF they are used mostly in `Targets`).
151
+
152
+ ```js
153
+ // basic IIIF structure for a SpecificResource
154
+ {
155
+ "@id": "<annotationId>",
156
+ "@type": "oa:SpecificResource",
157
+ "full": {
158
+ // link to the full image
159
+ },
160
+ "selector": {
161
+ "@type": "<selectorType>",
162
+ "value": "<selectorValue>"
163
+ },
164
+ "within": {
165
+ // extra context, such as the IIIF manifest in which to include the annotation
166
+ },
167
+ }
168
+ ```
169
+
170
+ ### Basic units
171
+
172
+ 3 conceptual units are present in the Specific Resource model:
173
+ - `Source resource`: the complete target , i.e. an entire image that we want to select a section of.
174
+ - `SpecificResource`: the segment of the resource described by the `Specifier`
175
+ - `Specifiers`: describes how to determine the aspects of the `Source` that constitute the Specific Resource.
176
+
177
+ ### Specifiers
178
+
179
+ There are 3 types of specifiers:
180
+ - `oa:State`: specifies the state of a `Body` or a `Target` applicable to an `Annotation` in order to retrieve the proper representation of the resource. For example,
181
+ - the timestamp at which a `Body` was created (if there are several versions of the same resource with different timestamps)
182
+ - `oa:Selector`: specifies the segment of a resource relevant to the `Annotation`: text range, image section, SVG selector...
183
+ - `oa:Style`: a description of how to style an `Annotation`
184
+
185
+ If `State` and `Selector` are present in a annotation, the `State` will be processed before `Selector` to be sure that we have the proper state.
186
+
187
+ Keys:
188
+ - `a` (IIIF `@type`) `oa:SpecificResource`: the specific resource
189
+ - `oa:hasSource` (SAS `full`): the `Source Resource` being specified by the `Specific Resource`.
190
+ - MUST be used: the `Specific Resource` is defined relatively to the `Source Resource`, and so the renderer will fetch the `Source` before targeting the `Specific resource` part.
191
+
192
+ I'll only present selectors, not `states` or `styles` that aren't used in IIIF.
193
+
194
+ ### Selectors
195
+
196
+ A `Selector` is a `Specifier` which describes how to determine the segment of interest from within the retrieved representation of the Source resource. There MUST be only 1 `Selector` per specifier, otherwise use the [multiplicity module](https://web.archive.org/web/20221225112718/http://www.openannotation.org/spec/core/multiplicity.html).
197
+
198
+ - `oa:hasSource` (IIIF `full`): the `Source resource`
199
+ - `oa:hasSelector` (IIIF `selector`): the `Selector`'s content
200
+
201
+ There are selectors other than those presented below: `RangeSelector`, `TextPositionSelector`, `TextQuoteSelector`... but they are out of scope with IIIF so I won't talk about them
202
+
203
+ #### FragmentSelector
204
+
205
+ - `a` (IIIF `@type`): `oa:FragmentSelector`
206
+ - `rdf:value` (IIIF `value`): `string'
207
+ - `dcterms:conformsTo`: the specification that defines the syntax of the fragment.
208
+ - for IIIF, targets can only be targeted using IIIF-specific `ImageApiSelector` or W3C media fragments (`xhwh=int,int,int,int`).
209
+ - SHOULD be used
210
+ - SHOULD be one of:
211
+
212
+ <table>
213
+ <tbody><tr><th>Fragment Specification</th><th>Description</th></tr>
214
+ <tr><td>http://tools.ietf.org/rfc/rfc3236</td><td><a href="https://web.archive.org/web/20221225112722/http://tools.ietf.org/rfc/rfc3236">XHTML, and HTML</a>. Example: #namedSection </td></tr>
215
+ <tr><td>http://tools.ietf.org/rfc/rfc3778</td><td><a href="https://web.archive.org/web/20221225112722/http://tools.ietf.org/rfc/rfc3778">PDF</a>. Example: #page=10&amp;viewrect=50,50,640,480</td></tr>
216
+ <tr><td>http://tools.ietf.org/rfc/rfc5147</td><td><a href="https://web.archive.org/web/20221225112722/http://tools.ietf.org/rfc/rfc5147">Plain Text</a>. Example: #char=0,10</td></tr>
217
+ <tr><td>http://tools.ietf.org/rfc/rfc3023</td><td><a href="https://web.archive.org/web/20221225112722/http://tools.ietf.org/rfc/rfc3023">XML</a>. Example: #xpointer(/a/b/c) </td></tr>
218
+ <tr><td>http://www.ietf.org/rfc/rfc3870</td><td><a href="https://web.archive.org/web/20221225112722/http://www.ietf.org/rfc/rfc3870">RDF/XML</a>. Example: #namedResource </td></tr>
219
+ <tr><td>http://www.w3.org/TR/media-frags/</td><td><a href="https://web.archive.org/web/20221225112722/http://www.w3.org/TR/media-frags/">W3C Media Fragments</a>. Example: #xywh=50,50,640,480</td></tr>
220
+ <tr><td>http://www.w3.org/TR/SVG/</td><td><a href="https://web.archive.org/web/20221225112722/http://www.w3.org/TR/SVG/">SVG</a>. Example: #svgView(viewBox(50,50,640,480))</td></tr>
221
+ </tbody></table>
222
+
223
+ ```js
224
+ {
225
+ // ...
226
+ selector: {
227
+ "@type": "oa:FragmentSelector",
228
+ "value": "xywh=int,int,int,int" // so here we use the W3C media fragments selector
229
+ }
230
+
231
+ }
232
+ ```
233
+
234
+ #### SVG selectors
235
+
236
+ `SvgSelectors` define an area through an SVG.
237
+ - the `SvgSelector`'s value MUST be a valid and complete SVG document
238
+ - the SVG SHOULD be a single shape: `path|rect|circle|ellipse|polyline|polygone|g`
239
+ - dimensions in the SVG MUST be relative to the `Source resource`.
240
+ - For example, given an image which is 600 pixels by 400 pixels, and the desired section is a circle of 100 pixel radius at the center of the image, then the SVG element would be: `<circle cx="300" cy="200" r="100"/>`
241
+
242
+
243
+ ### Examples
244
+
245
+
246
+ `Specific resource` structure in IIIF 2.x.
247
+ ```js
248
+ {
249
+ "@type" : "oa:SpecificResource",
250
+ "within" : {
251
+ "@id" : "https://aikon.enpc.fr/aikon/iiif/v2/wit9_man11_anno165/manifest.json",
252
+ "@type" : "sc:Manifest"
253
+ },
254
+ "selector" : {
255
+ "@type" : "oa:FragmentSelector",
256
+ "value" : "xywh=0,31,1865,1670"
257
+ },
258
+ "full" : "https://aikon.enpc.fr/aikon/iiif/v2/wit9_man11_anno165/canvas/c16.json"
259
+ }
260
+ ```
261
+
262
+ `Specific resource` that uses the IIIF `ImageApiSelector` extension
263
+ ```js
264
+ {
265
+ // `@id` uses the IIIF Image api to describe the fragment
266
+ "@id": "http://www.example.org/iiif/book1-page1/50,50,1250,1850/full/0/default.jpg",
267
+ "@type": "oa:SpecificResource",
268
+
269
+ // `full` describes the full image.
270
+ "full": {
271
+ "@id": "http://example.org/iiif/book1-page1/full/full/0/default.jpg",
272
+ "@type": "dctypes:Image",
273
+ "service": {
274
+ "@context": "http://iiif.io/api/image/2/context.json",
275
+ "@id": "http://example.org/iiif/book1-page1",
276
+ "profile": "http://iiif.io/api/image/2/level2.json"
277
+ }
278
+ },
279
+
280
+ // `selector` describes the region targeted in `@id`
281
+ "selector": {
282
+ "@context": "http://iiif.io/api/annex/openannotation/context.json",
283
+ "@type": "iiif:ImageApiSelector",
284
+ "region": "50,50,1250,1850"
285
+ }
286
+ }
287
+ ```
288
+
289
+ ---
290
+
291
+ ## Multiplicity
292
+
293
+ [https://web.archive.org/web/20221225112718/http://www.openannotation.org/spec/core/multiplicity.html](https://web.archive.org/web/20221225112718/http://www.openannotation.org/spec/core/multiplicity.html)
294
+
295
+ In IIIF, this module is useful if we want to specify more than 1 `SpecificResource`. In OA, the multiplicity module is used to have multiple bodies or targets in an annotation (IE: 3 bodies in 3 languages). Options for multiplicity are:
296
+
297
+ - `oa:Choice`: only one of several bodies/targets will be rendered at once. Done by defining 1 default value and other alternative values
298
+ - `oa:Composite`: when all resources are required for an annotation to function properly.
299
+ - `oa:List`: like a composite, but ordered
300
+
301
+ `Bodies` and `Targets` can use `multiplicity` by setting their `@type` to `oa:Choice | oa:Composite |oa:List`.
302
+
303
+ I have only ever seen `oa:Choice` be used in IIIF so that's the one I'll present.
304
+
305
+ ### `oa:Choice`
306
+
307
+ ```js
308
+ {
309
+ "@type": "oa:Choice",
310
+ "default": /** default choice */,
311
+ "item": /** one or several other available items */
312
+ }
313
+ ```
314
+
315
+ Example: a choice between a `FragmentSelector` and an `SvgSelector`
316
+ ```js
317
+ {
318
+ "@type" : "oa:Choice",
319
+ "default" : {
320
+ "@type" : "oa:FragmentSelector",
321
+ "value" : "xywh=0,31,1865,1670"
322
+ },
323
+ "item" : {
324
+ "@type" : "oa:SvgSelector",
325
+ "value" : "<svg xmlns=\"http://www.w3.org/2000/svg\"><path xmlns='http://www.w3.org/2000/svg' d='M0 31 h 932 v 0 h 932 v 835 v 835 h -932 h -932 v -835Z' id='rectangle_wit9_man11_anno165_c16_5ebd8bc8044b45b58aae2a508ca75eed' data-paper-data='{&quot;strokeWidth&quot;:1,&quot;rotation&quot;:0,&quot;annotation&quot;:null,&quot;nonHoverStrokeColor&quot;:[&quot;Color&quot;,0,1,0],&quot;editable&quot;:true,&quot;deleteIcon&quot;:null,&quot;rotationIcon&quot;:null,&quot;group&quot;:null}' fill-opacity='0' fill='#00ff00' fill-rule='nonzero' stroke='#00ff00' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter' stroke-miterlimit='10' stroke-dashoffset='0' style='mix-blend-mode: normal'/></svg>"
326
+ }
327
+ }
328
+ ```
329
+
330
+
331
+
332
+