target-supabase-sdk 0.2.20 → 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.d.ts +1 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +1 -1
- package/dist/chunks/{task-queue-CqmIVCBi.js → task-queue-DWFe0rCS.js} +20 -22
- 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/dist/shared/review/index.d.ts +1 -1
- package/dist/shared/review/index.d.ts.map +1 -1
- package/dist/shared/review/review.build.d.ts +3 -6
- package/dist/shared/review/review.build.d.ts.map +1 -1
- package/dist/shared/review/review.interface.d.ts +2 -2
- package/dist/shared/review/review.query.d.ts +2 -2
- package/dist/shared/review/review.query.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/browser.ts +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/src/shared/review/README.md +15 -16
- package/src/shared/review/index.ts +1 -1
- package/src/shared/review/review.build.ts +8 -13
- package/src/shared/review/review.interface.ts +2 -2
- package/src/shared/review/review.query.ts +4 -4
- package/dist/chunks/task-queue-CqmIVCBi.js.map +0 -1
|
@@ -3,9 +3,11 @@ import type { Link } from "../../link/link.interface";
|
|
|
3
3
|
import { type FeedSource, type FeedValue } from "./feed.interface";
|
|
4
4
|
export interface BuildFeedLinkDraftInput {
|
|
5
5
|
value: FeedValue;
|
|
6
|
+
/** When set, used as Link `name` (skips {@link buildFeedLinkName}). */
|
|
7
|
+
name?: string;
|
|
6
8
|
/** Dots are normalized to spaces in {@link buildFeedLinkName} before joining with `feedKey`. */
|
|
7
|
-
platformName
|
|
8
|
-
feedKey
|
|
9
|
+
platformName?: string;
|
|
10
|
+
feedKey?: string;
|
|
9
11
|
source: FeedSource;
|
|
10
12
|
locator: string;
|
|
11
13
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feed.build.d.ts","sourceRoot":"","sources":["../../../src/shared/feed/feed.build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAGH,KAAK,UAAU,EACf,KAAK,SAAS,EAGjB,MAAM,kBAAkB,CAAC;AAG1B,MAAM,WAAW,uBAAuB;IACpC,KAAK,EAAE,SAAS,CAAC;IACjB,gGAAgG;IAChG,YAAY,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"feed.build.d.ts","sourceRoot":"","sources":["../../../src/shared/feed/feed.build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAGH,KAAK,UAAU,EACf,KAAK,SAAS,EAGjB,MAAM,kBAAkB,CAAC;AAG1B,MAAM,WAAW,uBAAuB;IACpC,KAAK,EAAE,SAAS,CAAC;IACjB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,qEAAqE;AACrE,wBAAgB,qBAAqB,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,SAAS,CAK/E;AAED,iFAAiF;AACjF,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAcvG;AAED,gGAAgG;AAChG,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAKjF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,WAAW,CAAC,IAAI,CAAC,CAgCpF"}
|
|
@@ -23,12 +23,20 @@ export interface FeedAvailabilityResult {
|
|
|
23
23
|
* **Node-only**
|
|
24
24
|
*/
|
|
25
25
|
export declare function checkFeedLocalAvailability(input: CheckFeedLocalAvailabilityInput): Promise<FeedAvailabilityResult>;
|
|
26
|
+
export interface CheckFeedOssAvailabilityOptions {
|
|
27
|
+
/** Override global `fetch` (proxied outbound, etc.). Default: SDK `fetchWithRetry`. */
|
|
28
|
+
fetch?: (url: string, init?: RequestInit) => Promise<Response>;
|
|
29
|
+
/** When true, skip HTTP (co-located Files sandbox, etc.). */
|
|
30
|
+
tryLocalResolve?: (locator: string) => Promise<boolean>;
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
}
|
|
26
33
|
/**
|
|
27
34
|
* Remote reachability for feed ingest (`.oss` source) via HTTP(S).
|
|
28
35
|
*
|
|
29
|
-
*
|
|
36
|
+
* Optional `tryLocalResolve` first (same-host Files). Then `HEAD`, then `GET` with
|
|
37
|
+
* `Range: bytes=0-0` when `HEAD` is not allowed. Pass `fetch` for proxied outbound.
|
|
30
38
|
*
|
|
31
39
|
* **Node-only**
|
|
32
40
|
*/
|
|
33
|
-
export declare function checkFeedOssAvailability(locator: string): Promise<FeedAvailabilityResult>;
|
|
41
|
+
export declare function checkFeedOssAvailability(locator: string, options?: CheckFeedOssAvailabilityOptions): Promise<FeedAvailabilityResult>;
|
|
34
42
|
//# sourceMappingURL=feed.access.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feed.access.d.ts","sourceRoot":"","sources":["../../../../src/shared/feed/node/feed.access.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,WAAW,+BAA+B;IAC5C,KAAK,EAAE,SAAS,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,oBAAoB,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAUD;;;;;;;;;GASG;AACH,wBAAsB,0BAA0B,CAC5C,KAAK,EAAE,+BAA+B,GACvC,OAAO,CAAC,sBAAsB,CAAC,CA0CjC;
|
|
1
|
+
{"version":3,"file":"feed.access.d.ts","sourceRoot":"","sources":["../../../../src/shared/feed/node/feed.access.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,WAAW,+BAA+B;IAC5C,KAAK,EAAE,SAAS,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,oBAAoB,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAUD;;;;;;;;;GASG;AACH,wBAAsB,0BAA0B,CAC5C,KAAK,EAAE,+BAA+B,GACvC,OAAO,CAAC,sBAAsB,CAAC,CA0CjC;AAKD,MAAM,WAAW,+BAA+B;IAC5C,uFAAuF;IACvF,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/D,6DAA6D;IAC7D,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAsBD;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAC1C,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,+BAA+B,GAC1C,OAAO,CAAC,sBAAsB,CAAC,CAgCjC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type FeedIngestSource } from "../feed.interface";
|
|
1
|
+
import { type FeedIngestSource, type FeedValue } from "../feed.interface";
|
|
2
|
+
import { type CheckFeedOssAvailabilityOptions } from "./feed.access";
|
|
2
3
|
export interface RegisterFeedInput {
|
|
3
4
|
/** Existing feed Link row id (must still be `.public` unless already ingested with same payload). */
|
|
4
5
|
id: string;
|
|
@@ -7,6 +8,8 @@ export interface RegisterFeedInput {
|
|
|
7
8
|
locator: string;
|
|
8
9
|
/** Required when `source` is `.local` (e.g. `process.env.LOCAL_STORAGE_PROVIDER`). Ignored for `.oss`. */
|
|
9
10
|
localStorageProvider?: string;
|
|
11
|
+
/** `.oss` HTTP check: inject `fetch` / same-host resolve. */
|
|
12
|
+
ossCheck?: CheckFeedOssAvailabilityOptions;
|
|
10
13
|
}
|
|
11
14
|
export interface RegisterFeedResult {
|
|
12
15
|
id: string;
|
|
@@ -20,4 +23,26 @@ export interface RegisterFeedResult {
|
|
|
20
23
|
* **Node-only** — under `shared/feed/node/`; do not import from the browser entry.
|
|
21
24
|
*/
|
|
22
25
|
export declare function registerFeed(input: RegisterFeedInput): Promise<RegisterFeedResult>;
|
|
26
|
+
export interface CreateFeedInput {
|
|
27
|
+
/** Full Link `name` (Filter itemName, etc.). */
|
|
28
|
+
name: string;
|
|
29
|
+
value: FeedValue;
|
|
30
|
+
source: FeedIngestSource;
|
|
31
|
+
storageProvider: string;
|
|
32
|
+
locator: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
preview?: string;
|
|
35
|
+
tagList?: string[];
|
|
36
|
+
localStorageProvider?: string;
|
|
37
|
+
ossCheck?: CheckFeedOssAvailabilityOptions;
|
|
38
|
+
}
|
|
39
|
+
export interface CreateFeedResult {
|
|
40
|
+
id: string;
|
|
41
|
+
created: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Insert a new feed Link already on `.local` or `.oss` (not a `.public` promote).
|
|
45
|
+
* Dedup: `category` + `value` + `name`. Same original → `{ created: false }`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function createFeed(input: CreateFeedInput): Promise<CreateFeedResult>;
|
|
23
48
|
//# sourceMappingURL=feed.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feed.service.d.ts","sourceRoot":"","sources":["../../../../src/shared/feed/node/feed.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"feed.service.d.ts","sourceRoot":"","sources":["../../../../src/shared/feed/node/feed.service.ts"],"names":[],"mappings":"AAWA,OAAO,EACH,KAAK,gBAAgB,EAErB,KAAK,SAAS,EAGjB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACH,KAAK,+BAA+B,EAGvC,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,iBAAiB;IAC9B,qGAAqG;IACrG,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,gBAAgB,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,0GAA0G;IAC1G,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,+BAA+B,CAAC;CAC9C;AAED,MAAM,WAAW,kBAAkB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,gGAAgG;IAChG,OAAO,EAAE,OAAO,CAAC;CACpB;AAmDD;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA+FxF;AAED,MAAM,WAAW,eAAe;IAC5B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,gBAAgB,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,EAAE,+BAA+B,CAAC;CAC9C;AAED,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAyFlF"}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export type { FeedIngestSource } from "../feed.interface";
|
|
6
6
|
export { FEED_INGEST_SOURCES, isFeedIngestSource } from "../feed.interface";
|
|
7
|
-
export type { CheckFeedLocalAvailabilityInput, FeedAvailabilityResult } from "./feed.access";
|
|
7
|
+
export type { CheckFeedLocalAvailabilityInput, CheckFeedOssAvailabilityOptions, FeedAvailabilityResult, } from "./feed.access";
|
|
8
8
|
export { checkFeedLocalAvailability, checkFeedOssAvailability } from "./feed.access";
|
|
9
|
-
export type { RegisterFeedInput, RegisterFeedResult } from "./feed.service";
|
|
10
|
-
export { registerFeed } from "./feed.service";
|
|
9
|
+
export type { CreateFeedInput, CreateFeedResult, RegisterFeedInput, RegisterFeedResult } from "./feed.service";
|
|
10
|
+
export { createFeed, registerFeed } from "./feed.service";
|
|
11
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/shared/feed/node/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/shared/feed/node/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,YAAY,EACR,+BAA+B,EAC/B,+BAA+B,EAC/B,sBAAsB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACrF,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC/G,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -15,6 +15,8 @@ export interface FetchRetryOptions {
|
|
|
15
15
|
/** When set, retry/success lines are logged via SDK logger. */
|
|
16
16
|
logger?: LoggerWithScope;
|
|
17
17
|
hint?: string;
|
|
18
|
+
/** Override global `fetch` (e.g. proxied outbound fetch). Ignores `dispatcher`. */
|
|
19
|
+
fetch?: (url: string, init?: RequestInit) => Promise<Response>;
|
|
18
20
|
}
|
|
19
21
|
export declare function fetchWithRetry(url: string, initOrFactory: RequestInit | FetchInitFactory, options: FetchRetryOptions): Promise<Response>;
|
|
20
22
|
export declare function fetchBinaryWithRetry(url: string, init: RequestInit, options: FetchRetryOptions): Promise<ArrayBuffer>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-retry.d.ts","sourceRoot":"","sources":["../../../src/shared/http/fetch-retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAOpD,2DAA2D;AAC3D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,WAAW,CAAC;AAEjD,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAEzD;AAED,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6FAA6F;IAC7F,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAChD,+DAA+D;IAC/D,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"fetch-retry.d.ts","sourceRoot":"","sources":["../../../src/shared/http/fetch-retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAOpD,2DAA2D;AAC3D,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,WAAW,CAAC;AAEjD,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAEzD;AAED,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6FAA6F;IAC7F,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAChD,+DAA+D;IAC/D,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClE;AAuCD,wBAAsB,cAAc,CAChC,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,WAAW,GAAG,gBAAgB,EAC7C,OAAO,EAAE,iBAAiB,GAC3B,OAAO,CAAC,QAAQ,CAAC,CAoEnB;AAED,wBAAsB,oBAAoB,CACtC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,iBAAiB,GAC3B,OAAO,CAAC,WAAW,CAAC,CAMtB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Link } from "../../../link/link.interface";
|
|
2
2
|
import { type MediaValue } from "../media.interface";
|
|
3
3
|
export interface FindMediaLinkInput {
|
|
4
4
|
value: MediaValue;
|
|
@@ -13,6 +13,11 @@ export interface RegisterMediaLinkInput {
|
|
|
13
13
|
locator: string;
|
|
14
14
|
/** This host id for availability (e.g. `process.env.LOCAL_STORAGE_PROVIDER`). */
|
|
15
15
|
localStorageProvider: string;
|
|
16
|
+
/**
|
|
17
|
+
* Local file to probe when `locator` is http(s) (OSS ingest).
|
|
18
|
+
* Availability uses this path + `localStorageProvider`.
|
|
19
|
+
*/
|
|
20
|
+
localLocator?: string;
|
|
16
21
|
description?: string;
|
|
17
22
|
tagList?: string[];
|
|
18
23
|
}
|
|
@@ -22,7 +27,8 @@ export interface RegisterMediaLinkResult {
|
|
|
22
27
|
}
|
|
23
28
|
/**
|
|
24
29
|
* Register a media Link: dedup → availability → probe → `postTarget`.
|
|
25
|
-
* Idempotent when `category`+`value`+`name` already exist.
|
|
30
|
+
* Idempotent when `category`+`value`+`name` already exist (local path).
|
|
31
|
+
* HTTP `locator` + `localLocator`: probe local file, persist remote URL; patch if name exists.
|
|
26
32
|
*
|
|
27
33
|
* **Node-only** — under `shared/media/node/`; do not import from the browser entry.
|
|
28
34
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.service.d.ts","sourceRoot":"","sources":["../../../../src/shared/media/node/media.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"media.service.d.ts","sourceRoot":"","sources":["../../../../src/shared/media/node/media.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,IAAI,EAAoB,MAAM,8BAA8B,CAAC;AAIzF,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAMnE,MAAM,WAAW,kBAAkB;IAC/B,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,wDAAwD;AACxD,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAYnF;AAED,MAAM,WAAW,sBAAsB;IACnC,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;CACpB;AA6CD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA6FvG"}
|
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export type { BuildReviewLinkDraftInput } from "./review.build";
|
|
5
5
|
export { buildReviewLinkDraft } from "./review.build";
|
|
6
|
-
export {
|
|
6
|
+
export { reviewLinksForNameFilters } from "./review.query";
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/review/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/review/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import type { TargetDraft } from "../../core.interface";
|
|
2
2
|
import type { Link } from "../../link/link.interface";
|
|
3
|
-
import { type ReviewValue } from "./review.interface";
|
|
4
3
|
export interface BuildReviewLinkDraftInput {
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
/** Associated Target id — written to `Link.name`. */
|
|
8
|
-
refId: string;
|
|
4
|
+
/** Written to `Link.name` (caller-defined; often a subject Target id). */
|
|
5
|
+
name: string;
|
|
9
6
|
/** Interaction payload — written to `Link.details.original`. */
|
|
10
7
|
original: unknown;
|
|
11
8
|
tagList?: string[];
|
|
@@ -13,7 +10,7 @@ export interface BuildReviewLinkDraftInput {
|
|
|
13
10
|
}
|
|
14
11
|
/**
|
|
15
12
|
* Assemble a review {@link Link} draft (`category=link`, `loaderKey === value === "review"`).
|
|
16
|
-
* Does not validate `
|
|
13
|
+
* Does not validate `name` or write to Supabase.
|
|
17
14
|
*/
|
|
18
15
|
export declare function buildReviewLinkDraft(input: BuildReviewLinkDraftInput): TargetDraft<Link>;
|
|
19
16
|
//# sourceMappingURL=review.build.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.build.d.ts","sourceRoot":"","sources":["../../../src/shared/review/review.build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"review.build.d.ts","sourceRoot":"","sources":["../../../src/shared/review/review.build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAGtD,MAAM,WAAW,yBAAyB;IACtC,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,WAAW,CAAC,IAAI,CAAC,CAexF"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Review Link protocol — Link rows with `value` / `loaderKey` === {@link REVIEW_VALUE}.
|
|
3
3
|
* No separate Target category; category remains `link`.
|
|
4
4
|
*
|
|
5
|
-
* A Review records one user interaction
|
|
6
|
-
* Many review Links may share the same
|
|
5
|
+
* A Review records one user interaction; `Link.name` is caller-defined (often a subject Target id).
|
|
6
|
+
* Many review Links may share the same `name`.
|
|
7
7
|
*/
|
|
8
8
|
export declare const REVIEW_VALUE: "review";
|
|
9
9
|
/** Discriminator stored in both `Link.value` and `details.loaderKey`. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { QueryFilter } from "../../core.interface";
|
|
2
2
|
/**
|
|
3
|
-
* Filters for
|
|
3
|
+
* Filters for review Links with `Link.name === name`.
|
|
4
4
|
* Many rows may match — the SDK does not define dedup for reviews.
|
|
5
5
|
*/
|
|
6
|
-
export declare function
|
|
6
|
+
export declare function reviewLinksForNameFilters(name: string): QueryFilter[];
|
|
7
7
|
//# sourceMappingURL=review.query.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.query.d.ts","sourceRoot":"","sources":["../../../src/shared/review/review.query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAIxD;;;GAGG;AACH,wBAAgB,
|
|
1
|
+
{"version":3,"file":"review.query.d.ts","sourceRoot":"","sources":["../../../src/shared/review/review.query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAIxD;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAOrE"}
|
package/package.json
CHANGED
package/src/browser.ts
CHANGED
|
@@ -242,7 +242,7 @@ export {
|
|
|
242
242
|
mediaLinkDedupFilters,
|
|
243
243
|
} from "./shared/media";
|
|
244
244
|
export type { BuildReviewLinkDraftInput } from "./shared/review";
|
|
245
|
-
export { buildReviewLinkDraft,
|
|
245
|
+
export { buildReviewLinkDraft, reviewLinksForNameFilters } from "./shared/review";
|
|
246
246
|
export { isHttpUrl, resolveFetchUrl } from "./shared/utils/fetch-url";
|
|
247
247
|
export { getValueAtPath } from "./shared/utils/get-value-at-path";
|
|
248
248
|
export type {
|
package/src/node.ts
CHANGED
|
@@ -160,6 +160,9 @@ export {
|
|
|
160
160
|
export { RepoManager } from "./repo/repo-manager";
|
|
161
161
|
export type {
|
|
162
162
|
CheckFeedLocalAvailabilityInput,
|
|
163
|
+
CheckFeedOssAvailabilityOptions,
|
|
164
|
+
CreateFeedInput,
|
|
165
|
+
CreateFeedResult,
|
|
163
166
|
FeedAvailabilityResult,
|
|
164
167
|
FeedIngestSource,
|
|
165
168
|
RegisterFeedInput,
|
|
@@ -168,6 +171,7 @@ export type {
|
|
|
168
171
|
export {
|
|
169
172
|
checkFeedLocalAvailability,
|
|
170
173
|
checkFeedOssAvailability,
|
|
174
|
+
createFeed,
|
|
171
175
|
FEED_INGEST_SOURCES,
|
|
172
176
|
isFeedIngestSource,
|
|
173
177
|
registerFeed,
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
} from "target-supabase-sdk";
|
|
37
37
|
|
|
38
38
|
// Node — ingest after .public draft exists
|
|
39
|
-
import { registerFeed, FEED_INGEST_SOURCES } from "target-supabase-sdk/node";
|
|
39
|
+
import { registerFeed, createFeed, checkFeedOssAvailability, FEED_INGEST_SOURCES } from "target-supabase-sdk/node";
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
---
|
|
@@ -45,6 +45,7 @@ import { registerFeed, FEED_INGEST_SOURCES } from "target-supabase-sdk/node";
|
|
|
45
45
|
|
|
46
46
|
1. **Create (browser or any host)** — `buildFeedLinkDraft` with `source: ".public"`, public `locator` (often a platform URL), `original.storageProvider: ""`. Persist via `postTarget` / `createTarget`.
|
|
47
47
|
2. **Ingest (Node)** — `registerFeed` on an existing row `id`: validate the new locator, then promote `tagList` from `.public` to `.local` or `.oss` and update `original.storageProvider` + `locator`. Preserves `twinList` and other non-source tags.
|
|
48
|
+
3. **Create already ingested (Node)** — `createFeed` inserts a new row already tagged `.local` or `.oss` (Filter / OSS-first). Dedup on `category` + `value` + `name`.
|
|
48
49
|
|
|
49
50
|
---
|
|
50
51
|
|
|
@@ -108,7 +109,7 @@ Leading `.` marks **system** tags (not user tags).
|
|
|
108
109
|
3. Require `tagList` to include `.public` (not already ingested with different state).
|
|
109
110
|
4. **Availability**
|
|
110
111
|
- `.local` — `checkFeedLocalAvailability`: `storageProvider === localStorageProvider`, absolute path, file (or directory for `feed.image-list`) exists and is non-empty where applicable.
|
|
111
|
-
- `.oss` — `checkFeedOssAvailability`: `http(s)` URL; `HEAD`, then `GET` with `Range: bytes=0-0` if `HEAD` is not supported.
|
|
112
|
+
- `.oss` — `checkFeedOssAvailability`: `http(s)` URL; optional `tryLocalResolve` then `HEAD`, then `GET` with `Range: bytes=0-0` if `HEAD` is not supported. Pass `ossCheck.fetch` for proxied outbound.
|
|
112
113
|
5. **Update** — `updateTarget` with optimistic lock `details->original->>storageProvider` eq `""` (still `.public` tier). Sets `tagList` via `buildFeedTagList`, updates `original.storageProvider` and `locator`, keeps `twinList`.
|
|
113
114
|
|
|
114
115
|
**Errors (representative)**
|
|
@@ -149,7 +150,7 @@ Same variable as media register — see `src/shared/media/README.md`.
|
|
|
149
150
|
|
|
150
151
|
| Topic | Current behavior | Possible follow-up |
|
|
151
152
|
|-------|------------------|-------------------|
|
|
152
|
-
| OSS
|
|
153
|
+
| OSS HTTP | Default global `fetch`; inject `fetch` / `tryLocalResolve` | Signed URLs or provider-specific probes |
|
|
153
154
|
| `.local` on another host | Fails availability (by design, like media) | Remote agent ingest |
|
|
154
155
|
| `twinList` on ingest | Not re-validated | Optional probe per twin |
|
|
155
156
|
| Re-ingest / migrate `.local` → `.oss` | Not supported | New API with lock on prior source tag |
|
|
@@ -13,9 +13,11 @@ import { buildFeedLinkName } from "./feed.name";
|
|
|
13
13
|
|
|
14
14
|
export interface BuildFeedLinkDraftInput {
|
|
15
15
|
value: FeedValue;
|
|
16
|
+
/** When set, used as Link `name` (skips {@link buildFeedLinkName}). */
|
|
17
|
+
name?: string;
|
|
16
18
|
/** Dots are normalized to spaces in {@link buildFeedLinkName} before joining with `feedKey`. */
|
|
17
|
-
platformName
|
|
18
|
-
feedKey
|
|
19
|
+
platformName?: string;
|
|
20
|
+
feedKey?: string;
|
|
19
21
|
source: FeedSource;
|
|
20
22
|
locator: string;
|
|
21
23
|
/**
|
|
@@ -75,7 +77,8 @@ export function buildFeedLinkDraft(input: BuildFeedLinkDraftInput): TargetDraft<
|
|
|
75
77
|
throw new Error(`buildFeedLinkDraft: unsupported feed source: ${String(input.source)}`);
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
const
|
|
80
|
+
const explicitName = input.name?.trim() ?? "";
|
|
81
|
+
const name = explicitName !== "" ? explicitName : buildFeedLinkName(input.platformName ?? "", input.feedKey ?? "");
|
|
79
82
|
const locator = input.locator.trim();
|
|
80
83
|
if (locator === "") {
|
|
81
84
|
throw new Error("buildFeedLinkDraft: locator is empty");
|
|
@@ -87,7 +87,19 @@ export async function checkFeedLocalAvailability(
|
|
|
87
87
|
const OSS_CHECK_TIMEOUT_MS = 15_000;
|
|
88
88
|
const OSS_CHECK_MAX_ATTEMPTS = 2;
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
export interface CheckFeedOssAvailabilityOptions {
|
|
91
|
+
/** Override global `fetch` (proxied outbound, etc.). Default: SDK `fetchWithRetry`. */
|
|
92
|
+
fetch?: (url: string, init?: RequestInit) => Promise<Response>;
|
|
93
|
+
/** When true, skip HTTP (co-located Files sandbox, etc.). */
|
|
94
|
+
tryLocalResolve?: (locator: string) => Promise<boolean>;
|
|
95
|
+
timeoutMs?: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function probeHttpLocator(
|
|
99
|
+
locator: string,
|
|
100
|
+
method: "HEAD" | "GET",
|
|
101
|
+
options?: CheckFeedOssAvailabilityOptions,
|
|
102
|
+
): Promise<Response> {
|
|
91
103
|
return fetchWithRetry(
|
|
92
104
|
locator,
|
|
93
105
|
{
|
|
@@ -96,8 +108,9 @@ async function probeHttpLocator(locator: string, method: "HEAD" | "GET"): Promis
|
|
|
96
108
|
},
|
|
97
109
|
{
|
|
98
110
|
label: "feed-oss-check",
|
|
99
|
-
timeoutMs: OSS_CHECK_TIMEOUT_MS,
|
|
111
|
+
timeoutMs: options?.timeoutMs ?? OSS_CHECK_TIMEOUT_MS,
|
|
100
112
|
maxAttempts: OSS_CHECK_MAX_ATTEMPTS,
|
|
113
|
+
...(options?.fetch != null ? { fetch: options.fetch } : {}),
|
|
101
114
|
},
|
|
102
115
|
);
|
|
103
116
|
}
|
|
@@ -105,11 +118,15 @@ async function probeHttpLocator(locator: string, method: "HEAD" | "GET"): Promis
|
|
|
105
118
|
/**
|
|
106
119
|
* Remote reachability for feed ingest (`.oss` source) via HTTP(S).
|
|
107
120
|
*
|
|
108
|
-
*
|
|
121
|
+
* Optional `tryLocalResolve` first (same-host Files). Then `HEAD`, then `GET` with
|
|
122
|
+
* `Range: bytes=0-0` when `HEAD` is not allowed. Pass `fetch` for proxied outbound.
|
|
109
123
|
*
|
|
110
124
|
* **Node-only**
|
|
111
125
|
*/
|
|
112
|
-
export async function checkFeedOssAvailability(
|
|
126
|
+
export async function checkFeedOssAvailability(
|
|
127
|
+
locator: string,
|
|
128
|
+
options?: CheckFeedOssAvailabilityOptions,
|
|
129
|
+
): Promise<FeedAvailabilityResult> {
|
|
113
130
|
const trimmed = locator.trim();
|
|
114
131
|
if (trimmed === "") {
|
|
115
132
|
return { ok: false, reason: "locator is empty" };
|
|
@@ -118,10 +135,20 @@ export async function checkFeedOssAvailability(locator: string): Promise<FeedAva
|
|
|
118
135
|
return { ok: false, reason: `oss locator must be an http(s) URL: ${trimmed}` };
|
|
119
136
|
}
|
|
120
137
|
|
|
138
|
+
if (options?.tryLocalResolve != null) {
|
|
139
|
+
try {
|
|
140
|
+
if (await options.tryLocalResolve(trimmed)) {
|
|
141
|
+
return { ok: true };
|
|
142
|
+
}
|
|
143
|
+
} catch {
|
|
144
|
+
// fall through to HTTP
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
121
148
|
try {
|
|
122
|
-
let response = await probeHttpLocator(trimmed, "HEAD");
|
|
149
|
+
let response = await probeHttpLocator(trimmed, "HEAD", options);
|
|
123
150
|
if (response.status === 405 || response.status === 501) {
|
|
124
|
-
response = await probeHttpLocator(trimmed, "GET");
|
|
151
|
+
response = await probeHttpLocator(trimmed, "GET", options);
|
|
125
152
|
}
|
|
126
153
|
if (response.ok || (response.status >= 200 && response.status < 400)) {
|
|
127
154
|
return { ok: true };
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getPossibleTarget,
|
|
3
|
+
getTarget,
|
|
4
|
+
isCreateTargetAlreadyExistsError,
|
|
5
|
+
postTarget,
|
|
6
|
+
updateTarget,
|
|
7
|
+
} from "../../../core.api";
|
|
2
8
|
import type { Target } from "../../../core.interface";
|
|
3
9
|
import { CategoryLink, type Link, type LinkDetails } from "../../../link/link.interface";
|
|
4
10
|
import { createLogger } from "../../log/core/create-logger";
|
|
5
|
-
import { buildFeedTagList, resolveFeedOriginalStorageProvider } from "../feed.build";
|
|
11
|
+
import { buildFeedLinkDraft, buildFeedTagList, resolveFeedOriginalStorageProvider } from "../feed.build";
|
|
6
12
|
import {
|
|
7
13
|
type FeedIngestSource,
|
|
8
14
|
type FeedOriginal,
|
|
@@ -10,7 +16,12 @@ import {
|
|
|
10
16
|
isFeedIngestSource,
|
|
11
17
|
isFeedValue,
|
|
12
18
|
} from "../feed.interface";
|
|
13
|
-
import {
|
|
19
|
+
import { feedLinkDedupFilters } from "../feed.query";
|
|
20
|
+
import {
|
|
21
|
+
type CheckFeedOssAvailabilityOptions,
|
|
22
|
+
checkFeedLocalAvailability,
|
|
23
|
+
checkFeedOssAvailability,
|
|
24
|
+
} from "./feed.access";
|
|
14
25
|
|
|
15
26
|
const logger = createLogger({ module: "feed" });
|
|
16
27
|
|
|
@@ -22,6 +33,8 @@ export interface RegisterFeedInput {
|
|
|
22
33
|
locator: string;
|
|
23
34
|
/** Required when `source` is `.local` (e.g. `process.env.LOCAL_STORAGE_PROVIDER`). Ignored for `.oss`. */
|
|
24
35
|
localStorageProvider?: string;
|
|
36
|
+
/** `.oss` HTTP check: inject `fetch` / same-host resolve. */
|
|
37
|
+
ossCheck?: CheckFeedOssAvailabilityOptions;
|
|
25
38
|
}
|
|
26
39
|
|
|
27
40
|
export interface RegisterFeedResult {
|
|
@@ -137,7 +150,7 @@ export async function registerFeed(input: RegisterFeedInput): Promise<RegisterFe
|
|
|
137
150
|
throw new Error(`registerFeed: local locator unavailable — ${availability.reason ?? "unknown"}`);
|
|
138
151
|
}
|
|
139
152
|
} else {
|
|
140
|
-
const availability = await checkFeedOssAvailability(locator);
|
|
153
|
+
const availability = await checkFeedOssAvailability(locator, input.ossCheck);
|
|
141
154
|
if (!availability.ok) {
|
|
142
155
|
throw new Error(`registerFeed: oss locator unavailable — ${availability.reason ?? "unknown"}`);
|
|
143
156
|
}
|
|
@@ -181,3 +194,117 @@ export async function registerFeed(input: RegisterFeedInput): Promise<RegisterFe
|
|
|
181
194
|
});
|
|
182
195
|
return { id, updated: true };
|
|
183
196
|
}
|
|
197
|
+
|
|
198
|
+
export interface CreateFeedInput {
|
|
199
|
+
/** Full Link `name` (Filter itemName, etc.). */
|
|
200
|
+
name: string;
|
|
201
|
+
value: FeedValue;
|
|
202
|
+
source: FeedIngestSource;
|
|
203
|
+
storageProvider: string;
|
|
204
|
+
locator: string;
|
|
205
|
+
description?: string;
|
|
206
|
+
preview?: string;
|
|
207
|
+
tagList?: string[];
|
|
208
|
+
localStorageProvider?: string;
|
|
209
|
+
ossCheck?: CheckFeedOssAvailabilityOptions;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export interface CreateFeedResult {
|
|
213
|
+
id: string;
|
|
214
|
+
created: boolean;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Insert a new feed Link already on `.local` or `.oss` (not a `.public` promote).
|
|
219
|
+
* Dedup: `category` + `value` + `name`. Same original → `{ created: false }`.
|
|
220
|
+
*/
|
|
221
|
+
export async function createFeed(input: CreateFeedInput): Promise<CreateFeedResult> {
|
|
222
|
+
if (!isFeedValue(input.value)) {
|
|
223
|
+
throw new Error(`createFeed: unsupported feed value: ${String(input.value)}`);
|
|
224
|
+
}
|
|
225
|
+
if (!isFeedIngestSource(input.source)) {
|
|
226
|
+
throw new Error(`createFeed: source must be .local or .oss, got ${String(input.source)}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const name = input.name.trim();
|
|
230
|
+
if (name === "") {
|
|
231
|
+
throw new Error("createFeed: name is empty");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const resolvedStorageProvider = resolveFeedOriginalStorageProvider(input.source, input.storageProvider);
|
|
235
|
+
const locator = input.locator.trim();
|
|
236
|
+
if (locator === "") {
|
|
237
|
+
throw new Error("createFeed: locator is empty");
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const { data: existing } = await getPossibleTarget({
|
|
241
|
+
filterList: feedLinkDedupFilters({ value: input.value, name }),
|
|
242
|
+
});
|
|
243
|
+
if (existing != null) {
|
|
244
|
+
const link = existing as Link;
|
|
245
|
+
if (isSameIngestState(link, input.source, resolvedStorageProvider, locator)) {
|
|
246
|
+
return { id: existing.id, created: false };
|
|
247
|
+
}
|
|
248
|
+
throw new Error("createFeed: feed name already exists with different source, storageProvider, or locator");
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (input.source === ".local") {
|
|
252
|
+
const localStorageProvider = input.localStorageProvider?.trim() ?? "";
|
|
253
|
+
if (localStorageProvider === "") {
|
|
254
|
+
throw new Error("createFeed: localStorageProvider is required when source is .local");
|
|
255
|
+
}
|
|
256
|
+
const availability = await checkFeedLocalAvailability({
|
|
257
|
+
value: input.value,
|
|
258
|
+
storageProvider: resolvedStorageProvider,
|
|
259
|
+
locator,
|
|
260
|
+
localStorageProvider,
|
|
261
|
+
});
|
|
262
|
+
if (!availability.ok) {
|
|
263
|
+
throw new Error(`createFeed: local locator unavailable — ${availability.reason ?? "unknown"}`);
|
|
264
|
+
}
|
|
265
|
+
} else {
|
|
266
|
+
const availability = await checkFeedOssAvailability(locator, input.ossCheck);
|
|
267
|
+
if (!availability.ok) {
|
|
268
|
+
throw new Error(`createFeed: oss locator unavailable — ${availability.reason ?? "unknown"}`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const draft = buildFeedLinkDraft({
|
|
273
|
+
name,
|
|
274
|
+
value: input.value,
|
|
275
|
+
source: input.source,
|
|
276
|
+
storageProvider: resolvedStorageProvider,
|
|
277
|
+
locator,
|
|
278
|
+
description: input.description,
|
|
279
|
+
preview: input.preview ?? locator,
|
|
280
|
+
tagList: input.tagList,
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
const { data, error } = await postTarget({
|
|
285
|
+
name: draft.name,
|
|
286
|
+
value: draft.value,
|
|
287
|
+
category: draft.category,
|
|
288
|
+
tagList: draft.tagList,
|
|
289
|
+
details: draft.details,
|
|
290
|
+
});
|
|
291
|
+
if (error != null || data == null) {
|
|
292
|
+
throw new Error(error?.message ?? "createFeed: postTarget failed");
|
|
293
|
+
}
|
|
294
|
+
logger.info("feed created", {
|
|
295
|
+
topic: "register",
|
|
296
|
+
data: { id: data.id, source: input.source, name, locator },
|
|
297
|
+
});
|
|
298
|
+
return { id: data.id, created: true };
|
|
299
|
+
} catch (error) {
|
|
300
|
+
if (isCreateTargetAlreadyExistsError(error)) {
|
|
301
|
+
const raced = await getPossibleTarget({
|
|
302
|
+
filterList: feedLinkDedupFilters({ value: input.value, name }),
|
|
303
|
+
});
|
|
304
|
+
if (raced.data != null) {
|
|
305
|
+
return { id: raced.data.id, created: false };
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
export type { FeedIngestSource } from "../feed.interface";
|
|
7
7
|
export { FEED_INGEST_SOURCES, isFeedIngestSource } from "../feed.interface";
|
|
8
|
-
export type {
|
|
8
|
+
export type {
|
|
9
|
+
CheckFeedLocalAvailabilityInput,
|
|
10
|
+
CheckFeedOssAvailabilityOptions,
|
|
11
|
+
FeedAvailabilityResult,
|
|
12
|
+
} from "./feed.access";
|
|
9
13
|
export { checkFeedLocalAvailability, checkFeedOssAvailability } from "./feed.access";
|
|
10
|
-
export type { RegisterFeedInput, RegisterFeedResult } from "./feed.service";
|
|
11
|
-
export { registerFeed } from "./feed.service";
|
|
14
|
+
export type { CreateFeedInput, CreateFeedResult, RegisterFeedInput, RegisterFeedResult } from "./feed.service";
|
|
15
|
+
export { createFeed, registerFeed } from "./feed.service";
|