@mdbase-dev/connect-protocol 0.1.0-beta.176 → 0.1.0-beta.184
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/dist/application-contract.d.ts +28 -0
- package/dist/application-contract.js +21 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/manifest.js +4 -19
- package/dist/service-urls.d.ts +11 -0
- package/dist/service-urls.js +51 -0
- package/package.json +2 -2
|
@@ -7,6 +7,34 @@ export type MdbaseApplicationManifest = MdbaseAppManifest | LegacyMdbaseAppManif
|
|
|
7
7
|
export type MdbaseApplicationRequirements = ApplicationRequirements | LegacyApplicationRequirements;
|
|
8
8
|
export type MdbaseApplicationCapabilityRequirements = ApplicationCapabilityRequirements | LegacyApplicationCapabilityRequirements;
|
|
9
9
|
export type MdbaseApplicationCapabilityId = ApplicationCapabilityId | LegacyApplicationCapabilityId;
|
|
10
|
+
/**
|
|
11
|
+
* The declaration Connect registers and digests: the bundled manifest with its
|
|
12
|
+
* optional sections defaulted. Clients hash the same value to check that a
|
|
13
|
+
* registration describes the manifest they sent.
|
|
14
|
+
*/
|
|
15
|
+
export declare function normalizeApplicationManifest<T extends MdbaseApplicationManifest>(value: T): T & {
|
|
16
|
+
requirements: {
|
|
17
|
+
access: "full_collection";
|
|
18
|
+
contracts: [];
|
|
19
|
+
capabilities?: ApplicationCapabilityRequirements;
|
|
20
|
+
collection_kind?: "hosted";
|
|
21
|
+
people?: import("./people.js").ApplicationPeopleRequirement;
|
|
22
|
+
files?: import("./files.js").ApplicationFileRequirement;
|
|
23
|
+
configuration: import("./collection-setup.js").ConfigurationRequirement[];
|
|
24
|
+
} | {
|
|
25
|
+
contracts: import("./type-packs.js").ContractRequirement[];
|
|
26
|
+
collection_kind?: "hosted";
|
|
27
|
+
access: "full_collection";
|
|
28
|
+
capabilities?: LegacyApplicationCapabilityRequirements;
|
|
29
|
+
files?: import("./files.js").LegacyApplicationFileRequirement;
|
|
30
|
+
configuration: import("./collection-setup.js").ConfigurationRequirement[];
|
|
31
|
+
};
|
|
32
|
+
provisions: {
|
|
33
|
+
type_packs: import("./type-packs.js").TypePackProvision[];
|
|
34
|
+
configuration: import("./collection-setup.js").ConfigurationProvision[];
|
|
35
|
+
};
|
|
36
|
+
notifications: import("./application-declaration.js").ApplicationNotifications;
|
|
37
|
+
};
|
|
10
38
|
interface MdbaseAuthorizationSelection {
|
|
11
39
|
operations?: CollectionOperation[];
|
|
12
40
|
capabilities?: MdbaseApplicationCapabilityId[];
|
|
@@ -2,6 +2,27 @@ import { APPLICATION_SETUP_OPERATIONS, capabilityOperationsForContractVersion }
|
|
|
2
2
|
import { applicationFileRequest } from "./files.js";
|
|
3
3
|
import { connectError } from "./authorization-errors.js";
|
|
4
4
|
export const DEFAULT_OPERATIONS = ["describe", "changes", "read", "query"];
|
|
5
|
+
/**
|
|
6
|
+
* The declaration Connect registers and digests: the bundled manifest with its
|
|
7
|
+
* optional sections defaulted. Clients hash the same value to check that a
|
|
8
|
+
* registration describes the manifest they sent.
|
|
9
|
+
*/
|
|
10
|
+
export function normalizeApplicationManifest(value) {
|
|
11
|
+
const manifest = structuredClone(value);
|
|
12
|
+
return {
|
|
13
|
+
...manifest,
|
|
14
|
+
requirements: {
|
|
15
|
+
configuration: [],
|
|
16
|
+
...manifest.requirements
|
|
17
|
+
},
|
|
18
|
+
provisions: {
|
|
19
|
+
type_packs: [],
|
|
20
|
+
configuration: [],
|
|
21
|
+
...manifest.provisions
|
|
22
|
+
},
|
|
23
|
+
notifications: manifest.notifications ?? { criteria: [] }
|
|
24
|
+
};
|
|
25
|
+
}
|
|
5
26
|
export function semanticContractVersion(requirements) {
|
|
6
27
|
const version = requirements.capabilities === undefined ? 1 : requirements.capabilities?.contract_version;
|
|
7
28
|
if (version !== 1 && version !== 2)
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { ContractSetupChoice } from "./type-packs.js";
|
|
|
9
9
|
import type { ApplicationAuthorizationProof } from "./application-authorization.js";
|
|
10
10
|
export * from "./connect-problems.generated.js";
|
|
11
11
|
export { MdbaseConnectError, connectError, connectProblem, type ConnectErrorContext } from "./authorization-errors.js";
|
|
12
|
-
export { semanticContractVersion, authorizationOperations, authorizationFiles, validateAuthorizationSelection, declaredOperations, retainedCapabilities, DEFAULT_OPERATIONS, type MdbaseApplicationManifest, type MdbaseApplicationRequirements, type MdbaseApplicationCapabilityRequirements, type MdbaseApplicationCapabilityId } from "./application-contract.js";
|
|
12
|
+
export { semanticContractVersion, authorizationOperations, authorizationFiles, validateAuthorizationSelection, declaredOperations, normalizeApplicationManifest, retainedCapabilities, DEFAULT_OPERATIONS, type MdbaseApplicationManifest, type MdbaseApplicationRequirements, type MdbaseApplicationCapabilityRequirements, type MdbaseApplicationCapabilityId } from "./application-contract.js";
|
|
13
13
|
export * from "./files.js";
|
|
14
14
|
export * from "./operations.js";
|
|
15
15
|
export * from "./change-events.generated.js";
|
|
@@ -19,6 +19,7 @@ export * from "./capabilities.js";
|
|
|
19
19
|
export * from "./application-authorization.js";
|
|
20
20
|
export * from "./type-packs.js";
|
|
21
21
|
export * from "./collection-setup.js";
|
|
22
|
+
export { serviceUrl, validAuthorityTokenResponse } from "./service-urls.js";
|
|
22
23
|
export declare const CONTROL_PROTOCOL_VERSION: 1;
|
|
23
24
|
export { AUTHORIZATION_BINDING_PROTOCOL_VERSION as APPLICATION_AUTHORIZATION_PROTOCOL_VERSION } from "./compatibility.js";
|
|
24
25
|
export declare const LOOPBACK_PROTOCOL_VERSION: 1;
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export * from "./records.js";
|
|
|
3
3
|
import { YAML_DOCUMENT_RECORDS_CAPABILITY } from "./collection-setup.js";
|
|
4
4
|
export * from "./connect-problems.generated.js";
|
|
5
5
|
export { MdbaseConnectError, connectError, connectProblem } from "./authorization-errors.js";
|
|
6
|
-
export { semanticContractVersion, authorizationOperations, authorizationFiles, validateAuthorizationSelection, declaredOperations, retainedCapabilities, DEFAULT_OPERATIONS } from "./application-contract.js";
|
|
6
|
+
export { semanticContractVersion, authorizationOperations, authorizationFiles, validateAuthorizationSelection, declaredOperations, normalizeApplicationManifest, retainedCapabilities, DEFAULT_OPERATIONS } from "./application-contract.js";
|
|
7
7
|
export * from "./files.js";
|
|
8
8
|
export * from "./operations.js";
|
|
9
9
|
export * from "./change-events.generated.js";
|
|
@@ -13,6 +13,7 @@ export * from "./capabilities.js";
|
|
|
13
13
|
export * from "./application-authorization.js";
|
|
14
14
|
export * from "./type-packs.js";
|
|
15
15
|
export * from "./collection-setup.js";
|
|
16
|
+
export { serviceUrl, validAuthorityTokenResponse } from "./service-urls.js";
|
|
16
17
|
export const CONTROL_PROTOCOL_VERSION = 1;
|
|
17
18
|
export { AUTHORIZATION_BINDING_PROTOCOL_VERSION as APPLICATION_AUTHORIZATION_PROTOCOL_VERSION } from "./compatibility.js";
|
|
18
19
|
export const LOOPBACK_PROTOCOL_VERSION = 1;
|
package/dist/manifest.js
CHANGED
|
@@ -2,6 +2,7 @@ import { sha256 as sha256Bytes } from "@noble/hashes/sha2.js";
|
|
|
2
2
|
import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
3
3
|
import { isMap, parseDocument } from "yaml";
|
|
4
4
|
import { appManifestValidator as generatedAppManifestValidator, legacyAppManifestValidator as generatedLegacyAppManifestValidator } from "./manifest-validators.generated.js";
|
|
5
|
+
import { normalizeApplicationManifest } from "./application-contract.js";
|
|
5
6
|
import { RECORD_EXTENSIONS_CONFIGURATION_PATH } from "./collection-setup.js";
|
|
6
7
|
import { isNativeRedirectUri } from "./index.js";
|
|
7
8
|
export const APPLICATION_MANIFEST_MAX_BYTES = 524_288;
|
|
@@ -66,7 +67,7 @@ export function parseAppManifest(value, options = {}) {
|
|
|
66
67
|
const result = validateAppManifest(value, options);
|
|
67
68
|
if (!result.valid)
|
|
68
69
|
throw new AppManifestValidationError(result.issues);
|
|
69
|
-
return
|
|
70
|
+
return normalizeApplicationManifest(value);
|
|
70
71
|
}
|
|
71
72
|
/** Validate and clone without changing capability IDs, file aliases, or version. */
|
|
72
73
|
export function parseVersionedAppManifest(value, options = {}) {
|
|
@@ -74,24 +75,8 @@ export function parseVersionedAppManifest(value, options = {}) {
|
|
|
74
75
|
if (!result.valid)
|
|
75
76
|
throw new AppManifestValidationError(result.issues);
|
|
76
77
|
return declaredContractVersion(value) === 1
|
|
77
|
-
? { contractVersion: 1, manifest:
|
|
78
|
-
: { contractVersion: 2, manifest:
|
|
79
|
-
}
|
|
80
|
-
function normalizeManifest(value) {
|
|
81
|
-
const manifest = structuredClone(value);
|
|
82
|
-
return {
|
|
83
|
-
...manifest,
|
|
84
|
-
requirements: {
|
|
85
|
-
configuration: [],
|
|
86
|
-
...manifest.requirements
|
|
87
|
-
},
|
|
88
|
-
provisions: {
|
|
89
|
-
type_packs: [],
|
|
90
|
-
configuration: [],
|
|
91
|
-
...manifest.provisions
|
|
92
|
-
},
|
|
93
|
-
notifications: manifest.notifications ?? { criteria: [] }
|
|
94
|
-
};
|
|
78
|
+
? { contractVersion: 1, manifest: normalizeApplicationManifest(value) }
|
|
79
|
+
: { contractVersion: 2, manifest: normalizeApplicationManifest(value) };
|
|
95
80
|
}
|
|
96
81
|
export function formatManifestValidationIssues(issues) {
|
|
97
82
|
return issues.map((issue) => `${issue.path || "/"} ${issue.message}`).join("; ");
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A URL a client may send credentials or collection data to: HTTPS, or HTTP
|
|
3
|
+
* on a loopback host for development, with no embedded credentials.
|
|
4
|
+
*/
|
|
5
|
+
export declare function serviceUrl(value: unknown): URL | null;
|
|
6
|
+
/**
|
|
7
|
+
* A token response's remote authority capability, bound to its collection:
|
|
8
|
+
* operation, sync and file endpoints on one service origin, each at the exact
|
|
9
|
+
* `/v1/authorities/<collection>/<endpoint>` path with no query or fragment.
|
|
10
|
+
*/
|
|
11
|
+
export declare function validAuthorityTokenResponse(value: unknown, collectionId: unknown): boolean;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
2
|
+
const AUTHORITY_PATH = /^\/v1\/authorities\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\/(operations|sync|files)$/i;
|
|
3
|
+
/**
|
|
4
|
+
* A URL a client may send credentials or collection data to: HTTPS, or HTTP
|
|
5
|
+
* on a loopback host for development, with no embedded credentials.
|
|
6
|
+
*/
|
|
7
|
+
export function serviceUrl(value) {
|
|
8
|
+
if (typeof value !== "string")
|
|
9
|
+
return null;
|
|
10
|
+
let url;
|
|
11
|
+
try {
|
|
12
|
+
url = new URL(value);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const transport = url.protocol === "https:"
|
|
18
|
+
|| (url.protocol === "http:" && LOOPBACK_HOSTS.has(url.hostname));
|
|
19
|
+
return transport && !url.username && !url.password ? url : null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A token response's remote authority capability, bound to its collection:
|
|
23
|
+
* operation, sync and file endpoints on one service origin, each at the exact
|
|
24
|
+
* `/v1/authorities/<collection>/<endpoint>` path with no query or fragment.
|
|
25
|
+
*/
|
|
26
|
+
export function validAuthorityTokenResponse(value, collectionId) {
|
|
27
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
28
|
+
return false;
|
|
29
|
+
if (typeof collectionId !== "string")
|
|
30
|
+
return false;
|
|
31
|
+
const authority = value;
|
|
32
|
+
if (typeof authority.replica_id !== "string"
|
|
33
|
+
|| authority.replica_id.length === 0
|
|
34
|
+
|| typeof authority.access_token !== "string"
|
|
35
|
+
|| authority.access_token.length === 0
|
|
36
|
+
|| (authority.proof_public_key !== undefined
|
|
37
|
+
&& (typeof authority.proof_public_key !== "string"
|
|
38
|
+
|| authority.proof_public_key.length === 0)))
|
|
39
|
+
return false;
|
|
40
|
+
const endpoints = [
|
|
41
|
+
[authority.operations_url, "operations"],
|
|
42
|
+
[authority.sync_url, "sync"],
|
|
43
|
+
[authority.files_url, "files"]
|
|
44
|
+
];
|
|
45
|
+
const urls = endpoints.map(([value, endpoint]) => {
|
|
46
|
+
const url = serviceUrl(value);
|
|
47
|
+
const path = url && !url.search && !url.hash ? AUTHORITY_PATH.exec(url.pathname) : null;
|
|
48
|
+
return path?.[1] === collectionId && path[2] === endpoint ? url : null;
|
|
49
|
+
});
|
|
50
|
+
return urls.every((url) => url !== null && url.origin === urls[0].origin);
|
|
51
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mdbase-dev/connect-protocol",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.184",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,6 +47,6 @@
|
|
|
47
47
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
48
48
|
},
|
|
49
49
|
"mdbaseRelease": {
|
|
50
|
-
"commit": "
|
|
50
|
+
"commit": "69e517c21af2e9d3b723ff01fcd812e0a6d33db2"
|
|
51
51
|
}
|
|
52
52
|
}
|