target-supabase-sdk 0.2.17 → 0.2.19

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.
Files changed (57) hide show
  1. package/README.md +28 -0
  2. package/dist/browser.d.ts +2 -0
  3. package/dist/browser.d.ts.map +1 -1
  4. package/dist/browser.js +1 -1
  5. package/dist/chunks/{task-queue-DufG7PlX.js → task-queue-CUa40Vb5.js} +117 -2
  6. package/dist/chunks/task-queue-CUa40Vb5.js.map +1 -0
  7. package/dist/node/telegram/api-client.d.ts +12 -0
  8. package/dist/node/telegram/api-client.d.ts.map +1 -0
  9. package/dist/node/telegram/chunk-locator.d.ts +10 -0
  10. package/dist/node/telegram/chunk-locator.d.ts.map +1 -0
  11. package/dist/node/telegram/chunk.d.ts +4 -0
  12. package/dist/node/telegram/chunk.d.ts.map +1 -0
  13. package/dist/node/telegram/index.d.ts +8 -0
  14. package/dist/node/telegram/index.d.ts.map +1 -0
  15. package/dist/node/telegram/storage-provider.d.ts +32 -0
  16. package/dist/node/telegram/storage-provider.d.ts.map +1 -0
  17. package/dist/node/telegram/types.d.ts +53 -0
  18. package/dist/node/telegram/types.d.ts.map +1 -0
  19. package/dist/node.d.ts +4 -0
  20. package/dist/node.d.ts.map +1 -1
  21. package/dist/node.js +538 -7
  22. package/dist/node.js.map +1 -1
  23. package/dist/shared/feed/feed.build.d.ts +33 -0
  24. package/dist/shared/feed/feed.build.d.ts.map +1 -0
  25. package/dist/shared/feed/feed.interface.d.ts +35 -0
  26. package/dist/shared/feed/feed.interface.d.ts.map +1 -0
  27. package/dist/shared/feed/feed.name.d.ts +8 -0
  28. package/dist/shared/feed/feed.name.d.ts.map +1 -0
  29. package/dist/shared/feed/feed.query.d.ts +8 -0
  30. package/dist/shared/feed/feed.query.d.ts.map +1 -0
  31. package/dist/shared/feed/index.d.ts +13 -0
  32. package/dist/shared/feed/index.d.ts.map +1 -0
  33. package/dist/shared/feed/node/feed.access.d.ts +34 -0
  34. package/dist/shared/feed/node/feed.access.d.ts.map +1 -0
  35. package/dist/shared/feed/node/feed.service.d.ts +23 -0
  36. package/dist/shared/feed/node/feed.service.d.ts.map +1 -0
  37. package/dist/shared/feed/node/index.d.ts +11 -0
  38. package/dist/shared/feed/node/index.d.ts.map +1 -0
  39. package/package.json +8 -1
  40. package/src/browser.ts +8 -1
  41. package/src/node/telegram/api-client.ts +146 -0
  42. package/src/node/telegram/chunk-locator.ts +23 -0
  43. package/src/node/telegram/chunk.ts +33 -0
  44. package/src/node/telegram/index.ts +20 -0
  45. package/src/node/telegram/storage-provider.ts +182 -0
  46. package/src/node/telegram/types.ts +82 -0
  47. package/src/node.ts +37 -0
  48. package/src/shared/feed/README.md +163 -0
  49. package/src/shared/feed/feed.build.ts +101 -0
  50. package/src/shared/feed/feed.interface.ts +50 -0
  51. package/src/shared/feed/feed.name.ts +20 -0
  52. package/src/shared/feed/feed.query.ts +13 -0
  53. package/src/shared/feed/index.ts +13 -0
  54. package/src/shared/feed/node/feed.access.ts +134 -0
  55. package/src/shared/feed/node/feed.service.ts +183 -0
  56. package/src/shared/feed/node/index.ts +11 -0
  57. package/dist/chunks/task-queue-DufG7PlX.js.map +0 -1
