target-supabase-sdk 0.2.21 → 0.2.22
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/browser.js +1 -1
- package/dist/chunks/{task-queue-FygwujNS.js → task-queue-DWFe0rCS.js} +8 -4
- package/dist/chunks/task-queue-DWFe0rCS.js.map +1 -0
- package/dist/node.d.ts +2 -2
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +174 -19
- package/dist/node.js.map +1 -1
- package/dist/shared/feed/feed.build.d.ts +4 -2
- package/dist/shared/feed/feed.build.d.ts.map +1 -1
- package/dist/shared/feed/node/feed.access.d.ts +10 -2
- package/dist/shared/feed/node/feed.access.d.ts.map +1 -1
- package/dist/shared/feed/node/feed.service.d.ts +26 -1
- package/dist/shared/feed/node/feed.service.d.ts.map +1 -1
- package/dist/shared/feed/node/index.d.ts +3 -3
- package/dist/shared/feed/node/index.d.ts.map +1 -1
- package/dist/shared/http/fetch-retry.d.ts +2 -0
- package/dist/shared/http/fetch-retry.d.ts.map +1 -1
- package/dist/shared/media/node/media.service.d.ts +8 -2
- package/dist/shared/media/node/media.service.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/node.ts +4 -0
- package/src/shared/feed/README.md +4 -3
- package/src/shared/feed/feed.build.ts +6 -3
- package/src/shared/feed/node/feed.access.ts +33 -6
- package/src/shared/feed/node/feed.service.ts +131 -4
- package/src/shared/feed/node/index.ts +7 -3
- package/src/shared/http/fetch-retry.ts +13 -2
- package/src/shared/media/README.md +4 -4
- package/src/shared/media/node/media.service.ts +77 -10
- package/dist/chunks/task-queue-FygwujNS.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { getPossibleTarget, isCreateTargetAlreadyExistsError, postTarget } from "../../../core.api";
|
|
2
|
-
import type
|
|
1
|
+
import { getPossibleTarget, isCreateTargetAlreadyExistsError, postTarget, updateTarget } from "../../../core.api";
|
|
2
|
+
import { CategoryLink, type Link, type LinkDetails } from "../../../link/link.interface";
|
|
3
3
|
import { createLogger } from "../../log/core/create-logger";
|
|
4
|
+
import { isHttpUrl } from "../../utils/fetch-url";
|
|
4
5
|
import { buildMediaLinkDraft } from "../media.build";
|
|
5
6
|
import { isMediaValue, type MediaValue } from "../media.interface";
|
|
6
7
|
import { mediaLinkDedupFilters } from "../media.query";
|
|
@@ -35,6 +36,11 @@ export interface RegisterMediaLinkInput {
|
|
|
35
36
|
locator: string;
|
|
36
37
|
/** This host id for availability (e.g. `process.env.LOCAL_STORAGE_PROVIDER`). */
|
|
37
38
|
localStorageProvider: string;
|
|
39
|
+
/**
|
|
40
|
+
* Local file to probe when `locator` is http(s) (OSS ingest).
|
|
41
|
+
* Availability uses this path + `localStorageProvider`.
|
|
42
|
+
*/
|
|
43
|
+
localLocator?: string;
|
|
38
44
|
description?: string;
|
|
39
45
|
tagList?: string[];
|
|
40
46
|
}
|
|
@@ -44,9 +50,53 @@ export interface RegisterMediaLinkResult {
|
|
|
44
50
|
created: boolean;
|
|
45
51
|
}
|
|
46
52
|
|
|
53
|
+
function mediaOriginalFromRow(row: { details?: unknown }): { storageProvider?: string; locator?: string } {
|
|
54
|
+
const details = row.details as LinkDetails | undefined;
|
|
55
|
+
const original = details?.original as { storageProvider?: string; locator?: string } | undefined;
|
|
56
|
+
return original ?? {};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function patchMediaOriginal(
|
|
60
|
+
existing: Link,
|
|
61
|
+
storageProvider: string,
|
|
62
|
+
locator: string,
|
|
63
|
+
): Promise<RegisterMediaLinkResult> {
|
|
64
|
+
const original = mediaOriginalFromRow(existing);
|
|
65
|
+
if (original.storageProvider === storageProvider && original.locator === locator) {
|
|
66
|
+
return { id: existing.id, created: false };
|
|
67
|
+
}
|
|
68
|
+
await updateTarget({
|
|
69
|
+
id: existing.id,
|
|
70
|
+
optimisticLockFilterList: [
|
|
71
|
+
{ field: "category", operator: "eq", value: CategoryLink.LINK },
|
|
72
|
+
{ field: "value", operator: "eq", value: existing.value },
|
|
73
|
+
],
|
|
74
|
+
updateFn: (row) => {
|
|
75
|
+
const details = row.details as LinkDetails;
|
|
76
|
+
const prev = (details.original ?? {}) as Record<string, unknown>;
|
|
77
|
+
return {
|
|
78
|
+
details: {
|
|
79
|
+
...details,
|
|
80
|
+
original: {
|
|
81
|
+
...prev,
|
|
82
|
+
storageProvider,
|
|
83
|
+
locator,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
logger.info("media original patched", {
|
|
90
|
+
topic: "register",
|
|
91
|
+
data: { id: existing.id, locator },
|
|
92
|
+
});
|
|
93
|
+
return { id: existing.id, created: false };
|
|
94
|
+
}
|
|
95
|
+
|
|
47
96
|
/**
|
|
48
97
|
* Register a media Link: dedup → availability → probe → `postTarget`.
|
|
49
|
-
* Idempotent when `category`+`value`+`name` already exist.
|
|
98
|
+
* Idempotent when `category`+`value`+`name` already exist (local path).
|
|
99
|
+
* HTTP `locator` + `localLocator`: probe local file, persist remote URL; patch if name exists.
|
|
50
100
|
*
|
|
51
101
|
* **Node-only** — under `shared/media/node/`; do not import from the browser entry.
|
|
52
102
|
*/
|
|
@@ -59,19 +109,33 @@ export async function registerMediaLink(input: RegisterMediaLinkInput): Promise<
|
|
|
59
109
|
throw new Error("registerMediaLink: name is empty");
|
|
60
110
|
}
|
|
61
111
|
|
|
112
|
+
const storageProvider = input.storageProvider.trim();
|
|
113
|
+
const locator = input.locator.trim();
|
|
114
|
+
const localLocator = input.localLocator?.trim() ?? "";
|
|
115
|
+
const httpLocator = isHttpUrl(locator);
|
|
116
|
+
|
|
62
117
|
const existing = await findMediaLink({ value: input.value, name });
|
|
63
|
-
if (existing != null) {
|
|
118
|
+
if (existing != null && !httpLocator) {
|
|
64
119
|
logger.info("media already registered", {
|
|
65
120
|
topic: "dedup",
|
|
66
121
|
data: { id: existing.id, value: input.value, name },
|
|
67
122
|
});
|
|
68
123
|
return { id: existing.id, created: false };
|
|
69
124
|
}
|
|
125
|
+
if (existing != null && httpLocator) {
|
|
126
|
+
return patchMediaOriginal(existing, storageProvider, locator);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const probeStorageProvider = httpLocator ? input.localStorageProvider.trim() : storageProvider;
|
|
130
|
+
const probeLocator = httpLocator ? localLocator : locator;
|
|
131
|
+
if (httpLocator && probeLocator === "") {
|
|
132
|
+
throw new Error("registerMediaLink: localLocator is required when locator is http(s)");
|
|
133
|
+
}
|
|
70
134
|
|
|
71
135
|
const availability = await checkMediaAvailability({
|
|
72
136
|
value: input.value,
|
|
73
|
-
storageProvider:
|
|
74
|
-
locator:
|
|
137
|
+
storageProvider: probeStorageProvider,
|
|
138
|
+
locator: probeLocator,
|
|
75
139
|
localStorageProvider: input.localStorageProvider,
|
|
76
140
|
});
|
|
77
141
|
if (!availability.ok || availability.absolutePath == null) {
|
|
@@ -80,16 +144,16 @@ export async function registerMediaLink(input: RegisterMediaLinkInput): Promise<
|
|
|
80
144
|
|
|
81
145
|
const probed = await probeMediaOriginal({
|
|
82
146
|
value: input.value,
|
|
83
|
-
storageProvider:
|
|
84
|
-
locator:
|
|
147
|
+
storageProvider: probeStorageProvider,
|
|
148
|
+
locator: probeLocator,
|
|
85
149
|
absolutePath: availability.absolutePath,
|
|
86
150
|
});
|
|
87
151
|
|
|
88
152
|
const draft = buildMediaLinkDraft({
|
|
89
153
|
value: input.value,
|
|
90
154
|
name,
|
|
91
|
-
storageProvider: probed.storageProvider,
|
|
92
|
-
locator: probed.locator,
|
|
155
|
+
storageProvider: httpLocator ? storageProvider : probed.storageProvider,
|
|
156
|
+
locator: httpLocator ? locator : probed.locator,
|
|
93
157
|
contentHash: probed.contentHash,
|
|
94
158
|
size: probed.size,
|
|
95
159
|
mimeType: probed.mimeType,
|
|
@@ -117,6 +181,9 @@ export async function registerMediaLink(input: RegisterMediaLinkInput): Promise<
|
|
|
117
181
|
if (isCreateTargetAlreadyExistsError(error)) {
|
|
118
182
|
const raced = await findMediaLink({ value: input.value, name });
|
|
119
183
|
if (raced != null) {
|
|
184
|
+
if (httpLocator) {
|
|
185
|
+
return patchMediaOriginal(raced, storageProvider, locator);
|
|
186
|
+
}
|
|
120
187
|
logger.info("media register race — using existing", {
|
|
121
188
|
topic: "dedup",
|
|
122
189
|
data: { id: raced.id, value: input.value, name },
|