@bradford-tech/supabase-integrity-attest 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/esm/_dnt.test_shims.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/almost_equals.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/array_includes.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/assert.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/assertion_error.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/equal.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/equals.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/exists.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/fail.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/false.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/greater.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/greater_or_equal.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/instance_of.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/is_error.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/less.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/less_or_equal.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/match.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/mod.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_equals.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_instance_of.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_match.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/not_strict_equals.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/object_match.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/rejects.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/strict_equals.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/string_includes.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/throws.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/unimplemented.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.19/unreachable.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common64.d.ts +35 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common64.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common64.js +113 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts +4 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common_detach.js +13 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts +9 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_types.js +2 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base64.d.ts +40 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base64.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/base64.js +82 -0
- package/esm/deps/jsr.io/@std/internal/1.0.12/build_message.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.12/diff.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.12/diff_str.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.12/format.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.12/styles.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.12/types.d.ts.map +1 -0
- package/esm/mod.d.ts +6 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +4 -0
- package/esm/package.json +3 -0
- package/esm/src/assertion.d.ts +9 -0
- package/esm/src/assertion.d.ts.map +1 -0
- package/esm/src/assertion.js +64 -0
- package/esm/src/attestation.d.ts +37 -0
- package/esm/src/attestation.d.ts.map +1 -0
- package/esm/src/attestation.js +242 -0
- package/esm/src/authdata.d.ts +13 -0
- package/esm/src/authdata.d.ts.map +1 -0
- package/esm/src/authdata.js +29 -0
- package/esm/src/certificate.d.ts +25 -0
- package/esm/src/certificate.d.ts.map +1 -0
- package/esm/src/certificate.js +86 -0
- package/esm/src/constants.d.ts +9 -0
- package/esm/src/constants.d.ts.map +1 -0
- package/esm/src/constants.js +56 -0
- package/esm/src/cose.d.ts.map +1 -0
- package/esm/src/der.d.ts +3 -0
- package/esm/src/der.d.ts.map +1 -0
- package/esm/src/der.js +72 -0
- package/esm/src/errors.d.ts +26 -0
- package/esm/src/errors.d.ts.map +1 -0
- package/esm/src/errors.js +52 -0
- package/esm/src/utils.d.ts +13 -0
- package/esm/src/utils.d.ts.map +1 -0
- package/esm/src/utils.js +52 -0
- package/esm/tests/assertion.test.d.ts.map +1 -0
- package/esm/tests/attestation.test.d.ts.map +1 -0
- package/esm/tests/authdata.test.d.ts.map +1 -0
- package/esm/tests/certificate.test.d.ts.map +1 -0
- package/esm/tests/cose.test.d.ts.map +1 -0
- package/esm/tests/der.test.d.ts.map +1 -0
- package/esm/tests/errors.test.d.ts.map +1 -0
- package/esm/tests/fixtures/apple-attestation.d.ts.map +1 -0
- package/esm/tests/fixtures/generate-assertion.d.ts.map +1 -0
- package/esm/tests/utils.test.d.ts.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare enum AttestationErrorCode {
|
|
2
|
+
INVALID_FORMAT = "INVALID_FORMAT",
|
|
3
|
+
INVALID_CERTIFICATE_CHAIN = "INVALID_CERTIFICATE_CHAIN",
|
|
4
|
+
NONCE_MISMATCH = "NONCE_MISMATCH",
|
|
5
|
+
RP_ID_MISMATCH = "RP_ID_MISMATCH",
|
|
6
|
+
KEY_ID_MISMATCH = "KEY_ID_MISMATCH",
|
|
7
|
+
INVALID_COUNTER = "INVALID_COUNTER",
|
|
8
|
+
INVALID_AAGUID = "INVALID_AAGUID"
|
|
9
|
+
}
|
|
10
|
+
export declare class AttestationError extends Error {
|
|
11
|
+
readonly code: AttestationErrorCode;
|
|
12
|
+
readonly name = "AttestationError";
|
|
13
|
+
constructor(code: AttestationErrorCode, message: string);
|
|
14
|
+
}
|
|
15
|
+
export declare enum AssertionErrorCode {
|
|
16
|
+
INVALID_FORMAT = "INVALID_FORMAT",
|
|
17
|
+
RP_ID_MISMATCH = "RP_ID_MISMATCH",
|
|
18
|
+
COUNTER_NOT_INCREMENTED = "COUNTER_NOT_INCREMENTED",
|
|
19
|
+
SIGNATURE_INVALID = "SIGNATURE_INVALID"
|
|
20
|
+
}
|
|
21
|
+
export declare class AssertionError extends Error {
|
|
22
|
+
readonly code: AssertionErrorCode;
|
|
23
|
+
readonly name = "AssertionError";
|
|
24
|
+
constructor(code: AssertionErrorCode, message: string);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/src/errors.ts"],"names":[],"mappings":"AAEA,oBAAY,oBAAoB;IAC9B,cAAc,mBAAmB;IACjC,yBAAyB,8BAA8B;IACvD,cAAc,mBAAmB;IACjC,cAAc,mBAAmB;IACjC,eAAe,oBAAoB;IACnC,eAAe,oBAAoB;IACnC,cAAc,mBAAmB;CAClC;AAED,qBAAa,gBAAiB,SAAQ,KAAK;aAGvB,IAAI,EAAE,oBAAoB;IAF5C,SAAkB,IAAI,sBAAsB;gBAE1B,IAAI,EAAE,oBAAoB,EAC1C,OAAO,EAAE,MAAM;CAIlB;AAED,oBAAY,kBAAkB;IAC5B,cAAc,mBAAmB;IACjC,cAAc,mBAAmB;IACjC,uBAAuB,4BAA4B;IACnD,iBAAiB,sBAAsB;CACxC;AAED,qBAAa,cAAe,SAAQ,KAAK;aAGrB,IAAI,EAAE,kBAAkB;IAF1C,SAAkB,IAAI,oBAAoB;gBAExB,IAAI,EAAE,kBAAkB,EACxC,OAAO,EAAE,MAAM;CAIlB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
export var AttestationErrorCode;
|
|
3
|
+
(function (AttestationErrorCode) {
|
|
4
|
+
AttestationErrorCode["INVALID_FORMAT"] = "INVALID_FORMAT";
|
|
5
|
+
AttestationErrorCode["INVALID_CERTIFICATE_CHAIN"] = "INVALID_CERTIFICATE_CHAIN";
|
|
6
|
+
AttestationErrorCode["NONCE_MISMATCH"] = "NONCE_MISMATCH";
|
|
7
|
+
AttestationErrorCode["RP_ID_MISMATCH"] = "RP_ID_MISMATCH";
|
|
8
|
+
AttestationErrorCode["KEY_ID_MISMATCH"] = "KEY_ID_MISMATCH";
|
|
9
|
+
AttestationErrorCode["INVALID_COUNTER"] = "INVALID_COUNTER";
|
|
10
|
+
AttestationErrorCode["INVALID_AAGUID"] = "INVALID_AAGUID";
|
|
11
|
+
})(AttestationErrorCode || (AttestationErrorCode = {}));
|
|
12
|
+
export class AttestationError extends Error {
|
|
13
|
+
constructor(code, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
Object.defineProperty(this, "code", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true,
|
|
19
|
+
value: code
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(this, "name", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true,
|
|
25
|
+
value: "AttestationError"
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export var AssertionErrorCode;
|
|
30
|
+
(function (AssertionErrorCode) {
|
|
31
|
+
AssertionErrorCode["INVALID_FORMAT"] = "INVALID_FORMAT";
|
|
32
|
+
AssertionErrorCode["RP_ID_MISMATCH"] = "RP_ID_MISMATCH";
|
|
33
|
+
AssertionErrorCode["COUNTER_NOT_INCREMENTED"] = "COUNTER_NOT_INCREMENTED";
|
|
34
|
+
AssertionErrorCode["SIGNATURE_INVALID"] = "SIGNATURE_INVALID";
|
|
35
|
+
})(AssertionErrorCode || (AssertionErrorCode = {}));
|
|
36
|
+
export class AssertionError extends Error {
|
|
37
|
+
constructor(code, message) {
|
|
38
|
+
super(message);
|
|
39
|
+
Object.defineProperty(this, "code", {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
configurable: true,
|
|
42
|
+
writable: true,
|
|
43
|
+
value: code
|
|
44
|
+
});
|
|
45
|
+
Object.defineProperty(this, "name", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
configurable: true,
|
|
48
|
+
writable: true,
|
|
49
|
+
value: "AssertionError"
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Concatenate multiple Uint8Arrays into one. */
|
|
2
|
+
export declare function concat(...arrays: Uint8Array[]): Uint8Array;
|
|
3
|
+
/** Constant-time comparison of two byte arrays. */
|
|
4
|
+
export declare function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean;
|
|
5
|
+
/** Decode base64 string to bytes, or pass through Uint8Array unchanged. */
|
|
6
|
+
export declare function decodeBase64Bytes(input: Uint8Array | string): Uint8Array;
|
|
7
|
+
/** Convert a UTF-8 string to bytes, or pass through Uint8Array unchanged. */
|
|
8
|
+
export declare function toBytes(input: Uint8Array | string): Uint8Array;
|
|
9
|
+
/** Import a PEM-encoded SPKI public key as a CryptoKey for ECDSA P-256 verification. */
|
|
10
|
+
export declare function importPemPublicKey(pem: string): Promise<CryptoKey>;
|
|
11
|
+
/** Export a CryptoKey to PEM-encoded SPKI format. */
|
|
12
|
+
export declare function exportKeyToPem(key: CryptoKey): Promise<string>;
|
|
13
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/src/utils.ts"],"names":[],"mappings":"AAGA,iDAAiD;AACjD,wBAAgB,MAAM,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,CAU1D;AAED,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAOvE;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,UAAU,CAGxE;AAED,6EAA6E;AAC7E,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,UAAU,CAG9D;AAED,wFAAwF;AACxF,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAaxE;AAED,qDAAqD;AACrD,wBAAsB,cAAc,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAIpE"}
|
package/esm/src/utils.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
import { decodeBase64, encodeBase64 } from "../deps/jsr.io/@std/encoding/1.0.10/base64.js";
|
|
3
|
+
/** Concatenate multiple Uint8Arrays into one. */
|
|
4
|
+
export function concat(...arrays) {
|
|
5
|
+
let totalLength = 0;
|
|
6
|
+
for (const arr of arrays)
|
|
7
|
+
totalLength += arr.length;
|
|
8
|
+
const result = new Uint8Array(totalLength);
|
|
9
|
+
let offset = 0;
|
|
10
|
+
for (const arr of arrays) {
|
|
11
|
+
result.set(arr, offset);
|
|
12
|
+
offset += arr.length;
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
/** Constant-time comparison of two byte arrays. */
|
|
17
|
+
export function constantTimeEqual(a, b) {
|
|
18
|
+
if (a.length !== b.length)
|
|
19
|
+
return false;
|
|
20
|
+
let diff = 0;
|
|
21
|
+
for (let i = 0; i < a.length; i++) {
|
|
22
|
+
diff |= a[i] ^ b[i];
|
|
23
|
+
}
|
|
24
|
+
return diff === 0;
|
|
25
|
+
}
|
|
26
|
+
/** Decode base64 string to bytes, or pass through Uint8Array unchanged. */
|
|
27
|
+
export function decodeBase64Bytes(input) {
|
|
28
|
+
if (input instanceof Uint8Array)
|
|
29
|
+
return input;
|
|
30
|
+
return decodeBase64(input);
|
|
31
|
+
}
|
|
32
|
+
/** Convert a UTF-8 string to bytes, or pass through Uint8Array unchanged. */
|
|
33
|
+
export function toBytes(input) {
|
|
34
|
+
if (input instanceof Uint8Array)
|
|
35
|
+
return input;
|
|
36
|
+
return new TextEncoder().encode(input);
|
|
37
|
+
}
|
|
38
|
+
/** Import a PEM-encoded SPKI public key as a CryptoKey for ECDSA P-256 verification. */
|
|
39
|
+
export async function importPemPublicKey(pem) {
|
|
40
|
+
const base64 = pem
|
|
41
|
+
.replace("-----BEGIN PUBLIC KEY-----", "")
|
|
42
|
+
.replace("-----END PUBLIC KEY-----", "")
|
|
43
|
+
.replace(/\s/g, "");
|
|
44
|
+
const spki = decodeBase64(base64);
|
|
45
|
+
return await crypto.subtle.importKey("spki", spki, { name: "ECDSA", namedCurve: "P-256" }, true, ["verify"]);
|
|
46
|
+
}
|
|
47
|
+
/** Export a CryptoKey to PEM-encoded SPKI format. */
|
|
48
|
+
export async function exportKeyToPem(key) {
|
|
49
|
+
const spki = await crypto.subtle.exportKey("spki", key);
|
|
50
|
+
const base64 = encodeBase64(spki);
|
|
51
|
+
return `-----BEGIN PUBLIC KEY-----\n${base64}\n-----END PUBLIC KEY-----`;
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assertion.test.d.ts","sourceRoot":"","sources":["../../src/tests/assertion.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attestation.test.d.ts","sourceRoot":"","sources":["../../src/tests/attestation.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authdata.test.d.ts","sourceRoot":"","sources":["../../src/tests/authdata.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certificate.test.d.ts","sourceRoot":"","sources":["../../src/tests/certificate.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cose.test.d.ts","sourceRoot":"","sources":["../../src/tests/cose.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"der.test.d.ts","sourceRoot":"","sources":["../../src/tests/der.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.test.d.ts","sourceRoot":"","sources":["../../src/tests/errors.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apple-attestation.d.ts","sourceRoot":"","sources":["../../../src/tests/fixtures/apple-attestation.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,eAAO,MAAM,iBAAiB;;;;IAK5B,oDAAoD;;IAIpD,oDAAoD;;;;;;;;CAQrD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-assertion.d.ts","sourceRoot":"","sources":["../../../src/tests/fixtures/generate-assertion.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,UAAU,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,aAAa,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,wBAAwB,CAAC,CAiDnC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../src/tests/utils.test.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bradford-tech/supabase-integrity-attest",
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Verify Apple App Attest attestations and assertions using WebCrypto.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/bradford-tech/supabase-integrity-attest.git"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/bradford-tech/supabase-integrity-attest/issues"
|
|
12
|
+
},
|
|
13
|
+
"module": "./esm/mod.js",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": "./esm/mod.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"test": "node test_runner.js"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"asn1js": "^3.0.7",
|
|
24
|
+
"cborg": "^4.5.8",
|
|
25
|
+
"pkijs": "^3.3.3"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^20.9.0",
|
|
29
|
+
"picocolors": "^1.0.0",
|
|
30
|
+
"@deno/shim-deno-test": "~0.5.0"
|
|
31
|
+
},
|
|
32
|
+
"_generatedBy": "dnt@dev"
|
|
33
|
+
}
|