target-supabase-sdk 0.2.23 → 0.2.24

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 (77) hide show
  1. package/README.md +3 -3
  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-Ba8S21I6.js → task-queue-C_nUaM2S.js} +202 -21
  6. package/dist/chunks/task-queue-C_nUaM2S.js.map +1 -0
  7. package/dist/link/index.d.ts +2 -0
  8. package/dist/link/index.d.ts.map +1 -1
  9. package/dist/link/link.query.d.ts +9 -0
  10. package/dist/link/link.query.d.ts.map +1 -0
  11. package/dist/node.d.ts +2 -0
  12. package/dist/node.d.ts.map +1 -1
  13. package/dist/node.js +108 -6
  14. package/dist/node.js.map +1 -1
  15. package/dist/shared/feed/feed.query.d.ts.map +1 -1
  16. package/dist/shared/idea/idea.build.d.ts +35 -0
  17. package/dist/shared/idea/idea.build.d.ts.map +1 -0
  18. package/dist/shared/idea/idea.interface.d.ts +23 -0
  19. package/dist/shared/idea/idea.interface.d.ts.map +1 -0
  20. package/dist/shared/idea/idea.normalize.d.ts +3 -0
  21. package/dist/shared/idea/idea.normalize.d.ts.map +1 -0
  22. package/dist/shared/idea/idea.parse.d.ts +3 -0
  23. package/dist/shared/idea/idea.parse.d.ts.map +1 -0
  24. package/dist/shared/idea/idea.query.d.ts +6 -0
  25. package/dist/shared/idea/idea.query.d.ts.map +1 -0
  26. package/dist/shared/idea/idea.schema.d.ts +60 -0
  27. package/dist/shared/idea/idea.schema.d.ts.map +1 -0
  28. package/dist/shared/idea/index.d.ts +15 -0
  29. package/dist/shared/idea/index.d.ts.map +1 -0
  30. package/dist/shared/idea/node/idea.hash.d.ts +3 -0
  31. package/dist/shared/idea/node/idea.hash.d.ts.map +1 -0
  32. package/dist/shared/idea/node/idea.locator.d.ts +9 -0
  33. package/dist/shared/idea/node/idea.locator.d.ts.map +1 -0
  34. package/dist/shared/idea/node/index.d.ts +3 -0
  35. package/dist/shared/idea/node/index.d.ts.map +1 -0
  36. package/dist/shared/media/media.query.d.ts.map +1 -1
  37. package/dist/shared/review/review.query.d.ts.map +1 -1
  38. package/dist/shared/utils/config-path.utils.d.ts +1 -1
  39. package/dist/shared/utils/postgrest.utils.d.ts +1 -1
  40. package/dist/task/index.d.ts +1 -1
  41. package/dist/task/local-task-registry.d.ts +1 -1
  42. package/dist/trigger/trigger.api.d.ts +6 -1
  43. package/dist/trigger/trigger.api.d.ts.map +1 -1
  44. package/package.json +1 -1
  45. package/src/browser.ts +21 -0
  46. package/src/link/index.ts +2 -0
  47. package/src/link/link.query.ts +18 -0
  48. package/src/node.ts +8 -0
  49. package/src/shared/feed/README.md +1 -1
  50. package/src/shared/feed/feed.query.ts +2 -7
  51. package/src/shared/idea/README.md +82 -0
  52. package/src/shared/idea/VALIDATION-MATRIX.md +69 -0
  53. package/src/shared/idea/idea.build.ts +160 -0
  54. package/src/shared/idea/idea.interface.ts +34 -0
  55. package/src/shared/idea/idea.normalize.ts +17 -0
  56. package/src/shared/idea/idea.parse.ts +16 -0
  57. package/src/shared/idea/idea.query.ts +16 -0
  58. package/src/shared/idea/idea.schema.ts +32 -0
  59. package/src/shared/idea/index.ts +21 -0
  60. package/src/shared/idea/node/idea.hash.ts +6 -0
  61. package/src/shared/idea/node/idea.locator.ts +61 -0
  62. package/src/shared/idea/node/index.ts +7 -0
  63. package/src/shared/media/README.md +1 -1
  64. package/src/shared/media/media.query.ts +2 -7
  65. package/src/shared/review/review.query.ts +2 -7
  66. package/src/shared/utils/config-path.utils.ts +1 -1
  67. package/src/shared/utils/postgrest.utils.ts +1 -1
  68. package/src/task/index.ts +1 -1
  69. package/src/task/local-task-registry.ts +1 -1
  70. package/src/trigger/trigger.api.ts +6 -1
  71. package/dist/chunks/task-queue-Ba8S21I6.js.map +0 -1
  72. package/dist/resource/resource.interface.d.ts +0 -20
  73. package/dist/resource/resource.interface.d.ts.map +0 -1
  74. package/dist/task/task.utils.d.ts +0 -1
  75. package/dist/task/task.utils.d.ts.map +0 -1
  76. package/src/resource/resource.interface.ts +0 -37
  77. package/src/task/task.utils.ts +0 -0
