@nuggetslife/vc 0.1.0 → 0.3.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.
- package/Cargo.toml +1 -0
- package/W3C_CONFORMANCE.md +9 -6
- package/bench/frame_compare.mjs +7 -20
- package/bench/v2_internals.mjs +3 -5
- package/bench/vc_ops.mjs +4 -10
- package/index.d.ts +2 -2
- package/interop-allowlist.json +3 -0
- package/interop-smoke-allowlist.json +3 -0
- package/package.json +8 -7
- package/src/bls_signatures/bbs_bls_holder_bound_signature_2022/mod.rs +18 -27
- package/src/bls_signatures/bbs_bls_holder_bound_signature_proof_2022/mod.rs +9 -10
- package/src/bls_signatures/bbs_bls_signature_2020/mod.rs +21 -25
- package/src/bls_signatures/bbs_bls_signature_proof_2020/mod.rs +6 -12
- package/src/jsonld.rs +40 -75
- package/src/ld_signatures.rs +210 -224
- package/src/lib.rs +8 -0
- package/test-fixtures/interop/README.md +46 -0
- package/test-fixtures/interop/_contexts/README.md +51 -0
- package/test-fixtures/interop/_contexts/bbs-bound-v1.jsonld +92 -0
- package/test-fixtures/interop/_contexts/citizenship-v1.jsonld +58 -0
- package/test-fixtures/interop/_contexts/credentials-v1.jsonld +316 -0
- package/test-fixtures/interop/_contexts/elm-edc-ap.jsonld +809 -0
- package/test-fixtures/interop/_contexts/essif-schemas-vc-2020-v1.jsonld +47 -0
- package/test-fixtures/interop/_contexts/identity-v2.jsonld +195 -0
- package/test-fixtures/interop/_contexts/nuggets-identity-v1.jsonld +175 -0
- package/test-fixtures/interop/_contexts/nuggets-kyb-v1.jsonld +333 -0
- package/test-fixtures/interop/_contexts/openbadges-v3.jsonld +445 -0
- package/test-fixtures/interop/_contexts/security-bbs-v1.jsonld +93 -0
- package/test-fixtures/interop/ebsi/diploma-elm/README.md +29 -0
- package/test-fixtures/interop/ebsi/diploma-elm/expected.nq +70 -0
- package/test-fixtures/interop/ebsi/diploma-elm/frame.jsonld +24 -0
- package/test-fixtures/interop/ebsi/diploma-elm/input.jsonld +444 -0
- package/test-fixtures/interop/ebsi/diploma-simple/README.md +19 -0
- package/test-fixtures/interop/ebsi/diploma-simple/expected.nq +9 -0
- package/test-fixtures/interop/ebsi/diploma-simple/frame.jsonld +13 -0
- package/test-fixtures/interop/ebsi/diploma-simple/input.jsonld +24 -0
- package/test-fixtures/interop/idv2/full-disclosure/README.md +9 -0
- package/test-fixtures/interop/idv2/full-disclosure/expected.nq +59 -0
- package/test-fixtures/interop/idv2/full-disclosure/frame.jsonld +9 -0
- package/test-fixtures/interop/idv2/full-disclosure/input.jsonld +82 -0
- package/test-fixtures/interop/nuggets/identity-v1/README.md +17 -0
- package/test-fixtures/interop/nuggets/identity-v1/expected.nq +21 -0
- package/test-fixtures/interop/nuggets/identity-v1/frame.jsonld +17 -0
- package/test-fixtures/interop/nuggets/identity-v1/input.jsonld +31 -0
- package/test-fixtures/interop/nuggets/kyb-v1/README.md +15 -0
- package/test-fixtures/interop/nuggets/kyb-v1/expected.nq +18 -0
- package/test-fixtures/interop/nuggets/kyb-v1/frame.jsonld +24 -0
- package/test-fixtures/interop/nuggets/kyb-v1/input.jsonld +60 -0
- package/test-fixtures/interop/openbadges-v3/basic-achievement/README.md +17 -0
- package/test-fixtures/interop/openbadges-v3/basic-achievement/expected.nq +12 -0
- package/test-fixtures/interop/openbadges-v3/basic-achievement/frame.jsonld +17 -0
- package/test-fixtures/interop/openbadges-v3/basic-achievement/input.jsonld +25 -0
- package/test-fixtures/interop/openbadges-v3/with-allowed-values/README.md +11 -0
- package/test-fixtures/interop/openbadges-v3/with-allowed-values/expected.nq +25 -0
- package/test-fixtures/interop/openbadges-v3/with-allowed-values/frame.jsonld +22 -0
- package/test-fixtures/interop/openbadges-v3/with-allowed-values/input.jsonld +40 -0
- package/test-fixtures/interop/vp/single-vc-wrap/README.md +6 -0
- package/test-fixtures/interop/vp/single-vc-wrap/expected.nq +7 -0
- package/test-fixtures/interop/vp/single-vc-wrap/frame.jsonld +17 -0
- package/test-fixtures/interop/vp/single-vc-wrap/input.jsonld +27 -0
- package/test-fixtures/interop/w3c-vc-v1/permanent-resident-card/README.md +5 -0
- package/test-fixtures/interop/w3c-vc-v1/permanent-resident-card/expected.nq +13 -0
- package/test-fixtures/interop/w3c-vc-v1/permanent-resident-card/frame.jsonld +14 -0
- package/test-fixtures/interop/w3c-vc-v1/permanent-resident-card/input.jsonld +29 -0
- package/test_interop.mjs +184 -0
- package/test_interop_smoke.mjs +388 -0
- package/test_w3c_conformance.mjs +7 -0
- package/tools/regen_expected.mjs +108 -0
- package/w3c-baseline.json +63 -74
- package/w3c-denylist.json +6 -1
package/src/jsonld.rs
CHANGED
|
@@ -2,17 +2,14 @@ use serde_json::{json, Value};
|
|
|
2
2
|
use std::collections::HashMap;
|
|
3
3
|
use std::sync::Arc;
|
|
4
4
|
|
|
5
|
-
use vc::
|
|
6
|
-
document_loader::nuggets::DocumentLoader,
|
|
7
|
-
jsonld::{self, context_resolver::ContextResolver},
|
|
8
|
-
};
|
|
5
|
+
use vc::document_loader::nuggets::DocumentLoader;
|
|
9
6
|
|
|
10
7
|
use crate::ld_signatures::create_document_loader;
|
|
11
8
|
|
|
12
9
|
/// JSON-LD processor — drop-in replacement for the jsonld.js API.
|
|
13
10
|
///
|
|
14
|
-
/// Holds a `DocumentLoader`
|
|
15
|
-
///
|
|
11
|
+
/// Holds a `DocumentLoader` internally so it is created once and reused
|
|
12
|
+
/// across all method calls.
|
|
16
13
|
///
|
|
17
14
|
/// ```js
|
|
18
15
|
/// const jsonld = new JsonLd({ contexts: { "https://example.org/ctx": {...} } });
|
|
@@ -22,7 +19,6 @@ use crate::ld_signatures::create_document_loader;
|
|
|
22
19
|
#[napi]
|
|
23
20
|
pub struct JsonLd {
|
|
24
21
|
loader: Arc<DocumentLoader>,
|
|
25
|
-
cr: Arc<ContextResolver>,
|
|
26
22
|
additional_contexts: Arc<HashMap<String, Value>>,
|
|
27
23
|
}
|
|
28
24
|
|
|
@@ -47,10 +43,9 @@ impl JsonLd {
|
|
|
47
43
|
.and_then(|v| v.as_object())
|
|
48
44
|
.map(|obj| obj.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
|
|
49
45
|
.unwrap_or_default();
|
|
50
|
-
let
|
|
46
|
+
let loader = create_document_loader(additional_contexts.clone());
|
|
51
47
|
Self {
|
|
52
48
|
loader,
|
|
53
|
-
cr,
|
|
54
49
|
additional_contexts: Arc::new(additional_contexts),
|
|
55
50
|
}
|
|
56
51
|
}
|
|
@@ -64,15 +59,9 @@ impl JsonLd {
|
|
|
64
59
|
#[napi]
|
|
65
60
|
pub async fn expand(&self, input: Value, options: Option<Value>) -> napi::Result<Value> {
|
|
66
61
|
let opts = options.unwrap_or(json!({}));
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
.map_err(|e| napi::Error::from_reason(format!("expand (v2) failed: {e}")))
|
|
71
|
-
} else {
|
|
72
|
-
jsonld::expand(input, self.loader.clone(), self.cr.clone(), opts)
|
|
73
|
-
.await
|
|
74
|
-
.map_err(|e| napi::Error::from_reason(format!("expand failed: {e}")))
|
|
75
|
-
}
|
|
62
|
+
let additional = self.additional_contexts();
|
|
63
|
+
vc::jsonld_v2::expand_v2_sync(input, &additional, opts)
|
|
64
|
+
.map_err(|e| napi::Error::from_reason(format!("expand failed: {e}")))
|
|
76
65
|
}
|
|
77
66
|
|
|
78
67
|
/// Compact a JSON-LD document using a context.
|
|
@@ -90,15 +79,9 @@ impl JsonLd {
|
|
|
90
79
|
options: Option<Value>,
|
|
91
80
|
) -> napi::Result<Value> {
|
|
92
81
|
let opts = options.unwrap_or(json!({}));
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
.map_err(|e| napi::Error::from_reason(format!("compact (v2) failed: {e}")))
|
|
97
|
-
} else {
|
|
98
|
-
jsonld::compact_api(input, ctx, self.loader.clone(), self.cr.clone(), opts)
|
|
99
|
-
.await
|
|
100
|
-
.map_err(|e| napi::Error::from_reason(format!("compact failed: {e}")))
|
|
101
|
-
}
|
|
82
|
+
let additional = self.additional_contexts();
|
|
83
|
+
vc::jsonld_v2::compact_v2_sync(input, ctx, &additional, opts)
|
|
84
|
+
.map_err(|e| napi::Error::from_reason(format!("compact failed: {e}")))
|
|
102
85
|
}
|
|
103
86
|
|
|
104
87
|
/// Flatten a JSON-LD document.
|
|
@@ -118,15 +101,9 @@ impl JsonLd {
|
|
|
118
101
|
let opts = options.unwrap_or(json!({}));
|
|
119
102
|
// Filter out null ctx (JS passes null, Rust expects None)
|
|
120
103
|
let ctx = ctx.filter(|v| !v.is_null());
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
.map_err(|e| napi::Error::from_reason(format!("flatten (v2) failed: {e}")))
|
|
125
|
-
} else {
|
|
126
|
-
jsonld::flatten(input, ctx, self.loader.clone(), self.cr.clone(), opts)
|
|
127
|
-
.await
|
|
128
|
-
.map_err(|e| napi::Error::from_reason(format!("flatten failed: {e}")))
|
|
129
|
-
}
|
|
104
|
+
let additional = self.additional_contexts();
|
|
105
|
+
vc::jsonld_v2::flatten_v2_sync(input, ctx, &additional, opts)
|
|
106
|
+
.map_err(|e| napi::Error::from_reason(format!("flatten failed: {e}")))
|
|
130
107
|
}
|
|
131
108
|
|
|
132
109
|
/// Frame a JSON-LD document.
|
|
@@ -144,25 +121,16 @@ impl JsonLd {
|
|
|
144
121
|
options: Option<Value>,
|
|
145
122
|
) -> napi::Result<Value> {
|
|
146
123
|
let opts = options.unwrap_or(json!({}));
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
let loader = self.loader.clone();
|
|
153
|
-
let cr = self.cr.clone();
|
|
154
|
-
let join = tokio::task::spawn_blocking(move || {
|
|
155
|
-
vc::jsonld_v2::frame_native_sync(input, frame, loader, cr, opts)
|
|
156
|
-
.map_err(|e| napi::Error::from_reason(format!("frame (native) failed: {e}")))
|
|
157
|
-
});
|
|
158
|
-
join
|
|
159
|
-
.await
|
|
160
|
-
.map_err(|e| napi::Error::from_reason(format!("frame (v2) join: {e}")))?
|
|
161
|
-
} else {
|
|
162
|
-
jsonld::frame(input, frame, self.loader.clone(), self.cr.clone(), opts)
|
|
163
|
-
.await
|
|
124
|
+
// V2 frame is the native typed-tree walker (Sprint 3 Phase D cutover).
|
|
125
|
+
let loader = self.loader.clone();
|
|
126
|
+
let additional = self.additional_contexts();
|
|
127
|
+
let join = tokio::task::spawn_blocking(move || {
|
|
128
|
+
vc::jsonld_v2::frame_native_sync(input, frame, loader, opts, &additional)
|
|
164
129
|
.map_err(|e| napi::Error::from_reason(format!("frame failed: {e}")))
|
|
165
|
-
}
|
|
130
|
+
});
|
|
131
|
+
join
|
|
132
|
+
.await
|
|
133
|
+
.map_err(|e| napi::Error::from_reason(format!("frame join: {e}")))?
|
|
166
134
|
}
|
|
167
135
|
|
|
168
136
|
/// Convert a JSON-LD document to an RDF dataset.
|
|
@@ -174,22 +142,23 @@ impl JsonLd {
|
|
|
174
142
|
#[napi(js_name = "toRDF")]
|
|
175
143
|
pub async fn to_rdf(&self, input: Value, options: Option<Value>) -> napi::Result<Value> {
|
|
176
144
|
let opts = options.unwrap_or(json!({}));
|
|
177
|
-
//
|
|
178
|
-
//
|
|
145
|
+
// The N-Quads output path is the V2 fast path (string output);
|
|
146
|
+
// otherwise return the dataset as a JSON quads array.
|
|
179
147
|
let wants_nquads = opts
|
|
180
148
|
.get("format")
|
|
181
149
|
.and_then(|v| v.as_str())
|
|
182
150
|
.map(|s| s == "application/n-quads")
|
|
183
151
|
.unwrap_or(false);
|
|
184
|
-
|
|
185
|
-
|
|
152
|
+
let additional = self.additional_contexts();
|
|
153
|
+
if wants_nquads {
|
|
186
154
|
let nquads = vc::jsonld_v2::to_nquads_v2_sync(input, &additional, opts)
|
|
187
|
-
.map_err(|e| napi::Error::from_reason(format!("toRDF
|
|
155
|
+
.map_err(|e| napi::Error::from_reason(format!("toRDF failed: {e}")))?;
|
|
188
156
|
Ok(Value::String(nquads))
|
|
189
157
|
} else {
|
|
190
|
-
|
|
191
|
-
.
|
|
192
|
-
|
|
158
|
+
let quads = vc::jsonld_v2::to_quads_v2_sync(input, &additional, opts)
|
|
159
|
+
.map_err(|e| napi::Error::from_reason(format!("toRDF failed: {e}")))?;
|
|
160
|
+
serde_json::to_value(&quads)
|
|
161
|
+
.map_err(|e| napi::Error::from_reason(format!("toRDF serialize failed: {e}")))
|
|
193
162
|
}
|
|
194
163
|
}
|
|
195
164
|
|
|
@@ -202,7 +171,7 @@ impl JsonLd {
|
|
|
202
171
|
#[napi(js_name = "fromRDF")]
|
|
203
172
|
pub fn from_rdf(&self, dataset: Value, options: Option<Value>) -> napi::Result<Value> {
|
|
204
173
|
let opts = options.unwrap_or(json!({}));
|
|
205
|
-
|
|
174
|
+
vc::jsonld_v2::from_rdf_sync(dataset, opts)
|
|
206
175
|
.map_err(|e| napi::Error::from_reason(format!("fromRDF failed: {e}")))
|
|
207
176
|
}
|
|
208
177
|
|
|
@@ -228,20 +197,16 @@ impl JsonLd {
|
|
|
228
197
|
.and_then(|v| v.as_str())
|
|
229
198
|
.map(|s| s == "application/n-quads")
|
|
230
199
|
.unwrap_or(false);
|
|
231
|
-
let result = if
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
&additional,
|
|
236
|
-
self.loader.clone(),
|
|
237
|
-
self.cr.clone(),
|
|
238
|
-
opts,
|
|
239
|
-
)
|
|
240
|
-
.map_err(|e| napi::Error::from_reason(format!("canonize (v2) failed: {e}")))?
|
|
241
|
-
} else {
|
|
242
|
-
jsonld::canonize(input, self.loader.clone(), self.cr.clone(), opts)
|
|
200
|
+
let result = if input_is_nquads {
|
|
201
|
+
// canonize_v2 always runs expand+to_rdf and would mis-treat an
|
|
202
|
+
// N-Quads string as JSON-LD; route directly through RDF canonicalize.
|
|
203
|
+
vc::rdf_canonize::canonize(input, opts)
|
|
243
204
|
.await
|
|
244
205
|
.map_err(|e| napi::Error::from_reason(format!("canonize failed: {e}")))?
|
|
206
|
+
} else {
|
|
207
|
+
let additional = self.additional_contexts();
|
|
208
|
+
vc::jsonld_v2::canonize_v2_sync(input, &additional, self.loader.clone(), opts)
|
|
209
|
+
.map_err(|e| napi::Error::from_reason(format!("canonize failed: {e}")))?
|
|
245
210
|
};
|
|
246
211
|
Ok(Value::String(result))
|
|
247
212
|
}
|