@@ -0,0 +1,183 @@
1
+ import { getTarget, updateTarget } from "../../../core.api";
2
+ import type { Target } from "../../../core.interface";
3
+ import { CategoryLink, type Link, type LinkDetails } from "../../../link/link.interface";
4
+ import { createLogger } from "../../log/core/create-logger";
5
+ import { buildFeedTagList, resolveFeedOriginalStorageProvider } from "../feed.build";
6
+ import {
7
+ type FeedIngestSource,
8
+ type FeedOriginal,
9
+ type FeedValue,
10
+ isFeedIngestSource,
11
+ isFeedValue,
12
+ } from "../feed.interface";
13
+ import { checkFeedLocalAvailability, checkFeedOssAvailability } from "./feed.access";
14
+
15
+ const logger = createLogger({ module: "feed" });
16
+
17
+ export interface RegisterFeedInput {
18
+ /** Existing feed Link row id (must still be `.public` unless already ingested with same payload). */
19
+ id: string;
20
+ source: FeedIngestSource;
21
+ storageProvider: string;
22
+ locator: string;
23
+ /** Required when `source` is `.local` (e.g. `process.env.LOCAL_STORAGE_PROVIDER`). Ignored for `.oss`. */
24
+ localStorageProvider?: string;
25
+ }
26
+
27
+ export interface RegisterFeedResult {
28
+ id: string;
29
+ /** `false` when row was already ingested with the same source, storageProvider, and locator. */
30
+ updated: boolean;
31
+ }
32
+
33
+ function parseFeedOriginal(original: unknown): FeedOriginal | null {
34
+ if (original == null || typeof original !== "object") {
35
+ return null;
36
+ }
37
+ const record = original as Record<string, unknown>;
38
+ const storageProvider = typeof record.storageProvider === "string" ? record.storageProvider : null;
39
+ const locator = typeof record.locator === "string" ? record.locator : null;
40
+ if (storageProvider == null || locator == null) {
41
+ return null;
42
+ }
43
+ const twinList = Array.isArray(record.twinList)
44
+ ? record.twinList.filter((entry): entry is string => typeof entry === "string")
45
+ : undefined;
46
+ return {
47
+ storageProvider,
48
+ locator,
49
+ ...(twinList !== undefined ? { twinList } : {}),
50
+ };
51
+ }
52
+
53
+ function assertFeedLink(target: Target): Link {
54
+ if (target.category !== CategoryLink.LINK) {
55
+ throw new Error(`registerFeed: target is not a link (category=${target.category})`);
56
+ }
57
+ if (!isFeedValue(target.value)) {
58
+ throw new Error(`registerFeed: target value is not a feed loader: ${target.value}`);
59
+ }
60
+ const details = target.details as LinkDetails | undefined;
61
+ if (details == null || details.loaderKey !== target.value) {
62
+ throw new Error("registerFeed: invalid feed link details (loaderKey must equal value)");
63
+ }
64
+ return target as Link;
65
+ }
66
+
67
+ function hasIngestSourceTag(tagList: string[]): boolean {
68
+ return tagList.some((tag) => tag === ".local" || tag === ".oss");
69
+ }
70
+
71
+ function isSameIngestState(link: Link, source: FeedIngestSource, storageProvider: string, locator: string): boolean {
72
+ if (!link.tagList.includes(source)) {
73
+ return false;
74
+ }
75
+ const original = parseFeedOriginal(link.details.original);
76
+ if (original == null) {
77
+ return false;
78
+ }
79
+ return original.storageProvider === storageProvider && original.locator === locator;
80
+ }
81
+
82
+ /**
83
+ * Ingest a `.public` feed Link: validate locator, then promote `tagList` source to `.local` or `.oss`
84
+ * and update `details.original.storageProvider` + `locator`.
85
+ *
86
+ * **Node-only** — under `shared/feed/node/`; do not import from the browser entry.
87
+ */
88
+ export async function registerFeed(input: RegisterFeedInput): Promise<RegisterFeedResult> {
89
+ const id = input.id.trim();
90
+ if (id === "") {
91
+ throw new Error("registerFeed: id is empty");
92
+ }
93
+ if (!isFeedIngestSource(input.source)) {
94
+ throw new Error(`registerFeed: source must be .local or .oss, got ${String(input.source)}`);
95
+ }
96
+
97
+ const resolvedStorageProvider = resolveFeedOriginalStorageProvider(input.source, input.storageProvider);
98
+ const locator = input.locator.trim();
99
+ if (locator === "") {
100
+ throw new Error("registerFeed: locator is empty");
101
+ }
102
+
103
+ const { data: target } = await getTarget({ id });
104
+ if (target == null) {
105
+ throw new Error(`registerFeed: target not found: ${id}`);
106
+ }
107
+
108
+ const link = assertFeedLink(target);
109
+ const feedValue = link.value as FeedValue;
110
+
111
+ if (!link.tagList.includes(".public")) {
112
+ if (isSameIngestState(link, input.source, resolvedStorageProvider, locator)) {
113
+ logger.info("feed already ingested", {
114
+ topic: "dedup",
115
+ data: { id, source: input.source, locator },
116
+ });
117
+ return { id, updated: false };
118
+ }
119
+ if (hasIngestSourceTag(link.tagList)) {
120
+ throw new Error("registerFeed: feed already ingested with different source, storageProvider, or locator");
121
+ }
122
+ throw new Error("registerFeed: feed is not .public — cannot ingest");
123
+ }
124
+
125
+ if (input.source === ".local") {
126
+ const localStorageProvider = input.localStorageProvider?.trim() ?? "";
127
+ if (localStorageProvider === "") {
128
+ throw new Error("registerFeed: localStorageProvider is required when source is .local");
129
+ }
130
+ const availability = await checkFeedLocalAvailability({
131
+ value: feedValue,
132
+ storageProvider: resolvedStorageProvider,
133
+ locator,
134
+ localStorageProvider,
135
+ });
136
+ if (!availability.ok) {
137
+ throw new Error(`registerFeed: local locator unavailable — ${availability.reason ?? "unknown"}`);
138
+ }
139
+ } else {
140
+ const availability = await checkFeedOssAvailability(locator);
141
+ if (!availability.ok) {
142
+ throw new Error(`registerFeed: oss locator unavailable — ${availability.reason ?? "unknown"}`);
143
+ }
144
+ }
145
+
146
+ await updateTarget<Link, LinkDetails>({
147
+ id,
148
+ optimisticLockFilterList: [
149
+ { field: "category", operator: "eq", value: CategoryLink.LINK },
150
+ { field: "details->original->>storageProvider", operator: "eq", value: "" },
151
+ ],
152
+ updateFn: (row) => {
153
+ if (!row.tagList.includes(".public")) {
154
+ throw new Error("registerFeed: optimistic lock failed — .public tag missing");
155
+ }
156
+ if (hasIngestSourceTag(row.tagList) && !row.tagList.includes(".public")) {
157
+ throw new Error("registerFeed: feed already ingested");
158
+ }
159
+
160
+ const details = row.details;
161
+ const prior = parseFeedOriginal(details.original);
162
+ const nextOriginal: FeedOriginal = {
163
+ storageProvider: resolvedStorageProvider,
164
+ locator,
165
+ ...(prior?.twinList !== undefined ? { twinList: prior.twinList } : {}),
166
+ };
167
+
168
+ return {
169
+ tagList: buildFeedTagList(input.source, row.tagList),
170
+ details: {
171
+ ...details,
172
+ original: nextOriginal,
173
+ },
174
+ };
175
+ },
176
+ });
177
+
178
+ logger.info("feed ingested", {
179
+ topic: "register",
180
+ data: { id, source: input.source, storageProvider: resolvedStorageProvider, locator },
181
+ });
182
+ return { id, updated: true };
183
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Node-only feed surface — for `src/node.ts` / `target-supabase-sdk/node` only.
3
+ * Never re-export from `../index.ts` or `browser.ts`.
4
+ */
5
+
6
+ export type { FeedIngestSource } from "../feed.interface";
7
+ export { FEED_INGEST_SOURCES, isFeedIngestSource } from "../feed.interface";
8
+ export type { CheckFeedLocalAvailabilityInput, FeedAvailabilityResult } from "./feed.access";
9
+ export { checkFeedLocalAvailability, checkFeedOssAvailability } from "./feed.access";
10
+ export type { RegisterFeedInput, RegisterFeedResult } from "./feed.service";
11
+ export { registerFeed } from "./feed.service";