a shared link is a URL, not a key
Create, edit and revoke shared links from the album header, the selection bar and the Sharing panel. Password, expiry, and the three flags that decide what the person opening it can do. The panel showed a bare key because this plugin never learned the instance's public address. It does not need to store one: Immich has `externalDomain` in its own admin settings, `/server/config` already returns it, and it is the same field Immich's own copy-link button reads, so the two cannot disagree. Empty is a real state and the UI says so rather than inventing a host. Payload shapes came from the live instance's spec.json, not from memory. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+68
-2
@@ -128,17 +128,74 @@ export type SearchResponse = {
|
||||
export type ExploreItem = { value: string; data: Asset };
|
||||
export type ExploreSection = { fieldName: string; items: ExploreItem[] };
|
||||
|
||||
export type SharedLinkType = 'ALBUM' | 'INDIVIDUAL';
|
||||
|
||||
/**
|
||||
* `GET /shared-links` — Immich's `SharedLinkResponseDto`.
|
||||
*
|
||||
* `password` really is returned in the clear. That is Immich's choice, not ours, and the edit form uses it:
|
||||
* showing the owner the password they set beats making them reset it blind to find out what it was.
|
||||
*/
|
||||
export type SharedLink = {
|
||||
id: string;
|
||||
key: string;
|
||||
type: string;
|
||||
type: SharedLinkType;
|
||||
album?: Album | null;
|
||||
assets: Asset[];
|
||||
description?: string | null;
|
||||
password: string | null;
|
||||
slug: string | null;
|
||||
expiresAt: string | null;
|
||||
createdAt: string;
|
||||
allowDownload: boolean;
|
||||
allowUpload: boolean;
|
||||
showMetadata: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* `POST /shared-links`. `type` decides which of the next two fields is read: `ALBUM` takes `albumId`,
|
||||
* `INDIVIDUAL` takes `assetIds`.
|
||||
*/
|
||||
export type SharedLinkCreate = {
|
||||
type: SharedLinkType;
|
||||
albumId?: string;
|
||||
assetIds?: string[];
|
||||
description?: string | null;
|
||||
password?: string | null;
|
||||
expiresAt?: string | null;
|
||||
allowUpload?: boolean;
|
||||
allowDownload?: boolean;
|
||||
showMetadata?: boolean;
|
||||
};
|
||||
|
||||
/** `PATCH /shared-links/{id}`. Every field optional; omitting one leaves it as it was. */
|
||||
export type SharedLinkEdit = {
|
||||
description?: string | null;
|
||||
password?: string | null;
|
||||
expiresAt?: string | null;
|
||||
allowUpload?: boolean;
|
||||
allowDownload?: boolean;
|
||||
showMetadata?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* The URL to hand somebody, or null when Immich does not know its own public address.
|
||||
*
|
||||
* The host is Immich's `externalDomain`, not Officer's. A shared link is opened by someone with no Officer
|
||||
* account, so it has to resolve to the instance itself — and reading it from `/server/config` means Officer
|
||||
* stores no second copy that could disagree with the one Immich's own copy-link button uses.
|
||||
*
|
||||
* Empty is a real state: nobody has set it in Immich's admin settings yet, and the UI says exactly that
|
||||
* instead of inventing a hostname. `/s/<slug>` when a slug is set, `/share/<key>` otherwise — both are real
|
||||
* routes on the instance, verified against 3.1.0.
|
||||
*/
|
||||
export const shareUrl = (
|
||||
externalDomain: string | undefined,
|
||||
link: Pick<SharedLink, 'key' | 'slug'>,
|
||||
): string | null => {
|
||||
const base = externalDomain?.trim().replace(/\/+$/, '');
|
||||
if (!base) return null;
|
||||
return link.slug ? `${base}/s/${link.slug}` : `${base}/share/${link.key}`;
|
||||
};
|
||||
|
||||
export type TimeBucket = { timeBucket: string; count: number };
|
||||
@@ -153,7 +210,16 @@ export type MapMarker = { id: string; lat: number; lon: number; city: string | n
|
||||
* Immich's web app gets it, and the only part of /photos that talks to anything other than Officer. It is not
|
||||
* proxied because a vector basemap is thousands of tile requests that have nothing to do with the library.
|
||||
*/
|
||||
export type ServerConfig = { mapDarkStyleUrl: string; mapLightStyleUrl: string; version?: string };
|
||||
export type ServerConfig = {
|
||||
mapDarkStyleUrl: string;
|
||||
mapLightStyleUrl: string;
|
||||
version?: string;
|
||||
/**
|
||||
* Immich's own public address, from its admin settings — the one thing standing between a shared link and
|
||||
* a URL somebody can open. See `shareUrl`.
|
||||
*/
|
||||
externalDomain?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* `GET /timeline/bucket` is COLUMNAR — parallel arrays, not a list of objects. Immich went this way in 1.133
|
||||
|
||||
Reference in New Issue
Block a user