target-supabase-sdk 0.1.8 → 0.2.0
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/README.md +74 -6
- package/dist/auth/auth.api.d.ts.map +1 -1
- package/dist/auth/auth.api.js +2 -1
- package/dist/auth/auth.api.js.map +1 -1
- package/dist/browser.d.ts +52 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +45 -0
- package/dist/browser.js.map +1 -0
- package/dist/command/command.api.d.ts +43 -0
- package/dist/command/command.api.d.ts.map +1 -0
- package/dist/command/command.api.js +58 -0
- package/dist/command/command.api.js.map +1 -0
- package/dist/command/command.interface.d.ts +14 -0
- package/dist/command/command.interface.d.ts.map +1 -0
- package/dist/command/command.interface.js +9 -0
- package/dist/command/command.interface.js.map +1 -0
- package/dist/core.api.d.ts +70 -6
- package/dist/core.api.d.ts.map +1 -1
- package/dist/core.api.js +191 -13
- package/dist/core.api.js.map +1 -1
- package/dist/file/file-manager.d.ts +1 -1
- package/dist/file/file-manager.d.ts.map +1 -1
- package/dist/file/file-manager.js +1 -1
- package/dist/file/file-manager.js.map +1 -1
- package/dist/index.d.ts +2 -40
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -34
- package/dist/index.js.map +1 -1
- package/dist/link/link.interface.d.ts +1 -1
- package/dist/link/link.interface.d.ts.map +1 -1
- package/dist/node/node-log-scope.d.ts +11 -0
- package/dist/node/node-log-scope.d.ts.map +1 -0
- package/dist/node/node-log-scope.js +7 -0
- package/dist/node/node-log-scope.js.map +1 -0
- package/dist/node/node-runtime.base.d.ts +42 -0
- package/dist/node/node-runtime.base.d.ts.map +1 -0
- package/dist/node/node-runtime.base.js +397 -0
- package/dist/node/node-runtime.base.js.map +1 -0
- package/dist/node/node-task.preset.d.ts +1 -0
- package/dist/node/node-task.preset.d.ts.map +1 -0
- package/dist/node/node-task.preset.js +14 -0
- package/dist/node/node-task.preset.js.map +1 -0
- package/dist/node/node.api.d.ts +67 -31
- package/dist/node/node.api.d.ts.map +1 -1
- package/dist/node/node.api.js +65 -102
- package/dist/node/node.api.js.map +1 -1
- package/dist/node/node.interface.d.ts +7 -0
- package/dist/node/node.interface.d.ts.map +1 -1
- package/dist/node/node.interface.js +2 -0
- package/dist/node/node.interface.js.map +1 -1
- package/dist/node/node.utils.d.ts +5 -0
- package/dist/node/node.utils.d.ts.map +1 -0
- package/dist/node/node.utils.js +36 -0
- package/dist/node/node.utils.js.map +1 -0
- package/dist/node/task-node.d.ts +20 -0
- package/dist/node/task-node.d.ts.map +1 -0
- package/dist/node/task-node.js +245 -0
- package/dist/node/task-node.js.map +1 -0
- package/dist/node/trigger-node.d.ts +18 -0
- package/dist/node/trigger-node.d.ts.map +1 -0
- package/dist/node/trigger-node.js +150 -0
- package/dist/node/trigger-node.js.map +1 -0
- package/dist/node.d.ts +22 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +19 -0
- package/dist/node.js.map +1 -0
- package/dist/parcel/parcel-manager.d.ts +1 -1
- package/dist/parcel/parcel-manager.d.ts.map +1 -1
- package/dist/parcel/parcel-manager.js +1 -1
- package/dist/parcel/parcel-manager.js.map +1 -1
- package/dist/repo/repo-context.utils.d.ts +24 -0
- package/dist/repo/repo-context.utils.d.ts.map +1 -0
- package/dist/repo/repo-context.utils.js +81 -0
- package/dist/repo/repo-context.utils.js.map +1 -0
- package/dist/repo/repo-manager.d.ts +42 -0
- package/dist/repo/repo-manager.d.ts.map +1 -0
- package/dist/repo/repo-manager.js +166 -0
- package/dist/repo/repo-manager.js.map +1 -0
- package/dist/repo/repo.api.d.ts +16 -0
- package/dist/repo/repo.api.d.ts.map +1 -0
- package/dist/repo/repo.api.js +40 -0
- package/dist/repo/repo.api.js.map +1 -0
- package/dist/repo/repo.interface.d.ts +12 -5
- package/dist/repo/repo.interface.d.ts.map +1 -1
- package/dist/repo/repo.interface.js +2 -2
- package/dist/repo/repo.interface.js.map +1 -1
- package/dist/repo/repo.script-loader.d.ts +19 -0
- package/dist/repo/repo.script-loader.d.ts.map +1 -0
- package/dist/repo/repo.script-loader.js +108 -0
- package/dist/repo/repo.script-loader.js.map +1 -0
- package/dist/shared/log/create-api-logger.d.ts +21 -0
- package/dist/shared/log/create-api-logger.d.ts.map +1 -0
- package/dist/shared/log/create-api-logger.js +19 -0
- package/dist/shared/log/create-api-logger.js.map +1 -0
- package/dist/shared/log/index.d.ts +10 -0
- package/dist/shared/log/index.d.ts.map +1 -0
- package/dist/shared/log/index.js +10 -0
- package/dist/shared/log/index.js.map +1 -0
- package/dist/shared/log/log-manager.d.ts +93 -0
- package/dist/shared/log/log-manager.d.ts.map +1 -0
- package/dist/shared/log/log-manager.js +237 -0
- package/dist/shared/log/log-manager.js.map +1 -0
- package/dist/shared/log/log-scope.d.ts +49 -0
- package/dist/shared/log/log-scope.d.ts.map +1 -0
- package/dist/shared/log/log-scope.js +70 -0
- package/dist/shared/log/log-scope.js.map +1 -0
- package/dist/shared/utils/config-path.utils.d.ts +38 -0
- package/dist/shared/utils/config-path.utils.d.ts.map +1 -0
- package/dist/shared/utils/config-path.utils.js +85 -0
- package/dist/shared/utils/config-path.utils.js.map +1 -0
- package/dist/shared/utils/error.utils.d.ts +11 -0
- package/dist/shared/utils/error.utils.d.ts.map +1 -0
- package/dist/shared/utils/error.utils.js +15 -0
- package/dist/shared/utils/error.utils.js.map +1 -0
- package/dist/shared/utils/id.utils.d.ts +3 -0
- package/dist/shared/utils/id.utils.d.ts.map +1 -0
- package/dist/shared/utils/id.utils.js +5 -0
- package/dist/shared/utils/id.utils.js.map +1 -0
- package/dist/supabase.js +1 -1
- package/dist/supabase.js.map +1 -1
- package/dist/task/index.d.ts +15 -0
- package/dist/task/index.d.ts.map +1 -0
- package/dist/task/index.js +14 -0
- package/dist/task/index.js.map +1 -0
- package/dist/task/local-task-registry.d.ts +37 -0
- package/dist/task/local-task-registry.d.ts.map +1 -0
- package/dist/task/local-task-registry.js +214 -0
- package/dist/task/local-task-registry.js.map +1 -0
- package/dist/task/task-manager.d.ts +64 -0
- package/dist/task/task-manager.d.ts.map +1 -0
- package/dist/task/task-manager.js +196 -0
- package/dist/task/task-manager.js.map +1 -0
- package/dist/task/task-post.api.d.ts +49 -0
- package/dist/task/task-post.api.d.ts.map +1 -0
- package/dist/task/task-post.api.js +91 -0
- package/dist/task/task-post.api.js.map +1 -0
- package/dist/task/task-repo-context.d.ts +97 -0
- package/dist/task/task-repo-context.d.ts.map +1 -0
- package/dist/task/task-repo-context.js +12 -0
- package/dist/task/task-repo-context.js.map +1 -0
- package/dist/task/task-repo-validation.d.ts +46 -0
- package/dist/task/task-repo-validation.d.ts.map +1 -0
- package/dist/task/task-repo-validation.js +96 -0
- package/dist/task/task-repo-validation.js.map +1 -0
- package/dist/task/task.api.d.ts +198 -0
- package/dist/task/task.api.d.ts.map +1 -1
- package/dist/task/task.api.js +302 -1
- package/dist/task/task.api.js.map +1 -1
- package/dist/task/task.interface.d.ts +11 -2
- package/dist/task/task.interface.d.ts.map +1 -1
- package/dist/task/task.interface.js +10 -0
- package/dist/task/task.interface.js.map +1 -1
- package/dist/trigger/trigger.api.d.ts +140 -0
- package/dist/trigger/trigger.api.d.ts.map +1 -0
- package/dist/trigger/trigger.api.js +125 -0
- package/dist/trigger/trigger.api.js.map +1 -0
- package/dist/trigger/trigger.interface.d.ts +43 -0
- package/dist/trigger/trigger.interface.d.ts.map +1 -0
- package/dist/trigger/trigger.interface.js +11 -0
- package/dist/trigger/trigger.interface.js.map +1 -0
- package/dist/trigger/trigger.utils.d.ts +6 -0
- package/dist/trigger/trigger.utils.d.ts.map +1 -0
- package/dist/trigger/trigger.utils.js +39 -0
- package/dist/trigger/trigger.utils.js.map +1 -0
- package/package.json +30 -8
- package/src/auth/auth.api.ts +3 -1
- package/src/browser.ts +100 -0
- package/src/command/command.api.ts +88 -0
- package/src/command/command.interface.ts +17 -0
- package/src/core.api.ts +305 -26
- package/src/file/file-manager.ts +1 -1
- package/src/index.ts +2 -64
- package/src/link/link.interface.ts +1 -1
- package/src/node/node-log-scope.ts +15 -0
- package/src/node/node-runtime.base.ts +450 -0
- package/src/node/node-task.preset.ts +13 -0
- package/src/node/node.api.ts +95 -117
- package/src/node/node.interface.ts +8 -0
- package/src/node/node.utils.ts +36 -0
- package/src/node/task-node.ts +284 -0
- package/src/node/trigger-node.ts +180 -0
- package/src/node.ts +62 -0
- package/src/parcel/parcel-manager.ts +1 -1
- package/src/repo/repo-context.utils.ts +111 -0
- package/src/repo/repo-manager.ts +245 -0
- package/src/repo/repo.api.ts +50 -0
- package/src/repo/repo.interface.ts +13 -5
- package/src/repo/repo.script-loader.ts +140 -0
- package/src/shared/log/create-api-logger.ts +36 -0
- package/src/shared/log/index.ts +23 -0
- package/src/shared/log/log-manager.ts +335 -0
- package/src/shared/log/log-scope.ts +123 -0
- package/src/shared/utils/config-path.utils.ts +104 -0
- package/src/shared/utils/error.utils.ts +15 -0
- package/src/shared/utils/id.utils.ts +4 -0
- package/src/supabase.ts +1 -1
- package/src/task/index.ts +48 -0
- package/src/task/local-task-registry.ts +282 -0
- package/src/task/task-manager.ts +301 -0
- package/src/task/task-post.api.ts +116 -0
- package/src/task/task-repo-context.ts +105 -0
- package/src/task/task-repo-validation.ts +171 -0
- package/src/task/task.api.ts +369 -0
- package/src/task/task.interface.ts +12 -2
- package/src/trigger/trigger.api.ts +166 -0
- package/src/trigger/trigger.interface.ts +50 -0
- package/src/trigger/trigger.utils.ts +56 -0
- package/dist/task/task-node-manager.d.ts +0 -1
- package/dist/task/task-node-manager.d.ts.map +0 -1
- package/dist/task/task-node-manager.js +0 -2
- package/dist/task/task-node-manager.js.map +0 -1
- package/src/task/task-node-manager.ts +0 -0
package/src/task/task.api.ts
CHANGED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { createTarget, getPossibleTarget, QueryFilter, updateTargetDetails, validateWithSchema, isOptimisticLockError, OPTIMISTIC_LOCK_FAILED_MESSAGE } from "../core.api";
|
|
2
|
+
import { generateResponse, type SupabaseResponse } from "../core.interface";
|
|
3
|
+
import { createApiLogger, logManager, type LoggerWithScope } from "../shared/log";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { CategoryTask, ResultCode, Task, TaskDetails, TaskStatus, TaskStatusAction } from "./task.interface";
|
|
6
|
+
|
|
7
|
+
const TASK_STATUS_FIELD = "details->>status" as const;
|
|
8
|
+
const TASK_NODE_ID_FIELD = "details->>nodeId" as const;
|
|
9
|
+
|
|
10
|
+
// ─── State machine ───────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Task state machine (field: `details.status`)
|
|
14
|
+
*
|
|
15
|
+
* ```text
|
|
16
|
+
* publish claim (CLAIM / patchClaimTask) finish
|
|
17
|
+
* OPEN ──────► TODO ──────────────────► DOING ─────────────► DONE
|
|
18
|
+
* │ │ reset │ cancel │ close
|
|
19
|
+
* │ │ └──────► TODO │
|
|
20
|
+
* └──────── reset ─┴──────────────────────── reset ────────────┘
|
|
21
|
+
* | │
|
|
22
|
+
* └──────────────────── close ─────────────────────────────────┘
|
|
23
|
+
* ▼
|
|
24
|
+
* CLOSED
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* | TaskStatusAction | from | to | lock filters | caller |
|
|
28
|
+
* |------------------|-------------------|--------|--------------------------------|---------------|
|
|
29
|
+
* | PUBLISH | OPEN | TODO | status = OPEN | scheduler |
|
|
30
|
+
* | CLAIM | TODO | DOING | status = TODO | worker |
|
|
31
|
+
* | RESET | TODO | OPEN | status = TODO (no nodeId) | admin |
|
|
32
|
+
* | RESET | DOING, DONE | OPEN | status ∈ {DOING,DONE} + nodeId | worker |
|
|
33
|
+
* | CANCEL | DOING | TODO | DOING + nodeId | worker |
|
|
34
|
+
* | FINISH | DOING | DONE | DOING + nodeId | worker |
|
|
35
|
+
* | CLOSE | OPEN, DONE | CLOSED | status ∈ {OPEN, DONE} | scheduler |
|
|
36
|
+
*
|
|
37
|
+
* RESET: omit `nodeId` to reset from **TODO**; pass `nodeId` to reset from **DOING** or **DONE**.
|
|
38
|
+
*
|
|
39
|
+
* All public APIs validate input with Zod (`validateWithSchema`). Optimistic locks live in
|
|
40
|
+
* `optimisticLockFilterList` on UPDATE — see `.cursor/skills/optimistic-lock-update/SKILL.md`.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
// ─── Zod schemas ─────────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
const taskIdSchema = z.string().trim().min(1);
|
|
46
|
+
const nodeIdSchema = z.string().trim().min(1);
|
|
47
|
+
/** Optional — orchestrator (e.g. TaskNode loop) passes its trace to correlate logs. */
|
|
48
|
+
const traceIdSchema = z.string().trim().min(1).optional();
|
|
49
|
+
const traceParentIdSchema = z.string().trim().min(1).nullable().optional();
|
|
50
|
+
|
|
51
|
+
const patchChangeTaskStatusBaseSchema = {
|
|
52
|
+
id: taskIdSchema,
|
|
53
|
+
extra: z.string().optional(),
|
|
54
|
+
traceId: traceIdSchema,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/** Shared by CLAIM / CANCEL / FINISH — worker-side actions that require nodeId */
|
|
58
|
+
const patchChangeTaskStatusNodeOwnedSchema = {
|
|
59
|
+
...patchChangeTaskStatusBaseSchema,
|
|
60
|
+
nodeId: nodeIdSchema,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const patchChangeTaskStatusSchema = z.discriminatedUnion("action", [
|
|
64
|
+
z.object({
|
|
65
|
+
...patchChangeTaskStatusBaseSchema,
|
|
66
|
+
action: z.literal(TaskStatusAction.PUBLISH),
|
|
67
|
+
}),
|
|
68
|
+
z.object({
|
|
69
|
+
...patchChangeTaskStatusBaseSchema,
|
|
70
|
+
action: z.literal(TaskStatusAction.CLOSE),
|
|
71
|
+
}),
|
|
72
|
+
z.object({
|
|
73
|
+
...patchChangeTaskStatusNodeOwnedSchema,
|
|
74
|
+
action: z.literal(TaskStatusAction.CLAIM),
|
|
75
|
+
}),
|
|
76
|
+
z.object({
|
|
77
|
+
...patchChangeTaskStatusBaseSchema,
|
|
78
|
+
action: z.literal(TaskStatusAction.RESET),
|
|
79
|
+
nodeId: nodeIdSchema.optional(),
|
|
80
|
+
}),
|
|
81
|
+
z.object({
|
|
82
|
+
...patchChangeTaskStatusNodeOwnedSchema,
|
|
83
|
+
action: z.literal(TaskStatusAction.CANCEL),
|
|
84
|
+
}),
|
|
85
|
+
z.object({
|
|
86
|
+
...patchChangeTaskStatusNodeOwnedSchema,
|
|
87
|
+
action: z.literal(TaskStatusAction.FINISH),
|
|
88
|
+
cost: z.number().min(0),
|
|
89
|
+
}),
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
export type PatchChangeTaskStatusPayload = z.infer<typeof patchChangeTaskStatusSchema>;
|
|
93
|
+
|
|
94
|
+
export const patchTaskProgressSchema = z.object({
|
|
95
|
+
id: taskIdSchema,
|
|
96
|
+
progress: z.number().min(0).max(100),
|
|
97
|
+
nodeId: nodeIdSchema,
|
|
98
|
+
traceId: traceIdSchema,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
export type PatchTaskProgressPayload = z.infer<typeof patchTaskProgressSchema>;
|
|
102
|
+
|
|
103
|
+
export const patchClaimTaskSchema = z.object({
|
|
104
|
+
nodeId: nodeIdSchema,
|
|
105
|
+
availableTaskList: z.array(z.string()).min(1),
|
|
106
|
+
traceId: traceIdSchema,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
export type PatchClaimTaskPayload = z.infer<typeof patchClaimTaskSchema>;
|
|
110
|
+
|
|
111
|
+
// ─── Optimistic lock helpers ─────────────────────────────────────────────────
|
|
112
|
+
|
|
113
|
+
function lockOnStatus(...allowed: TaskStatus[]): QueryFilter[] {
|
|
114
|
+
if (allowed.length === 1) {
|
|
115
|
+
return [{ field: TASK_STATUS_FIELD, operator: "eq", value: allowed[0] }];
|
|
116
|
+
}
|
|
117
|
+
return [{ field: TASK_STATUS_FIELD, operator: "in", value: allowed }];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function lockOnOwnerNode(nodeId: string): QueryFilter {
|
|
121
|
+
return { field: TASK_NODE_ID_FIELD, operator: "eq", value: nodeId };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** DOING row owned by `nodeId` — used by FINISH, CANCEL, patchTaskProgress */
|
|
125
|
+
function lockOnDoingOwner(nodeId: string): QueryFilter[] {
|
|
126
|
+
return [...lockOnStatus(TaskStatus.DOING), lockOnOwnerNode(nodeId)];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** TODO without nodeId; DOING/DONE with owner when nodeId is provided */
|
|
130
|
+
function lockOnReset(nodeId?: string): QueryFilter[] {
|
|
131
|
+
if (nodeId != null) {
|
|
132
|
+
return [...lockOnStatus(TaskStatus.DOING, TaskStatus.DONE), lockOnOwnerNode(nodeId)];
|
|
133
|
+
}
|
|
134
|
+
return lockOnStatus(TaskStatus.TODO);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function clearExecutionState(): Pick<TaskDetails, "progress" | "nodeId" | "result"> {
|
|
138
|
+
return { progress: 0, nodeId: null, result: undefined };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── Internal transitions ────────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
async function transitionTask({
|
|
144
|
+
id,
|
|
145
|
+
optimisticLockFilterList,
|
|
146
|
+
updateFn,
|
|
147
|
+
updateExtraFn,
|
|
148
|
+
}: {
|
|
149
|
+
id: string;
|
|
150
|
+
optimisticLockFilterList: QueryFilter[];
|
|
151
|
+
updateFn: (details: TaskDetails) => TaskDetails;
|
|
152
|
+
updateExtraFn?: (existing: TaskDetails) => string;
|
|
153
|
+
}): Promise<Task> {
|
|
154
|
+
return updateTargetDetails<Task, TaskDetails>({
|
|
155
|
+
id,
|
|
156
|
+
optimisticLockFilterList,
|
|
157
|
+
updateFn,
|
|
158
|
+
updateExtraFn,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function logTaskTransition(
|
|
163
|
+
logger: LoggerWithScope,
|
|
164
|
+
action: TaskStatusAction | "patchTaskProgress" | "patchClaimTask",
|
|
165
|
+
task: Task,
|
|
166
|
+
data?: Record<string, unknown>
|
|
167
|
+
): void {
|
|
168
|
+
logger.info("任务状态迁移成功", {
|
|
169
|
+
topic: "task",
|
|
170
|
+
data: {
|
|
171
|
+
action,
|
|
172
|
+
taskId: task.id,
|
|
173
|
+
taskValue: task.value,
|
|
174
|
+
status: task.details.status,
|
|
175
|
+
nodeId: task.details.nodeId,
|
|
176
|
+
...data,
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** TODO → DOING — lock status only (no owner yet); used by CLAIM and {@link patchClaimTask} */
|
|
182
|
+
async function claimTaskById({
|
|
183
|
+
taskId,
|
|
184
|
+
nodeId,
|
|
185
|
+
updateExtraFn,
|
|
186
|
+
}: {
|
|
187
|
+
taskId: string;
|
|
188
|
+
nodeId: string;
|
|
189
|
+
updateExtraFn?: (existing: TaskDetails) => string;
|
|
190
|
+
}): Promise<Task> {
|
|
191
|
+
return transitionTask({
|
|
192
|
+
id: taskId,
|
|
193
|
+
optimisticLockFilterList: lockOnStatus(TaskStatus.TODO),
|
|
194
|
+
updateFn: (details) => ({
|
|
195
|
+
...details,
|
|
196
|
+
status: TaskStatus.DOING,
|
|
197
|
+
nodeId,
|
|
198
|
+
}),
|
|
199
|
+
updateExtraFn,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ─── patchChangeTaskStatus ───────────────────────────────────────────────────
|
|
204
|
+
|
|
205
|
+
export const patchChangeTaskStatus = validateWithSchema(
|
|
206
|
+
patchChangeTaskStatusSchema,
|
|
207
|
+
"patchChangeTaskStatusSchema"
|
|
208
|
+
)(async (params) => {
|
|
209
|
+
const logger = createApiLogger("patchChangeTaskStatus", { traceId: params.traceId });
|
|
210
|
+
const { id, action, extra } = params;
|
|
211
|
+
const updateExtraFn = extra == null ? undefined : () => extra;
|
|
212
|
+
|
|
213
|
+
switch (action) {
|
|
214
|
+
case TaskStatusAction.PUBLISH: {
|
|
215
|
+
const data = await transitionTask({
|
|
216
|
+
id,
|
|
217
|
+
optimisticLockFilterList: lockOnStatus(TaskStatus.OPEN),
|
|
218
|
+
updateFn: (details) => ({
|
|
219
|
+
...details,
|
|
220
|
+
...clearExecutionState(),
|
|
221
|
+
status: TaskStatus.TODO,
|
|
222
|
+
}),
|
|
223
|
+
updateExtraFn,
|
|
224
|
+
});
|
|
225
|
+
logTaskTransition(logger, action, data);
|
|
226
|
+
return generateResponse.success<Task>(data);
|
|
227
|
+
}
|
|
228
|
+
case TaskStatusAction.CLAIM: {
|
|
229
|
+
const { nodeId } = params;
|
|
230
|
+
const data = await claimTaskById({ taskId: id, nodeId, updateExtraFn });
|
|
231
|
+
logTaskTransition(logger, action, data);
|
|
232
|
+
return generateResponse.success<Task>(data);
|
|
233
|
+
}
|
|
234
|
+
case TaskStatusAction.RESET: {
|
|
235
|
+
const { nodeId } = params;
|
|
236
|
+
const data = await transitionTask({
|
|
237
|
+
id,
|
|
238
|
+
optimisticLockFilterList: lockOnReset(nodeId),
|
|
239
|
+
updateFn: (details) => ({
|
|
240
|
+
...details,
|
|
241
|
+
...clearExecutionState(),
|
|
242
|
+
status: TaskStatus.OPEN,
|
|
243
|
+
}),
|
|
244
|
+
updateExtraFn,
|
|
245
|
+
});
|
|
246
|
+
logTaskTransition(logger, action, data, nodeId != null ? undefined : { resetFrom: "TODO" });
|
|
247
|
+
return generateResponse.success<Task>(data);
|
|
248
|
+
}
|
|
249
|
+
case TaskStatusAction.CANCEL: {
|
|
250
|
+
const { nodeId } = params;
|
|
251
|
+
const data = await transitionTask({
|
|
252
|
+
id,
|
|
253
|
+
optimisticLockFilterList: lockOnDoingOwner(nodeId),
|
|
254
|
+
updateFn: (details) => ({
|
|
255
|
+
...details,
|
|
256
|
+
...clearExecutionState(),
|
|
257
|
+
status: TaskStatus.TODO,
|
|
258
|
+
}),
|
|
259
|
+
updateExtraFn,
|
|
260
|
+
});
|
|
261
|
+
logTaskTransition(logger, action, data);
|
|
262
|
+
return generateResponse.success<Task>(data);
|
|
263
|
+
}
|
|
264
|
+
case TaskStatusAction.CLOSE: {
|
|
265
|
+
const data = await transitionTask({
|
|
266
|
+
id,
|
|
267
|
+
optimisticLockFilterList: lockOnStatus(TaskStatus.OPEN, TaskStatus.DONE),
|
|
268
|
+
updateFn: (details) => ({
|
|
269
|
+
...details,
|
|
270
|
+
status: TaskStatus.CLOSED,
|
|
271
|
+
}),
|
|
272
|
+
updateExtraFn,
|
|
273
|
+
});
|
|
274
|
+
logTaskTransition(logger, action, data);
|
|
275
|
+
return generateResponse.success<Task>(data);
|
|
276
|
+
}
|
|
277
|
+
case TaskStatusAction.FINISH: {
|
|
278
|
+
const { cost, nodeId } = params;
|
|
279
|
+
const data = await transitionTask({
|
|
280
|
+
id,
|
|
281
|
+
optimisticLockFilterList: lockOnDoingOwner(nodeId),
|
|
282
|
+
updateFn: (details) => ({
|
|
283
|
+
...details,
|
|
284
|
+
progress: 100,
|
|
285
|
+
status: TaskStatus.DONE,
|
|
286
|
+
nodeId,
|
|
287
|
+
result: {
|
|
288
|
+
cost,
|
|
289
|
+
code: ResultCode.SUCCESS,
|
|
290
|
+
},
|
|
291
|
+
}),
|
|
292
|
+
updateExtraFn,
|
|
293
|
+
});
|
|
294
|
+
logTaskTransition(logger, action, data, { cost });
|
|
295
|
+
return generateResponse.success<Task>(data);
|
|
296
|
+
}
|
|
297
|
+
default: {
|
|
298
|
+
const _exhaustive: never = action;
|
|
299
|
+
const message = `[patchChangeTaskStatus] Unknown action: ${String(_exhaustive)}`;
|
|
300
|
+
logger.error(message, { topic: "task", data: { action: String(_exhaustive) } });
|
|
301
|
+
return generateResponse.error(message);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// ─── patchTaskProgress ───────────────────────────────────────────────────────
|
|
307
|
+
|
|
308
|
+
/** Update progress on a DOING task; only the owning node may write (see `lockOnDoingOwner`). */
|
|
309
|
+
export const patchTaskProgress = validateWithSchema(
|
|
310
|
+
patchTaskProgressSchema,
|
|
311
|
+
"patchTaskProgressSchema"
|
|
312
|
+
)(async ({ id, progress, nodeId, traceId }) => {
|
|
313
|
+
const logger = createApiLogger("patchTaskProgress", { traceId, labels: { nodeId } });
|
|
314
|
+
const data = await transitionTask({
|
|
315
|
+
id,
|
|
316
|
+
optimisticLockFilterList: lockOnDoingOwner(nodeId),
|
|
317
|
+
updateFn: (details) => ({
|
|
318
|
+
...details,
|
|
319
|
+
progress,
|
|
320
|
+
}),
|
|
321
|
+
});
|
|
322
|
+
logTaskTransition(logger, "patchTaskProgress", data, { progress });
|
|
323
|
+
return generateResponse.success<Task>(data);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// ─── patchClaimTask ──────────────────────────────────────────────────────────
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Discover and claim one TODO task for this node.
|
|
330
|
+
*
|
|
331
|
+
* Flow: filter by `availableTaskList` → {@link claimTaskById} (same as `action: CLAIM`).
|
|
332
|
+
* Equivalent to `patchChangeTaskStatus({ id, action: CLAIM, nodeId })` when `id` is already known.
|
|
333
|
+
*
|
|
334
|
+
* Returns `data: null` when no TODO task matches.
|
|
335
|
+
* Optimistic lock conflicts return `{ error }` with `code: "OPTIMISTIC_LOCK"` (not thrown).
|
|
336
|
+
*/
|
|
337
|
+
export const patchClaimTask = validateWithSchema(
|
|
338
|
+
patchClaimTaskSchema,
|
|
339
|
+
"patchClaimTaskSchema"
|
|
340
|
+
)(async ({ nodeId, availableTaskList, traceId }): Promise<SupabaseResponse<Task | null>> => {
|
|
341
|
+
const logger = createApiLogger("patchClaimTask", { traceId, labels: { nodeId } });
|
|
342
|
+
|
|
343
|
+
try {
|
|
344
|
+
const { data: possibleTask } = await getPossibleTarget({
|
|
345
|
+
filterList: [
|
|
346
|
+
{ field: "category", operator: "eq", value: CategoryTask.TASK },
|
|
347
|
+
{ field: TASK_STATUS_FIELD, operator: "eq", value: TaskStatus.TODO },
|
|
348
|
+
{ field: "value", operator: "in", value: availableTaskList },
|
|
349
|
+
],
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
if (possibleTask == null) {
|
|
353
|
+
return generateResponse.success(null);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const todoTask = possibleTask as Task;
|
|
357
|
+
const data = await claimTaskById({ taskId: todoTask.id, nodeId });
|
|
358
|
+
logTaskTransition(logger, "patchClaimTask", data);
|
|
359
|
+
return generateResponse.success(data);
|
|
360
|
+
} catch (error) {
|
|
361
|
+
if (isOptimisticLockError(error)) {
|
|
362
|
+
logger.debug("認領競爭失敗,本輪無可認領任務", { topic: "task" });
|
|
363
|
+
return generateResponse.error(OPTIMISTIC_LOCK_FAILED_MESSAGE, undefined, "OPTIMISTIC_LOCK") as SupabaseResponse<Task | null>;
|
|
364
|
+
}
|
|
365
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
366
|
+
logger.error("認領任務失敗", { topic: "task", data: { error: message } });
|
|
367
|
+
return generateResponse.error(message) as SupabaseResponse<Task | null>;
|
|
368
|
+
}
|
|
369
|
+
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Target } from "../core.interface";
|
|
2
|
-
import { Repo } from "../repo/repo.interface";
|
|
3
2
|
|
|
4
3
|
export enum CategoryTask {
|
|
5
4
|
TASK = "task",
|
|
@@ -13,6 +12,16 @@ export enum TaskStatus {
|
|
|
13
12
|
CLOSED = "CLOSED",
|
|
14
13
|
}
|
|
15
14
|
|
|
15
|
+
/** Named transitions for {@link patchChangeTaskStatus} — verb aligned with state machine edges */
|
|
16
|
+
export enum TaskStatusAction {
|
|
17
|
+
PUBLISH = "publish",
|
|
18
|
+
CLAIM = "claim",
|
|
19
|
+
RESET = "reset",
|
|
20
|
+
CANCEL = "cancel",
|
|
21
|
+
CLOSE = "close",
|
|
22
|
+
FINISH = "finish",
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
export enum ResultCode {
|
|
17
26
|
SUCCESS = 1000,
|
|
18
27
|
|
|
@@ -40,11 +49,12 @@ export interface Task extends Target {
|
|
|
40
49
|
export interface TaskDetails {
|
|
41
50
|
manifestVersion: number;
|
|
42
51
|
status: TaskStatus;
|
|
43
|
-
repo: Repo;
|
|
44
52
|
params: unknown;
|
|
45
53
|
/** [0,100] */
|
|
46
54
|
progress: number;
|
|
47
55
|
nodeId: null | string;
|
|
56
|
+
/** Task lifecycle correlation id (written at postTask). */
|
|
57
|
+
traceId?: string;
|
|
48
58
|
result?: {
|
|
49
59
|
cost: number;
|
|
50
60
|
code: ResultCode;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { createTarget, scanTargetList, updateTargetDetails, validateWithSchema } from "../core.api";
|
|
2
|
+
import { generateResponse, type SupabaseResponse } from "../core.interface";
|
|
3
|
+
import { TaskStatus } from "../task/task.interface";
|
|
4
|
+
import { createApiLogger } from "../shared/log";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import {
|
|
7
|
+
CategoryTrigger,
|
|
8
|
+
Trigger,
|
|
9
|
+
TriggerStatus,
|
|
10
|
+
type TriggerAction,
|
|
11
|
+
type TriggerSchedule,
|
|
12
|
+
} from "./trigger.interface";
|
|
13
|
+
|
|
14
|
+
const TRIGGER_STATUS_FIELD = "details->>status" as const;
|
|
15
|
+
|
|
16
|
+
const traceIdSchema = z.string().trim().min(1).optional();
|
|
17
|
+
|
|
18
|
+
const dailyScheduleSchema = z.object({
|
|
19
|
+
kind: z.literal("daily"),
|
|
20
|
+
hour: z.number().int().min(0).max(23),
|
|
21
|
+
minute: z.number().int().min(0).max(59),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const postTaskActionSchema = z.object({
|
|
25
|
+
kind: z.literal("post_task"),
|
|
26
|
+
taskTypeKey: z.string().trim().min(1),
|
|
27
|
+
taskParams: z.unknown(),
|
|
28
|
+
taskName: z.string().trim().min(1).optional(),
|
|
29
|
+
taskStatus: z.enum([TaskStatus.OPEN, TaskStatus.TODO]).optional(),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const postTriggerSchema = z.object({
|
|
33
|
+
name: z.string().trim().min(1),
|
|
34
|
+
value: z.string().trim().min(1),
|
|
35
|
+
status: z.nativeEnum(TriggerStatus).optional().default(TriggerStatus.ENABLED),
|
|
36
|
+
schedule: dailyScheduleSchema,
|
|
37
|
+
action: postTaskActionSchema,
|
|
38
|
+
tagList: z.array(z.string()).optional().default([]),
|
|
39
|
+
traceId: traceIdSchema,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export type PostTriggerPayload = z.infer<typeof postTriggerSchema>;
|
|
43
|
+
|
|
44
|
+
export const scanEnabledTriggersSchema = z.object({
|
|
45
|
+
traceId: traceIdSchema,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export type ScanEnabledTriggersPayload = z.infer<typeof scanEnabledTriggersSchema>;
|
|
49
|
+
|
|
50
|
+
export const patchTriggerFiredSchema = z.object({
|
|
51
|
+
triggerId: z.string().trim().min(1),
|
|
52
|
+
fireKey: z.string().trim().min(1),
|
|
53
|
+
expectedLastFireKey: z.string().nullable().optional(),
|
|
54
|
+
traceId: traceIdSchema,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export type PatchTriggerFiredPayload = z.infer<typeof patchTriggerFiredSchema>;
|
|
58
|
+
|
|
59
|
+
function enabledTriggerFilter() {
|
|
60
|
+
return [{ field: TRIGGER_STATUS_FIELD, operator: "eq" as const, value: TriggerStatus.ENABLED }];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** List all ENABLED triggers (Phase 1: in-memory due check). */
|
|
64
|
+
export const scanEnabledTriggers = validateWithSchema(
|
|
65
|
+
scanEnabledTriggersSchema,
|
|
66
|
+
"scanEnabledTriggersSchema"
|
|
67
|
+
)(async ({ traceId }) => {
|
|
68
|
+
const logger = createApiLogger("scanEnabledTriggers", { traceId });
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const { data: triggerList } = await scanTargetList<Trigger>({
|
|
72
|
+
category: CategoryTrigger.TRIGGER,
|
|
73
|
+
filterList: enabledTriggerFilter(),
|
|
74
|
+
orderBy: { field: "created_at", ascending: true },
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const rows = triggerList ?? [];
|
|
78
|
+
logger.info("已掃描 ENABLED Trigger", {
|
|
79
|
+
topic: "trigger",
|
|
80
|
+
data: { count: rows.length },
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return generateResponse.success(rows);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
86
|
+
return generateResponse.error(message) as SupabaseResponse<Trigger[]>;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
/** Create a trigger row (scheduler / admin). */
|
|
91
|
+
export const postTrigger = validateWithSchema(
|
|
92
|
+
postTriggerSchema,
|
|
93
|
+
"postTriggerSchema"
|
|
94
|
+
)(async ({ name, value, status, schedule, action, tagList, traceId }) => {
|
|
95
|
+
const logger = createApiLogger("postTrigger", { traceId });
|
|
96
|
+
|
|
97
|
+
const details = {
|
|
98
|
+
manifestVersion: 0,
|
|
99
|
+
status,
|
|
100
|
+
schedule: schedule as TriggerSchedule,
|
|
101
|
+
action: action as TriggerAction,
|
|
102
|
+
lastFiredAt: null,
|
|
103
|
+
lastFireKey: null,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const result = await createTarget<Trigger, PostTriggerPayload>({
|
|
107
|
+
payload: { name, value, status, schedule, action, tagList, traceId },
|
|
108
|
+
createFn: () => ({
|
|
109
|
+
name,
|
|
110
|
+
value,
|
|
111
|
+
category: CategoryTrigger.TRIGGER,
|
|
112
|
+
tagList,
|
|
113
|
+
details,
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
logger.info("Trigger 已創建", {
|
|
118
|
+
topic: "trigger",
|
|
119
|
+
data: { triggerId: result.data?.id, triggerKey: value, status },
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return result;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Mark trigger as fired for `fireKey`.
|
|
127
|
+
* When `expectedLastFireKey` is set, uses optimistic lock on that field.
|
|
128
|
+
*/
|
|
129
|
+
export const patchTriggerFired = validateWithSchema(
|
|
130
|
+
patchTriggerFiredSchema,
|
|
131
|
+
"patchTriggerFiredSchema"
|
|
132
|
+
)(async ({ triggerId, fireKey, expectedLastFireKey, traceId }) => {
|
|
133
|
+
const logger = createApiLogger("patchTriggerFired", { traceId });
|
|
134
|
+
const now = Date.now();
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const optimisticLockFilterList =
|
|
138
|
+
expectedLastFireKey != null && expectedLastFireKey !== ""
|
|
139
|
+
? [{ field: "details->>lastFireKey" as const, operator: "eq" as const, value: expectedLastFireKey }]
|
|
140
|
+
: [];
|
|
141
|
+
|
|
142
|
+
const data = await updateTargetDetails<Trigger, Trigger["details"]>({
|
|
143
|
+
id: triggerId,
|
|
144
|
+
optimisticLockFilterList,
|
|
145
|
+
updateFn: (current) => ({
|
|
146
|
+
...current,
|
|
147
|
+
lastFireKey: fireKey,
|
|
148
|
+
lastFiredAt: now,
|
|
149
|
+
}),
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
logger.success("Trigger 觸發記錄已更新", {
|
|
153
|
+
topic: "trigger",
|
|
154
|
+
data: { triggerId, fireKey },
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
return generateResponse.success(data);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
160
|
+
logger.warn("Trigger 觸發記錄更新失敗", {
|
|
161
|
+
topic: "trigger",
|
|
162
|
+
data: { triggerId, fireKey, error: message },
|
|
163
|
+
});
|
|
164
|
+
return generateResponse.error(message);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Target } from "../core.interface";
|
|
2
|
+
import { TaskStatus } from "../task/task.interface";
|
|
3
|
+
|
|
4
|
+
export enum CategoryTrigger {
|
|
5
|
+
TRIGGER = "trigger",
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export enum TriggerStatus {
|
|
9
|
+
ENABLED = "ENABLED",
|
|
10
|
+
DISABLED = "DISABLED",
|
|
11
|
+
PAUSED = "PAUSED",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Phase 1: daily fire at `hour`:`minute` UTC. */
|
|
15
|
+
export interface TriggerDailySchedule {
|
|
16
|
+
kind: "daily";
|
|
17
|
+
hour: number;
|
|
18
|
+
minute: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type TriggerSchedule = TriggerDailySchedule;
|
|
22
|
+
|
|
23
|
+
export interface TriggerPostTaskAction {
|
|
24
|
+
kind: "post_task";
|
|
25
|
+
taskTypeKey: string;
|
|
26
|
+
taskParams: unknown;
|
|
27
|
+
taskName?: string;
|
|
28
|
+
taskStatus?: TaskStatus.OPEN | TaskStatus.TODO;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type TriggerAction = TriggerPostTaskAction;
|
|
32
|
+
|
|
33
|
+
export interface Trigger extends Target {
|
|
34
|
+
/** Human readable */
|
|
35
|
+
name: string;
|
|
36
|
+
/** Unique trigger key */
|
|
37
|
+
value: string;
|
|
38
|
+
details: TriggerDetails;
|
|
39
|
+
category: CategoryTrigger;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface TriggerDetails {
|
|
43
|
+
manifestVersion: number;
|
|
44
|
+
status: TriggerStatus;
|
|
45
|
+
schedule: TriggerSchedule;
|
|
46
|
+
action: TriggerAction;
|
|
47
|
+
lastFiredAt?: number | null;
|
|
48
|
+
/** Idempotency key for the last successful fire, e.g. `daily:2026-06-18` (UTC date). */
|
|
49
|
+
lastFireKey?: string | null;
|
|
50
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Trigger, TriggerDailySchedule } from "./trigger.interface";
|
|
2
|
+
|
|
3
|
+
interface UtcDateParts {
|
|
4
|
+
year: number;
|
|
5
|
+
month: number;
|
|
6
|
+
day: number;
|
|
7
|
+
hour: number;
|
|
8
|
+
minute: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function parseUtcDateParts(now: Date): UtcDateParts {
|
|
12
|
+
return {
|
|
13
|
+
year: now.getUTCFullYear(),
|
|
14
|
+
month: now.getUTCMonth() + 1,
|
|
15
|
+
day: now.getUTCDate(),
|
|
16
|
+
hour: now.getUTCHours(),
|
|
17
|
+
minute: now.getUTCMinutes(),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function buildDailyFireKey(_schedule: TriggerDailySchedule, now: Date): string {
|
|
22
|
+
const { year, month, day } = parseUtcDateParts(now);
|
|
23
|
+
const yyyy = String(year).padStart(4, "0");
|
|
24
|
+
const mm = String(month).padStart(2, "0");
|
|
25
|
+
const dd = String(day).padStart(2, "0");
|
|
26
|
+
return `daily:${yyyy}-${mm}-${dd}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function isDailyScheduleDue(
|
|
30
|
+
schedule: TriggerDailySchedule,
|
|
31
|
+
now: Date,
|
|
32
|
+
lastFireKey: string | null | undefined
|
|
33
|
+
): boolean {
|
|
34
|
+
const parts = parseUtcDateParts(now);
|
|
35
|
+
if (parts.hour !== schedule.hour || parts.minute !== schedule.minute) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const fireKey = buildDailyFireKey(schedule, now);
|
|
39
|
+
return lastFireKey !== fireKey;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function isTriggerDue(trigger: Trigger, now: Date = new Date()): boolean {
|
|
43
|
+
const { schedule, lastFireKey } = trigger.details;
|
|
44
|
+
if (schedule.kind !== "daily") {
|
|
45
|
+
throw new Error(`Unsupported trigger schedule kind: ${String((schedule as { kind?: string }).kind)}`);
|
|
46
|
+
}
|
|
47
|
+
return isDailyScheduleDue(schedule, now, lastFireKey);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function buildFireKey(trigger: Trigger, now: Date = new Date()): string {
|
|
51
|
+
const { schedule } = trigger.details;
|
|
52
|
+
if (schedule.kind !== "daily") {
|
|
53
|
+
throw new Error(`Unsupported trigger schedule kind: ${String((schedule as { kind?: string }).kind)}`);
|
|
54
|
+
}
|
|
55
|
+
return buildDailyFireKey(schedule, now);
|
|
56
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
//# sourceMappingURL=task-node-manager.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"task-node-manager.d.ts","sourceRoot":"","sources":["../../src/task/task-node-manager.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"task-node-manager.js","sourceRoot":"","sources":["../../src/task/task-node-manager.ts"],"names":[],"mappings":""}
|
|
File without changes
|