@teamscala/service-boot 0.23.363 → 0.23.364
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/package.json
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
* Authenticated asset upload — POST /api/transfers/upload. Restores the
|
|
7
7
|
* handler deleted with @teamscala/server-files (commit ca5643ef); avatar/logo
|
|
8
8
|
* upload had 404'd on every service since. Writes to S3 via
|
|
9
|
-
* @teamscala/object-storage/create/write-ops and returns the
|
|
10
|
-
* (`/api/
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* @teamscala/object-storage/create/write-ops and returns the SERVABLE URL
|
|
10
|
+
* (`/api/assets/<key>`) the client persists into avatar_url/logo_url — the
|
|
11
|
+
* stored value is the servable value (single-logo-pathway), so display code
|
|
12
|
+
* reads the column with no rewriting. Self-authenticates (getSession) so it
|
|
13
|
+
* mounts BEFORE the auth gate.
|
|
14
14
|
*
|
|
15
15
|
* Key scheme is USER-scoped (`users/<userId>/<type>/<file>-<ts>.<ext>`) per
|
|
16
16
|
* the operator ruling: a profile picture belongs to the individual, not any
|
|
@@ -104,7 +104,7 @@ export async function attachTransfersUpload(app: Hono): Promise<void> {
|
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
const storedUrl = `/api/
|
|
107
|
+
const storedUrl = `/api/assets/${key}`;
|
|
108
108
|
return c.json({ url: storedUrl, thumbUrl: storedUrl });
|
|
109
109
|
});
|
|
110
110
|
}
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Stamp partner and client brand assets onto a proposal page's pageData, after
|
|
7
7
|
* it is built.
|
|
8
|
-
*
|
|
9
8
|
* Split from proposal-post-processors.ts (single-purpose-file: two unrelated
|
|
10
9
|
* export groups). Both helpers here are synchronous, take an already-resolved
|
|
11
10
|
* loader-graph org, and only map a logo/colour onto pageData — no network, no
|
|
@@ -13,7 +12,6 @@
|
|
|
13
12
|
* async ORPC lookup, which is the distinction that was invisible while they sat
|
|
14
13
|
* together.
|
|
15
14
|
*/
|
|
16
|
-
import { toAssetPath } from "@teamscala/formatters/asset-url";
|
|
17
15
|
|
|
18
16
|
/**
|
|
19
17
|
* Stash a proposal's connected partner logo/colour on `pageData` from the
|
|
@@ -37,7 +35,7 @@ export function applyPartnerBrand(
|
|
|
37
35
|
| null,
|
|
38
36
|
): void {
|
|
39
37
|
if (!partnerOrg) return;
|
|
40
|
-
if (partnerOrg.logo_url) pageData.partnerLogo =
|
|
38
|
+
if (partnerOrg.logo_url) pageData.partnerLogo = partnerOrg.logo_url;
|
|
41
39
|
if (partnerOrg.brand_primary_color)
|
|
42
40
|
pageData.partnerBrandColor = partnerOrg.brand_primary_color;
|
|
43
41
|
}
|
|
@@ -56,5 +54,5 @@ export function applyClientLogo(
|
|
|
56
54
|
| null,
|
|
57
55
|
): void {
|
|
58
56
|
if (!clientOrg?.logo_url) return;
|
|
59
|
-
pageData.clientLogo =
|
|
57
|
+
pageData.clientLogo = clientOrg.logo_url;
|
|
60
58
|
}
|
|
@@ -38,7 +38,7 @@ describe("buildResourceNotFoundResponse", () => {
|
|
|
38
38
|
const bytes = new Uint8Array([137, 80, 78, 71]);
|
|
39
39
|
const requested: string[] = [];
|
|
40
40
|
const logo = await inlineLogoAsDataUri(
|
|
41
|
-
"/api/
|
|
41
|
+
"/api/assets/c503629a/logos/cropped.png",
|
|
42
42
|
async () => ({
|
|
43
43
|
file(key) {
|
|
44
44
|
requested.push(key);
|
|
@@ -55,7 +55,7 @@ describe("buildResourceNotFoundResponse", () => {
|
|
|
55
55
|
|
|
56
56
|
it("passes the resolved logo to the waking page instead of its placeholder", async () => {
|
|
57
57
|
const logo = await inlineLogoAsDataUri(
|
|
58
|
-
"/api/
|
|
58
|
+
"/api/assets/c503629a/logos/cropped.png",
|
|
59
59
|
async () => ({
|
|
60
60
|
file() {
|
|
61
61
|
return {
|
|
@@ -33,7 +33,6 @@ import { createCache } from "@teamscala/cache/create-cache";
|
|
|
33
33
|
import { createNotifyListener, getDirectDatabaseUrl } from "@teamscala/db/notify-listener/index";
|
|
34
34
|
import { getServerClient } from "@teamscala/orpc/server-client-registry";
|
|
35
35
|
import { loadRegistryConfig } from "@teamscala/db/registry/load-config";
|
|
36
|
-
import { toAssetPath } from "@teamscala/formatters/asset-url";
|
|
37
36
|
import { getAppLogger } from "@teamscala/logger/app-loggers";
|
|
38
37
|
import { brandLogoImgTag } from "@teamscala/os/brand/brand-logo-img-tag";
|
|
39
38
|
import { ServiceInstallConfigSchema } from "./load-service-install-row.ts";
|
|
@@ -134,10 +133,10 @@ const ASSETS_PREFIX = "/api/assets/";
|
|
|
134
133
|
|
|
135
134
|
/**
|
|
136
135
|
* Inline a stored logo value as a `data:<mime>;base64,…` URI by fetching its
|
|
137
|
-
* bytes from S3 (the same store `/api/assets/` proxies to).
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
136
|
+
* bytes from S3 (the same store `/api/assets/` proxies to). The stored value
|
|
137
|
+
* IS the servable form — `/api/assets/<key>` — so the bucket key is the path
|
|
138
|
+
* segment after that prefix (single-logo-pathway). Skew-tolerant: any miss →
|
|
139
|
+
* null.
|
|
141
140
|
*/
|
|
142
141
|
type LogoStorage = {
|
|
143
142
|
file(key: string): {
|
|
@@ -151,9 +150,8 @@ export async function inlineLogoAsDataUri(
|
|
|
151
150
|
getStorage: () => Promise<LogoStorage | null> = getClient as unknown as () => Promise<LogoStorage | null>,
|
|
152
151
|
): Promise<string | null> {
|
|
153
152
|
try {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const key = decodeURIComponent(assetPath.slice(ASSETS_PREFIX.length));
|
|
153
|
+
if (!stored.startsWith(ASSETS_PREFIX)) return null;
|
|
154
|
+
const key = decodeURIComponent(stored.slice(ASSETS_PREFIX.length));
|
|
157
155
|
const s3 = await getStorage();
|
|
158
156
|
if (!s3) return null;
|
|
159
157
|
const file = s3.file(key);
|