@@ -0,0 +1,160 @@
1
+ import type { TargetDraft } from "../../core.interface";
2
+ import { buildLinkTargetDraft } from "../../link/link.build";
3
+ import type { Link } from "../../link/link.interface";
4
+ import {
5
+ IDEA_IMAGE_LINK_NAME,
6
+ IDEA_IMAGE_TAG_RAW,
7
+ IDEA_LINK_VALUE,
8
+ type IdeaOriginal,
9
+ isIdeaImageLinkName,
10
+ } from "./idea.interface";
11
+ import { normalizeStringList } from "./idea.normalize";
12
+
13
+ export interface BuildIdeaLinkDraftInput {
14
+ /** Article title — Link.name (not used for image ideas). */
15
+ name: string;
16
+ /** Body or image content hash — `details.original.content`. */
17
+ content: string;
18
+ reviewList?: readonly string[];
19
+ url?: string;
20
+ heat?: number;
21
+ tagList?: readonly string[];
22
+ description?: string;
23
+ preview?: string;
24
+ }
25
+
26
+ export interface BuildIdeaImageLinkDraftInput {
27
+ /** SHA-256 hex of image bytes — stored in `details.original.content`. */
28
+ contentHash: string;
29
+ /** Temp download or other absolute URL — `details.original.url`. */
30
+ url: string;
31
+ heat?: number;
32
+ tagList?: readonly string[];
33
+ description?: string;
34
+ preview?: string;
35
+ }
36
+
37
+ function resolveIdeaOriginal(input: {
38
+ content: string;
39
+ reviewList?: readonly string[];
40
+ url?: string;
41
+ heat?: number;
42
+ }): IdeaOriginal {
43
+ const content = input.content.trim();
44
+ if (content === "") {
45
+ throw new Error("buildIdeaLinkDraft: content is empty");
46
+ }
47
+ if (content.length > 100_000) {
48
+ throw new Error("buildIdeaLinkDraft: content exceeds 100000 characters");
49
+ }
50
+
51
+ const url = input.url?.trim() ?? "";
52
+ if (url.length > 2000) {
53
+ throw new Error("buildIdeaLinkDraft: url exceeds 2000 characters");
54
+ }
55
+
56
+ const reviewList = normalizeStringList(input.reviewList);
57
+ if (reviewList.length > 32) {
58
+ throw new Error("buildIdeaLinkDraft: reviewList exceeds 32 entries");
59
+ }
60
+ for (const entry of reviewList) {
61
+ if (entry.length > 8000) {
62
+ throw new Error("buildIdeaLinkDraft: reviewList entry exceeds 8000 characters");
63
+ }
64
+ }
65
+
66
+ return {
67
+ content,
68
+ reviewList,
69
+ url,
70
+ heat: Math.max(0, Math.floor(input.heat ?? 0)),
71
+ };
72
+ }
73
+
74
+ /**
75
+ * Assemble a text idea {@link Link} draft (`category=link`, `loaderKey === value === "idea"`).
76
+ * Does not write to Supabase or enforce title uniqueness.
77
+ */
78
+ export function buildIdeaLinkDraft(input: BuildIdeaLinkDraftInput): TargetDraft<Link> {
79
+ const name = input.name.trim();
80
+ if (name === "") {
81
+ throw new Error("buildIdeaLinkDraft: name is empty");
82
+ }
83
+ if (name.length > 500) {
84
+ throw new Error("buildIdeaLinkDraft: name exceeds 500 characters");
85
+ }
86
+ if (isIdeaImageLinkName(name)) {
87
+ throw new Error("buildIdeaLinkDraft: name is reserved for image ideas; use buildIdeaImageLinkDraft");
88
+ }
89
+
90
+ const tagList = normalizeStringList(input.tagList);
91
+ if (tagList.length > 32) {
92
+ throw new Error("buildIdeaLinkDraft: tagList exceeds 32 entries");
93
+ }
94
+ for (const tag of tagList) {
95
+ if (tag.length > 128) {
96
+ throw new Error("buildIdeaLinkDraft: tag exceeds 128 characters");
97
+ }
98
+ }
99
+
100
+ const original = resolveIdeaOriginal({
101
+ content: input.content,
102
+ reviewList: input.reviewList,
103
+ url: input.url,
104
+ heat: input.heat,
105
+ });
106
+
107
+ return buildLinkTargetDraft({
108
+ name,
109
+ value: IDEA_LINK_VALUE,
110
+ description: input.description ?? "",
111
+ preview: input.preview ?? "",
112
+ loaderKey: IDEA_LINK_VALUE,
113
+ tagList,
114
+ original,
115
+ });
116
+ }
117
+
118
+ /**
119
+ * Assemble a clipboard-image idea Link (`name=idea.image`, `value=idea`).
120
+ * Caller stores bytes and supplies hash + temp URL; no dedup by content hash.
121
+ */
122
+ export function buildIdeaImageLinkDraft(input: BuildIdeaImageLinkDraftInput): TargetDraft<Link> {
123
+ const contentHash = input.contentHash.trim();
124
+ if (contentHash === "") {
125
+ throw new Error("buildIdeaImageLinkDraft: contentHash is empty");
126
+ }
127
+ if (contentHash.length > 100_000) {
128
+ throw new Error("buildIdeaImageLinkDraft: contentHash exceeds 100000 characters");
129
+ }
130
+
131
+ const url = input.url.trim();
132
+ if (url === "") {
133
+ throw new Error("buildIdeaImageLinkDraft: url is empty");
134
+ }
135
+ if (url.length > 2000) {
136
+ throw new Error("buildIdeaImageLinkDraft: url exceeds 2000 characters");
137
+ }
138
+
139
+ const tagList = normalizeStringList(input.tagList ?? [IDEA_IMAGE_TAG_RAW]);
140
+ if (tagList.length === 0) {
141
+ throw new Error("buildIdeaImageLinkDraft: tagList is empty");
142
+ }
143
+
144
+ const original: IdeaOriginal = {
145
+ content: contentHash,
146
+ reviewList: [],
147
+ url,
148
+ heat: Math.max(0, Math.floor(input.heat ?? 0)),
149
+ };
150
+
151
+ return buildLinkTargetDraft({
152
+ name: IDEA_IMAGE_LINK_NAME,
153
+ value: IDEA_LINK_VALUE,
154
+ description: input.description ?? "",
155
+ preview: input.preview ?? "",
156
+ loaderKey: IDEA_LINK_VALUE,
157
+ tagList,
158
+ original,
159
+ });
160
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Idea Link protocol — Link rows with `value` / `loaderKey` === {@link IDEA_LINK_VALUE}.
3
+ * Clipboard images use fixed `name` {@link IDEA_IMAGE_LINK_NAME} (not a separate value).
4
+ */
5
+
6
+ export const IDEA_LINK_VALUE = "idea" as const;
7
+
8
+ /** Discriminator stored in both `Link.value` and `details.loaderKey`. */
9
+ export type IdeaLinkValue = typeof IDEA_LINK_VALUE;
10
+
11
+ /** Link.name for clipboard-image ideas (distinct from title-based text ideas). */
12
+ export const IDEA_IMAGE_LINK_NAME = "idea.image" as const;
13
+
14
+ /** Default tag for raw captures (quick-note, paste-image). Leading `.` = system tag. */
15
+ export const IDEA_IMAGE_TAG_RAW = ".raw" as const;
16
+
17
+ /** Temp sandbox prefix for pasted images (`TEMP_FS_ROOT` on upload-service). */
18
+ export const IDEA_IMAGE_TEMP_DIR = "idea/paste" as const;
19
+
20
+ /** `Link.details.original` for idea Links (text and image). */
21
+ export interface IdeaOriginal {
22
+ content: string;
23
+ reviewList: string[];
24
+ url: string;
25
+ heat: number;
26
+ }
27
+
28
+ export function isIdeaLinkValue(value: string): value is IdeaLinkValue {
29
+ return value === IDEA_LINK_VALUE;
30
+ }
31
+
32
+ export function isIdeaImageLinkName(name: string): boolean {
33
+ return name.trim() === IDEA_IMAGE_LINK_NAME;
34
+ }
@@ -0,0 +1,17 @@
1
+ /** Trim, dedupe, and drop empty strings from tag/review lists. */
2
+ export function normalizeStringList(raw: readonly string[] | undefined | null): string[] {
3
+ if (raw == null || raw.length === 0) {
4
+ return [];
5
+ }
6
+ const seen = new Set<string>();
7
+ const out: string[] = [];
8
+ for (const item of raw) {
9
+ const text = item.trim();
10
+ if (text === "" || seen.has(text)) {
11
+ continue;
12
+ }
13
+ seen.add(text);
14
+ out.push(text);
15
+ }
16
+ return out;
17
+ }
@@ -0,0 +1,16 @@
1
+ import type { IdeaOriginal } from "./idea.interface";
2
+ import { normalizeStringList } from "./idea.normalize";
3
+ import { ideaOriginalSchema } from "./idea.schema";
4
+
5
+ export function parseIdeaOriginal(original: unknown): IdeaOriginal | null {
6
+ const parsed = ideaOriginalSchema.safeParse(original);
7
+ if (!parsed.success) {
8
+ return null;
9
+ }
10
+ return {
11
+ content: parsed.data.content,
12
+ reviewList: normalizeStringList(parsed.data.reviewList),
13
+ url: parsed.data.url,
14
+ heat: parsed.data.heat,
15
+ };
16
+ }
@@ -0,0 +1,16 @@
1
+ import type { QueryFilter } from "../../core.interface";
2
+ import { CategoryLink } from "../../link/link.interface";
3
+ import { IDEA_IMAGE_LINK_NAME, IDEA_LINK_VALUE } from "./idea.interface";
4
+
5
+ /** List/get filters: `category=link` and `value=idea` (do not filter on `details.loaderKey`). */
6
+ export function ideaLinkValueFilters(): QueryFilter[] {
7
+ return [
8
+ { field: "category", operator: "eq", value: CategoryLink.LINK },
9
+ { field: "value", operator: "eq", value: IDEA_LINK_VALUE },
10
+ ];
11
+ }
12
+
13
+ /** Clipboard-image ideas only (`name=idea.image`). */
14
+ export function ideaImageLinkFilters(): QueryFilter[] {
15
+ return [...ideaLinkValueFilters(), { field: "name", operator: "eq", value: IDEA_IMAGE_LINK_NAME }];
16
+ }
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+
3
+ /** Runtime shape of `Link.details.original` for value=idea. */
4
+ export const ideaOriginalSchema = z.object({
5
+ content: z.string().trim().min(1).max(100_000),
6
+ reviewList: z.array(z.string().trim().min(1).max(8000)).max(32).default([]),
7
+ url: z.string().trim().max(2000).default(""),
8
+ heat: z.number().int().min(0).default(0),
9
+ });
10
+
11
+ const ideaTagSchema = z.string().trim().min(1).max(128);
12
+
13
+ /** HTTP / API create body limits (upload-service `POST /v0/upload/idea`). */
14
+ export const ideaCreateSchema = z.object({
15
+ name: z.string().trim().min(1, "name is required").max(500),
16
+ content: z.string().trim().min(1, "content is required").max(100_000),
17
+ reviewList: z.array(z.string().trim().min(1).max(8000)).max(32).default([]),
18
+ url: z.string().trim().max(2000).default(""),
19
+ tagList: z.array(ideaTagSchema).max(32).default([]),
20
+ });
21
+
22
+ export type IdeaCreateSchemaInput = z.infer<typeof ideaCreateSchema>;
23
+
24
+ export const ideaUpdateSchema = z.object({
25
+ name: z.string().trim().min(1).max(500).optional(),
26
+ content: z.string().trim().min(1).max(100_000).optional(),
27
+ reviewList: z.array(z.string().trim().min(1).max(8000)).max(32).optional(),
28
+ url: z.string().trim().max(2000).optional(),
29
+ tagList: z.array(ideaTagSchema).max(32).optional(),
30
+ });
31
+
32
+ export type IdeaUpdateSchemaInput = z.infer<typeof ideaUpdateSchema>;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Idea Link — browser-safe public barrel only.
3
+ *
4
+ * Node-only code lives in `./node/` and is exported from `src/node.ts`.
5
+ */
6
+
7
+ export type { BuildIdeaImageLinkDraftInput, BuildIdeaLinkDraftInput } from "./idea.build";
8
+ export { buildIdeaImageLinkDraft, buildIdeaLinkDraft } from "./idea.build";
9
+ export type { IdeaOriginal } from "./idea.interface";
10
+ export {
11
+ IDEA_IMAGE_LINK_NAME,
12
+ IDEA_IMAGE_TAG_RAW,
13
+ IDEA_IMAGE_TEMP_DIR,
14
+ IDEA_LINK_VALUE,
15
+ isIdeaImageLinkName,
16
+ } from "./idea.interface";
17
+ export { normalizeStringList } from "./idea.normalize";
18
+ export { parseIdeaOriginal } from "./idea.parse";
19
+ export { ideaLinkValueFilters } from "./idea.query";
20
+ export type { IdeaCreateSchemaInput, IdeaUpdateSchemaInput } from "./idea.schema";
21
+ export { ideaCreateSchema, ideaUpdateSchema } from "./idea.schema";
@@ -0,0 +1,6 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ /** SHA-256 hex of image bytes (filename + `details.original.content` for paste-image ideas). */
4
+ export function hashIdeaPasteImage(buffer: Buffer): string {
5
+ return createHash("sha256").update(buffer).digest("hex");
6
+ }
@@ -0,0 +1,61 @@
1
+ import { IDEA_IMAGE_TEMP_DIR } from "../idea.interface";
2
+
3
+ /** Path suffix on upload-service public URL for temp file download. */
4
+ export const IDEA_TEMP_DOWNLOAD_PATH_SUFFIX = "/v0/upload/temp/download";
5
+
6
+ /** Flat path under temp sandbox: `idea/paste/{sha256}.{ext}`. */
7
+ export function buildIdeaPasteRelativePath(contentHash: string, ext: string): string {
8
+ const hash = contentHash.trim();
9
+ const extension = ext.trim().replace(/^\./, "");
10
+ if (hash === "" || extension === "") {
11
+ throw new Error("buildIdeaPasteRelativePath: contentHash and ext are required");
12
+ }
13
+ return `${IDEA_IMAGE_TEMP_DIR}/${hash}.${extension}`;
14
+ }
15
+
16
+ function normalizeRelativeSandboxPath(path: string): string | null {
17
+ const normalized = path.replace(/\\/g, "/").trim();
18
+ if (normalized === "" || normalized.startsWith("/") || normalized.includes("..")) {
19
+ return null;
20
+ }
21
+ return normalized;
22
+ }
23
+
24
+ /** Build absolute locator stored in `details.original.url`. */
25
+ export function buildIdeaTempDownloadLocator(relativePath: string, publicBaseUrl: string): string {
26
+ const sanitized = normalizeRelativeSandboxPath(relativePath);
27
+ if (sanitized == null) {
28
+ throw new Error("buildIdeaTempDownloadLocator: invalid relativePath");
29
+ }
30
+ const base = publicBaseUrl.trim().replace(/\/+$/, "");
31
+ const url = new URL(`${base}${IDEA_TEMP_DOWNLOAD_PATH_SUFFIX}`);
32
+ url.searchParams.set("path", sanitized);
33
+ return url.href;
34
+ }
35
+
36
+ /** Parse temp download URL → sandbox-relative path, or null when not a temp download URL. */
37
+ export function parseIdeaTempDownloadLocator(locator: string): string | null {
38
+ const trimmed = locator.trim();
39
+ if (trimmed === "") {
40
+ return null;
41
+ }
42
+
43
+ let parsed: URL;
44
+ try {
45
+ parsed = new URL(trimmed, "http://localhost");
46
+ } catch {
47
+ return null;
48
+ }
49
+
50
+ const pathname = parsed.pathname.replace(/\\/g, "/");
51
+ if (!pathname.endsWith(IDEA_TEMP_DOWNLOAD_PATH_SUFFIX)) {
52
+ return null;
53
+ }
54
+
55
+ const pathParam = parsed.searchParams.get("path");
56
+ if (pathParam == null || pathParam.trim() === "") {
57
+ return null;
58
+ }
59
+
60
+ return normalizeRelativeSandboxPath(pathParam.trim());
61
+ }
@@ -0,0 +1,7 @@
1
+ export { hashIdeaPasteImage } from "./idea.hash";
2
+ export {
3
+ buildIdeaPasteRelativePath,
4
+ buildIdeaTempDownloadLocator,
5
+ IDEA_TEMP_DOWNLOAD_PATH_SUFFIX,
6
+ parseIdeaTempDownloadLocator,
7
+ } from "./idea.locator";
@@ -106,4 +106,4 @@ Internal SDK code:
106
106
 
107
107
  Cross-host `storageProvider` cannot be verified on the current process — availability returns `ok: false`.
108
108
 
109
- See `.cursor/skills/media-link/SKILL.md`.
109
+ See `.cursor/skills/link-conventions/SKILL.md`.
@@ -1,13 +1,8 @@
1
1
  import type { QueryFilter } from "../../core.interface";
2
- import { CategoryLink } from "../../link/link.interface";
2
+ import { linkDedupFilters } from "../../link/link.query";
3
3
  import type { MediaValue } from "./media.interface";
4
4
 
5
5
  /** Dedup key: `category=link` + `value` + `name` (matches register / find). */
6
6
  export function mediaLinkDedupFilters(input: { value: MediaValue; name: string }): QueryFilter[] {
7
- const name = input.name.trim();
8
- return [
9
- { field: "category", operator: "eq", value: CategoryLink.LINK },
10
- { field: "value", operator: "eq", value: input.value },
11
- { field: "name", operator: "eq", value: name },
12
- ];
7
+ return linkDedupFilters(input);
13
8
  }
@@ -1,5 +1,5 @@
1
1
  import type { QueryFilter } from "../../core.interface";
2
- import { CategoryLink } from "../../link/link.interface";
2
+ import { linkDedupFilters } from "../../link/link.query";
3
3
  import { REVIEW_VALUE } from "./review.interface";
4
4
 
5
5
  /**
@@ -7,10 +7,5 @@ import { REVIEW_VALUE } from "./review.interface";
7
7
  * Many rows may match — the SDK does not define dedup for reviews.
8
8
  */
9
9
  export function reviewLinksForNameFilters(name: string): QueryFilter[] {
10
- const trimmed = name.trim();
11
- return [
12
- { field: "category", operator: "eq", value: CategoryLink.LINK },
13
- { field: "value", operator: "eq", value: REVIEW_VALUE },
14
- { field: "name", operator: "eq", value: trimmed },
15
- ];
10
+ return linkDedupFilters({ value: REVIEW_VALUE, name });
16
11
  }
@@ -15,7 +15,7 @@ export function getConfigFileDir(configFilePath: string): string {
15
15
  * - Absolute `pathInConfig` → returned as-is
16
16
  * - Relative `pathInConfig` → `resolve(dirname(configFilePath), pathInConfig)`
17
17
  *
18
- * **Not** relative to `process.cwd()`. See `.cursor/skills/config-file-relative-paths/SKILL.md`.
18
+ * **Not** relative to `process.cwd()`. See `.cursor/skills/task-local-discovery/SKILL.md`.
19
19
  */
20
20
  export function resolvePathFromConfigFile(configFilePath: string, pathInConfig: string): string {
21
21
  const trimmed = pathInConfig.trim();
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * PostgREST / Supabase JS client helpers for `target` table filters.
3
3
  *
4
- * @see `.cursor/skills/postgrest-query-filters/SKILL.md`
4
+ * @see `.cursor/skills/target-list-query/SKILL.md`
5
5
  */
6
6
 
7
7
  /**
package/src/task/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Task domain public API — curated re-exports only.
3
- * Internal modules (local-task-registry, task-repo-context, task.utils) stay private.
3
+ * Internal modules (local-task-registry, task-repo-context) stay private.
4
4
  */
5
5
 
6
6
  export type {
@@ -244,7 +244,7 @@ async function runBootstrapScan(options: BootstrapLocalTasksOptions): Promise<Bo
244
244
  * ./tasks/my-task/index.mjs
245
245
  * ```
246
246
  *
247
- * `taskDir` / `entry` paths are relative to **their config file's directory** (see config-file-relative-paths skill).
247
+ * `taskDir` / `entry` paths are relative to **their config file's directory** (see task-local-discovery skill).
248
248
  *
249
249
  * Legacy fallback: `./task.config.js` at project root (`taskDir: "./tasks"`).
250
250
  */
@@ -60,7 +60,12 @@ function enabledTriggerFilter() {
60
60
  return [{ field: TRIGGER_STATUS_FIELD, operator: "eq" as const, value: TriggerStatus.ENABLED }];
61
61
  }
62
62
 
63
- /** List all ENABLED triggers (Phase 1: in-memory due check). */
63
+ /**
64
+ * List all ENABLED triggers. Due-check is in-memory on the caller:
65
+ * filter with `isTriggerDue`, then `patchTriggerFired` with `buildFireKey`
66
+ * (both from `trigger.utils`, exported on `/node`).
67
+ * Do not call this from TriggerNode (local interval runners only).
68
+ */
64
69
  export const scanEnabledTriggers = validateWithSchema(
65
70
  scanEnabledTriggersSchema,
66
71
  "scanEnabledTriggersSchema",