immich-api 0.2.0__py3-none-any.whl
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.
- immich_api/__init__.py +54 -0
- immich_api/__main__.py +4 -0
- immich_api/album_metadata.py +119 -0
- immich_api/api/__init__.py +3 -0
- immich_api/api/api_client_system.py +7 -0
- immich_api/auth.py +94 -0
- immich_api/connector_manifest.yml +212 -0
- immich_api/connectors/__init__.py +0 -0
- immich_api/connectors/mcp_source_presets.json +3 -0
- immich_api/connectors/tool_schema_fingerprints.json +1 -0
- immich_api/error_authority.py +248 -0
- immich_api/error_rendering.py +105 -0
- immich_api/immich_input_models.py +12 -0
- immich_api/immich_response_models.py +15 -0
- immich_api/kg_ingest.py +75 -0
- immich_api/mcp/__init__.py +21 -0
- immich_api/mcp/album_sample.py +38 -0
- immich_api/mcp_config.json +3 -0
- immich_api/mcp_server.py +50 -0
- immich_api/ontology/__init__.py +6 -0
- immich_api/ontology/immich.ttl +119 -0
- immich_api/ontology/schema-provenance.json +483 -0
- immich_api/ontology/shapes/immich.ttl +69 -0
- immich_api/openapi_auth_scheme.py +77 -0
- immich_api/openapi_contract.json +80122 -0
- immich_api/openapi_execution.py +30 -0
- immich_api/openapi_inventory.json +16154 -0
- immich_api/openapi_request.py +119 -0
- immich_api/openapi_response.py +76 -0
- immich_api/openapi_runtime.py +203 -0
- immich_api/parity/__init__.py +17 -0
- immich_api/parity/check_openapi_parity.py +173 -0
- immich_api/parity/openapi_discovery.py +95 -0
- immich_api/parity/openapi_parity.py +239 -0
- immich_api/parity/openapi_provider_evidence.py +143 -0
- immich_api/parity/openapi_provider_overlay.py +239 -0
- immich_api/parity/openapi_provider_responses.py +132 -0
- immich_api/parity/openapi_schema.py +206 -0
- immich_api/parity/openapi_schema_budget.py +104 -0
- immich_api/parity/openapi_schema_inputs.py +89 -0
- immich_api/parity/openapi_schema_types.py +163 -0
- immich_api/parity/openapi_security.py +157 -0
- immich_api/parity/openapi_source_parity.py +98 -0
- immich_api/parity/openapi_transport_parity.py +169 -0
- immich_api/parity/unicode_patterns.py +105 -0
- immich_api/parity/unicode_properties.json +4719 -0
- immich_api/prompts/__init__.py +0 -0
- immich_api/prompts/immich_album_review.json +18 -0
- immich_api/prompts/immich_asset_metadata.json +18 -0
- immich_api/prompts/immich_person_record.json +18 -0
- immich_api/prompts/immich_specialist.json +17 -0
- immich_api/prompts/main_agent.json +24 -0
- immich_api/skills/__init__.py +0 -0
- immich_api/skills/immich-album-review/SKILL.md +17 -0
- immich_api/skills/immich-asset-metadata/SKILL.md +17 -0
- immich_api/skills/immich-health/SKILL.md +17 -0
- immich_api/skills/immich-person-record/SKILL.md +17 -0
- immich_api-0.2.0.dist-info/METADATA +242 -0
- immich_api-0.2.0.dist-info/RECORD +63 -0
- immich_api-0.2.0.dist-info/WHEEL +5 -0
- immich_api-0.2.0.dist-info/entry_points.txt +14 -0
- immich_api-0.2.0.dist-info/licenses/LICENSE +21 -0
- immich_api-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
@prefix : <http://knuckles.team/kg#> .
|
|
2
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
3
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
4
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
5
|
+
@prefix sh: <http://www.w3.org/ns/shacl#> .
|
|
6
|
+
@prefix prov: <http://www.w3.org/ns/prov#> .
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
:ImmichAssetShape a sh:NodeShape ; sh:targetClass :ImmichAsset ;
|
|
10
|
+
sh:property [ sh:path :immichAssetId ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ; sh:pattern "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$" ],
|
|
11
|
+
[ sh:path :immichAssetType ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ; sh:in ("IMAGE" "VIDEO" "AUDIO" "OTHER") ],
|
|
12
|
+
[ sh:path :immichAssetOriginalMimeType ; sh:maxCount 1 ; sh:datatype xsd:string ],
|
|
13
|
+
[ sh:path :immichAssetDuration ; sh:maxCount 1 ; sh:datatype xsd:integer ; sh:minInclusive 0 ; sh:maxInclusive 2147483647 ],
|
|
14
|
+
[ sh:path :immichAssetWidth ; sh:maxCount 1 ; sh:datatype xsd:integer ; sh:minInclusive 0 ; sh:maxInclusive 9007199254740991 ],
|
|
15
|
+
[ sh:path :immichAssetHeight ; sh:maxCount 1 ; sh:datatype xsd:integer ; sh:minInclusive 0 ; sh:maxInclusive 9007199254740991 ],
|
|
16
|
+
[ sh:path :immichAssetFileCreatedAt ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:dateTime ],
|
|
17
|
+
[ sh:path :immichAssetUpdatedAt ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:dateTime ],
|
|
18
|
+
[ sh:path :immichAssetIsFavorite ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:boolean ],
|
|
19
|
+
[ sh:path :immichAssetIsArchived ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:boolean ],
|
|
20
|
+
[ sh:path :immichAssetIsTrashed ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:boolean ],
|
|
21
|
+
[ sh:path :immichAssetVisibility ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ; sh:in ("archive" "timeline" "hidden" "locked") ],
|
|
22
|
+
[ sh:path :immichAssetOwner ; sh:maxCount 1 ; sh:class :ImmichUser ],
|
|
23
|
+
[ sh:path :immichAssetPeople ; sh:class :ImmichPersonRecord ],
|
|
24
|
+
[ sh:path :immichAssetTags ; sh:class :ImmichTag ],
|
|
25
|
+
[ sh:path :immichAssetStack ; sh:maxCount 1 ; sh:class :ImmichAssetStack ] .
|
|
26
|
+
|
|
27
|
+
:ImmichAlbumShape a sh:NodeShape ; sh:targetClass :ImmichAlbum ;
|
|
28
|
+
sh:property [ sh:path :immichAlbumId ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ; sh:pattern "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$" ],
|
|
29
|
+
[ sh:path :immichAlbumAlbumName ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ],
|
|
30
|
+
[ sh:path :immichAlbumAssetCount ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:integer ; sh:minInclusive 0 ; sh:maxInclusive 9007199254740991 ],
|
|
31
|
+
[ sh:path :immichAlbumShared ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:boolean ],
|
|
32
|
+
[ sh:path :immichAlbumHasSharedLink ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:boolean ],
|
|
33
|
+
[ sh:path :immichAlbumCreatedAt ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:dateTime ],
|
|
34
|
+
[ sh:path :immichAlbumUpdatedAt ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:dateTime ],
|
|
35
|
+
[ sh:path :immichAlbumAlbumUsers ; sh:class :ImmichAlbumMembership ],
|
|
36
|
+
[ sh:path :immichAlbumAlbumThumbnailAssetId ; sh:maxCount 1 ; sh:datatype xsd:string ; sh:pattern "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$" ] .
|
|
37
|
+
|
|
38
|
+
:ImmichPersonRecordShape a sh:NodeShape ; sh:targetClass :ImmichPersonRecord ;
|
|
39
|
+
sh:property [ sh:path :immichPersonRecordId ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ; sh:pattern "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$" ],
|
|
40
|
+
[ sh:path :immichPersonRecordName ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ],
|
|
41
|
+
[ sh:path :immichPersonRecordIsHidden ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:boolean ],
|
|
42
|
+
[ sh:path :immichPersonRecordIsFavorite ; sh:maxCount 1 ; sh:datatype xsd:boolean ],
|
|
43
|
+
[ sh:path :immichPersonRecordUpdatedAt ; sh:maxCount 1 ; sh:datatype xsd:dateTime ] .
|
|
44
|
+
|
|
45
|
+
:ImmichUserShape a sh:NodeShape ; sh:targetClass :ImmichUser ;
|
|
46
|
+
sh:property [ sh:path :immichUserId ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ; sh:pattern "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$" ],
|
|
47
|
+
[ sh:path :immichUserName ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ] .
|
|
48
|
+
|
|
49
|
+
:ImmichLibraryShape a sh:NodeShape ; sh:targetClass :ImmichLibrary ;
|
|
50
|
+
sh:property [ sh:path :immichLibraryId ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ; sh:pattern "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$" ],
|
|
51
|
+
[ sh:path :immichLibraryName ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ],
|
|
52
|
+
[ sh:path :immichLibraryAssetCount ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:integer ; sh:minInclusive -9007199254740991 ; sh:maxInclusive 9007199254740991 ],
|
|
53
|
+
[ sh:path :immichLibraryCreatedAt ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:dateTime ],
|
|
54
|
+
[ sh:path :immichLibraryUpdatedAt ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:dateTime ] .
|
|
55
|
+
|
|
56
|
+
:ImmichAlbumMembershipShape a sh:NodeShape ; sh:targetClass :ImmichAlbumMembership ;
|
|
57
|
+
sh:property [ sh:path :immichAlbumMembershipRole ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ; sh:in ("editor" "owner" "viewer") ],
|
|
58
|
+
[ sh:path :immichAlbumMembershipUser ; sh:maxCount 1 ; sh:class :ImmichUser ] .
|
|
59
|
+
|
|
60
|
+
:ImmichTagShape a sh:NodeShape ; sh:targetClass :ImmichTag ;
|
|
61
|
+
sh:property [ sh:path :immichTagId ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ; sh:pattern "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$" ],
|
|
62
|
+
[ sh:path :immichTagName ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ],
|
|
63
|
+
[ sh:path :immichTagCreatedAt ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:dateTime ],
|
|
64
|
+
[ sh:path :immichTagUpdatedAt ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:dateTime ] .
|
|
65
|
+
|
|
66
|
+
:ImmichAssetStackShape a sh:NodeShape ; sh:targetClass :ImmichAssetStack ;
|
|
67
|
+
sh:property [ sh:path :immichAssetStackId ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ; sh:pattern "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$" ],
|
|
68
|
+
[ sh:path :immichAssetStackAssetCount ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:integer ; sh:minInclusive 0 ; sh:maxInclusive 9007199254740991 ],
|
|
69
|
+
[ sh:path :immichAssetStackPrimaryAssetId ; sh:maxCount 1 ; sh:minCount 1 ; sh:datatype xsd:string ; sh:pattern "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$" ] .
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Typed, declared provider authentication backed by SDK credential references."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from enum import StrEnum
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AuthKind(StrEnum):
|
|
13
|
+
"""Supported wire representations; neither implies provider permissions."""
|
|
14
|
+
|
|
15
|
+
BEARER = "bearer"
|
|
16
|
+
HEADER = "header"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class ProviderAuthScheme:
|
|
21
|
+
"""One named OpenAPI scheme, never a credential value or a default header."""
|
|
22
|
+
|
|
23
|
+
name: str
|
|
24
|
+
kind: AuthKind
|
|
25
|
+
header: str = ""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def declared_scheme(
|
|
29
|
+
name: str, definitions: Mapping[str, Any]
|
|
30
|
+
) -> ProviderAuthScheme | None:
|
|
31
|
+
"""Fail closed for an explicit unknown or unsupported scheme."""
|
|
32
|
+
if not name:
|
|
33
|
+
return None
|
|
34
|
+
if name not in definitions:
|
|
35
|
+
raise ValueError("Selected authentication scheme is not declared")
|
|
36
|
+
definition = definitions[name]
|
|
37
|
+
if not isinstance(definition, Mapping):
|
|
38
|
+
raise TypeError("Authentication scheme must be an OpenAPI object")
|
|
39
|
+
wire_scheme = definition.get("scheme", "")
|
|
40
|
+
if (
|
|
41
|
+
definition.get("type") == "http"
|
|
42
|
+
and isinstance(wire_scheme, str)
|
|
43
|
+
and wire_scheme.casefold() == "bearer"
|
|
44
|
+
):
|
|
45
|
+
return ProviderAuthScheme(name, AuthKind.BEARER)
|
|
46
|
+
return ProviderAuthScheme(name, AuthKind.HEADER, _credential_header(definition))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _credential_header(definition: Mapping[str, Any]) -> str:
|
|
50
|
+
"""Validate a header credential independently of bearer selection."""
|
|
51
|
+
if definition.get("type") != "apiKey" or definition.get("in") != "header":
|
|
52
|
+
raise ValueError("Unsupported provider authentication scheme")
|
|
53
|
+
header = definition.get("name")
|
|
54
|
+
if not isinstance(header, str) or not re.fullmatch(
|
|
55
|
+
r"[!#$%&'*+.^_`|~0-9A-Za-z-]+", header
|
|
56
|
+
):
|
|
57
|
+
raise ValueError("Invalid credential header name")
|
|
58
|
+
if header.casefold() in {
|
|
59
|
+
"host",
|
|
60
|
+
"connection",
|
|
61
|
+
"content-length",
|
|
62
|
+
"transfer-encoding",
|
|
63
|
+
"proxy-authorization",
|
|
64
|
+
"proxy-authenticate",
|
|
65
|
+
"cookie",
|
|
66
|
+
}:
|
|
67
|
+
raise ValueError("Credential header conflicts with HTTP transport")
|
|
68
|
+
return header
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def credential_headers(definitions: Mapping[str, Any]) -> set[str]:
|
|
72
|
+
"""Reserve every declared credential header, including on public operations."""
|
|
73
|
+
return {"authorization", "cookie", "host", "x-api-key"} | {
|
|
74
|
+
str(scheme.get("name", "")).casefold()
|
|
75
|
+
for scheme in definitions.values()
|
|
76
|
+
if scheme.get("type") == "apiKey" and scheme.get("in") == "header"
|
|
77
|
+
}
|