target-supabase-sdk 0.2.6 → 0.2.8
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 +4 -0
- package/dist/browser.js +2 -2
- package/dist/chunks/{enable-log-persist-BL2FaGQp.js → enable-log-persist-CKxXtE3K.js} +2 -2
- package/dist/chunks/{enable-log-persist-BL2FaGQp.js.map → enable-log-persist-CKxXtE3K.js.map} +1 -1
- package/dist/chunks/{list.api-Ab9v8yOg.js → list.api-6Q4_-7oN.js} +68 -22
- package/dist/chunks/list.api-6Q4_-7oN.js.map +1 -0
- package/dist/chunks/{task-queue-D_7kYBx3.js → task-queue-D5uWjqVN.js} +3 -2
- package/dist/chunks/task-queue-D5uWjqVN.js.map +1 -0
- package/dist/core.api.d.ts +52 -2
- package/dist/core.api.d.ts.map +1 -1
- package/dist/node.js +6 -6
- package/dist/preload.js +2 -2
- package/dist/service/config.api.d.ts.map +1 -1
- package/package.json +3 -1
- package/src/core.api.ts +143 -46
- package/src/service/config.api.ts +1 -0
- package/dist/chunks/list.api-Ab9v8yOg.js.map +0 -1
- package/dist/chunks/task-queue-D_7kYBx3.js.map +0 -1
package/dist/core.api.d.ts
CHANGED
|
@@ -112,13 +112,61 @@ export declare const postTarget: (payload: PostTargetPayload) => Promise<import(
|
|
|
112
112
|
export interface PatchTargetPayload extends PostTargetPayload {
|
|
113
113
|
id: string;
|
|
114
114
|
}
|
|
115
|
+
export declare const OPTIMISTIC_LOCK_FAILED_MESSAGE = "[updateTargetDetails] Optimistic lock failed: target no longer matches expected state.";
|
|
116
|
+
/** Thrown when UPDATE matched no row and the target id is gone (or no locks were used). */
|
|
117
|
+
export declare const UPDATE_TARGET_NOT_FOUND_MESSAGE = "[updateTarget] Target not found or was deleted.";
|
|
118
|
+
/**
|
|
119
|
+
* @deprecated Use {@link updateTarget} (narrow RMW + optimistic lock) or {@link updateTargetDetails}.
|
|
120
|
+
*
|
|
121
|
+
* Full-row rewrite of create-shaped fields. Forces callers to resupply name/value/category,
|
|
122
|
+
* has no optimistic lock, and can accidentally mutate identity columns. Unused in-tree.
|
|
123
|
+
*/
|
|
115
124
|
export declare const patchTarget: ({ id, ...restPayload }: PatchTargetPayload) => Promise<import("./core.interface").SupabaseResponse<Target>>;
|
|
125
|
+
/** Mutable Target columns allowed by {@link updateTarget} (identity fields excluded). */
|
|
126
|
+
export interface UpdateTargetRowSnapshot<D> {
|
|
127
|
+
tagList: string[];
|
|
128
|
+
details: D;
|
|
129
|
+
extra?: string;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Narrow patch returned by `updateTarget` updateFn.
|
|
133
|
+
* Omitted keys are left unchanged on the row.
|
|
134
|
+
*/
|
|
135
|
+
export type UpdateTargetPatch<D> = {
|
|
136
|
+
tagList?: string[];
|
|
137
|
+
details?: D;
|
|
138
|
+
extra?: string;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Read-modify-write mutable Target columns (`tagList` / `details` / `extra`) with optional
|
|
142
|
+
* DB-level optimistic locking. Does not write `name` / `value` / `category`.
|
|
143
|
+
*
|
|
144
|
+
* Prefer this when the update may touch `tagList` (and optionally `details`/`extra`) in one UPDATE.
|
|
145
|
+
* For details-only flows, {@link updateTargetDetails} remains the thinner API.
|
|
146
|
+
*/
|
|
147
|
+
export interface UpdateTargetParams<D> {
|
|
148
|
+
/** Target row id. */
|
|
149
|
+
id: string;
|
|
150
|
+
/**
|
|
151
|
+
* Builds a narrow patch from the row fetched immediately before UPDATE.
|
|
152
|
+
* Only returned keys are written; omit a key to leave that column unchanged.
|
|
153
|
+
*/
|
|
154
|
+
updateFn: (existing: UpdateTargetRowSnapshot<D>) => UpdateTargetPatch<D>;
|
|
155
|
+
/**
|
|
156
|
+
* Optimistic lock conditions applied on UPDATE (not on the prior SELECT).
|
|
157
|
+
* Same semantics as {@link UpdateTargetDetailsParams.optimisticLockFilterList}.
|
|
158
|
+
*/
|
|
159
|
+
optimisticLockFilterList?: QueryFilter[];
|
|
160
|
+
}
|
|
161
|
+
export declare const updateTarget: <T, D>({ id, updateFn, optimisticLockFilterList }: UpdateTargetParams<D>) => Promise<T>;
|
|
116
162
|
/**
|
|
117
163
|
* Read-modify-write `target.details` with optional DB-level optimistic locking on UPDATE.
|
|
118
164
|
*
|
|
119
165
|
* Do not use application-layer pre-update validators (e.g. checking state after SELECT then
|
|
120
166
|
* UPDATE with only `id`). That pattern is not atomic and loses under concurrency. Pass expected
|
|
121
167
|
* row conditions via `optimisticLockFilterList` so they are applied on the UPDATE statement.
|
|
168
|
+
*
|
|
169
|
+
* For updates that also need `tagList`, use {@link updateTarget}.
|
|
122
170
|
*/
|
|
123
171
|
export interface UpdateTargetDetailsParams<D> {
|
|
124
172
|
/** Target row id. */
|
|
@@ -139,12 +187,14 @@ export interface UpdateTargetDetailsParams<D> {
|
|
|
139
187
|
* write and could not prevent concurrent overwrites. These filters become part of the UPDATE
|
|
140
188
|
* WHERE clause (via `applyQueryFilters`), e.g. `{ field: "details->>status", operator: "eq", value: "TODO" }`.
|
|
141
189
|
*
|
|
142
|
-
* If no row matches after UPDATE
|
|
190
|
+
* If no row matches after UPDATE:
|
|
191
|
+
* - empty locks → not-found (`UPDATE_TARGET_NOT_FOUND_MESSAGE`)
|
|
192
|
+
* - non-empty locks → re-SELECT by id; gone → not-found, still present → `OPTIMISTIC_LOCK_FAILED_MESSAGE`
|
|
193
|
+
* Empty array = update by id only.
|
|
143
194
|
*/
|
|
144
195
|
optimisticLockFilterList?: QueryFilter[];
|
|
145
196
|
}
|
|
146
197
|
export declare const updateTargetDetails: <T, D>({ id, updateFn, updateExtraFn, optimisticLockFilterList, }: UpdateTargetDetailsParams<D>) => Promise<T>;
|
|
147
|
-
export declare const OPTIMISTIC_LOCK_FAILED_MESSAGE = "[updateTargetDetails] Optimistic lock failed: target no longer matches expected state.";
|
|
148
198
|
export declare const OPTIMISTIC_LOCK_ERROR_CODE: "OPTIMISTIC_LOCK";
|
|
149
199
|
export declare function isOptimisticLockError(error: unknown): boolean;
|
|
150
200
|
export declare function isOptimisticLockResponse(error: {
|
package/dist/core.api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.api.d.ts","sourceRoot":"","sources":["../src/core.api.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"core.api.d.ts","sourceRoot":"","sources":["../src/core.api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,KAAK,EAAY,OAAO,EAAE,MAAM,KAAK,CAAC;AAC7C,OAAO,EAAoB,KAAK,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACnF,OAAO,EAAE,aAAa,EAAuB,MAAM,cAAc,CAAC;AAGlE,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC;IAC9B,KAAK,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,uDAAuD;AACvD,eAAO,MAAM,yBAAyB,MAA4B,CAAC;AAKnE,MAAM,MAAM,mBAAmB,GAAG,sBAAsB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AA2F7F,MAAM,WAAW,YAAY;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC5B,UAAU,CAAC,EAAE,WAAW,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,YAAY,CAAC;CAC1B;AAED,eAAO,MAAM,SAAS,uBAA8B;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,WAAW,EAAE,CAAA;CAAE,iEAW7F,CAAC;AAEF,eAAO,MAAM,iBAAiB,mBAA0B;IAAE,UAAU,EAAE,WAAW,EAAE,CAAA;CAAE,wEAQpF,CAAC;AAEF,MAAM,WAAW,mBAAoB,SAAQ,eAAe;IACxD,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7B,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8FAA8F;IAC9F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACvC;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,GAAU,CAAC,SAAS,MAAM,sGASjD,mBAAmB,8DAuBrB,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACjC,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7B,UAAU,CAAC,EAAE,WAAW,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,GAAU,CAAC,SAAS,MAAM,qFAOlD,oBAAoB,8DA8CtB,CAAC;AAEF,MAAM,WAAW,yBAA0B,SAAQ,eAAe;IAC9D,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7B,2EAA2E;IAC3E,aAAa,CAAC,EAAE,mBAAmB,CAAC;CACvC;AACD,eAAO,MAAM,mBAAmB,4CAAwD,yBAAyB,iEAehH,CAAC;AAUF,MAAM,WAAW,oBAAoB;IACjC,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,WAAW,EAAE,CAAC;IAC3B,4DAA4D;IAC5D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,GAAU,CAAC,SAAS,MAAM,qEAMlD,oBAAoB,8DA4BtB,CAAC;AAEF,eAAO,MAAM,YAAY,uBAA8B;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,WAAW,EAAE,CAAA;CAAE,kEAgBhG,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;CAC/B;AAeD,eAAO,MAAM,UAAU,YAAmB,iBAAiB,iEAa1D,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IACzD,EAAE,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,8BAA8B,2FACiD,CAAC;AAE7F,2FAA2F;AAC3F,eAAO,MAAM,+BAA+B,oDAAoD,CAAC;AAEjG;;;;;GAKG;AACH,eAAO,MAAM,WAAW,2BAAkC,kBAAkB,iEA0B3E,CAAC;AAEF,yFAAyF;AACzF,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACjC,qBAAqB;IACrB,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,QAAQ,EAAE,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC,CAAC,KAAK,iBAAiB,CAAC,CAAC,CAAC,CAAC;IACzE;;;OAGG;IACH,wBAAwB,CAAC,EAAE,WAAW,EAAE,CAAC;CAC5C;AAED,eAAO,MAAM,YAAY,GAAU,CAAC,EAAE,CAAC,8CAAmD,kBAAkB,CAAC,CAAC,CAAC,eA0E9G,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,WAAW,yBAAyB,CAAC,CAAC;IACxC,qBAAqB;IACrB,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC;IAC7B;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,MAAM,CAAC;IACxC;;;;;;;;;;;OAWG;IACH,wBAAwB,CAAC,EAAE,WAAW,EAAE,CAAC;CAC5C;AAED,eAAO,MAAM,mBAAmB,GAAU,CAAC,EAAE,CAAC,8DAK3C,yBAAyB,CAAC,CAAC,CAAC,eAe9B,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAG,iBAA0B,CAAC;AAErE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE7D;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE7F;AAED,eAAO,MAAM,oCAAoC,yCAAyC,CAAC;AAQ3F,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAExE;AAqBD;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAU,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,wEAMlE;IACC,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,CAAC,EAAE,UAAU,aAAa,CAAC,CAAC,CAAC,CAAC;IACvC,QAAQ,EAAE,CAAC,YAAY,EAAE,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC;IAC9C,yFAAyF;IACzF,yBAAyB,CAAC,EAAE,WAAW,EAAE,CAAC;IAC1C;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB,4DA4CA,CAAC;AAEF,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,UAAU,CAAC,IAC1F,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,eAChB,CAAC,KAAG,CAAC,CAK7B;AAeD,2FAA2F;AAC3F,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,SAAW,IAE1E,CAAC,MAAM,CAAC,YAAY,cAAQ,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,gCACzB,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAQ/C"}
|
package/dist/node.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { M as MAX_POLL_TARGET_LIST_SIZE,
|
|
3
|
-
export { B as BaseValidator, C as CREATE_TARGET_ALREADY_EXISTS_MESSAGE, a as CategoryList, L as LOG_BATCH_LOADER_KEY, b as LOG_PERSIST_LOADER_KEY, d as MAX_TARGET_LIST_PAGE_SIZE, O as OPTIMISTIC_LOCK_ERROR_CODE, e as OPTIMISTIC_LOCK_FAILED_MESSAGE, P as PostListValidator, S as StatusCode, h as deleteTarget, k as getTarget, l as getTargetList, m as getTargetTotalCount, n as handleSupabaseError, o as isCreateTargetAlreadyExistsError, p as isDevEnvironment, q as isOptimisticLockError, s as logDev, t as logDevGroup, v as patchTarget, x as postListCreate, y as postLogListCreate, z as postTarget,
|
|
4
|
-
import { l as loadEnvFiles, b as readEnv, c as requireEnv, d as createJsonFileStateStore, a as logPersistEnabledFromEnv, e as disableLogPersist, g as getLogPersistStats, s as snapshotLogPersistReady, w as waitForLogPersistReady, f as ensureLogPersistFromEnv } from './chunks/enable-log-persist-
|
|
5
|
-
export { C as CLI_PROD_FLAG, S as SERVICE_ENV_PROFILE_ENV_KEY, h as SERVICE_ENV_PROFILE_PROD, i as enableLogPersist, j as envBool, k as envInt, m as envMs, n as envNumber, o as envPort, q as envProfileFromProcess, t as parseEnvFile, u as parseEnvLine, p as pinEnvProfileFromArgv, x as pollUntil, y as resolveDefaultEnvFiles, z as resolveLogPersistRegistryPath, r as resolveProjectRootByPackageName, A as resolveProjectRootFromModule, v as validateLogPersistPreloadEnv } from './chunks/enable-log-persist-
|
|
2
|
+
import { M as MAX_POLL_TARGET_LIST_SIZE, H as validateWithSchema, f as createLogger, w as pollTargetList, i as generateResponse, g as createTarget, D as supabase, u as logManager, J as createScope, c as LogLevel, K as patchScope, A as scanTargetList, N as withModule, j as getPossibleTarget, r as isOptimisticLockResponse, F as updateTargetDetails } from './chunks/list.api-6Q4_-7oN.js';
|
|
3
|
+
export { B as BaseValidator, C as CREATE_TARGET_ALREADY_EXISTS_MESSAGE, a as CategoryList, L as LOG_BATCH_LOADER_KEY, b as LOG_PERSIST_LOADER_KEY, d as MAX_TARGET_LIST_PAGE_SIZE, O as OPTIMISTIC_LOCK_ERROR_CODE, e as OPTIMISTIC_LOCK_FAILED_MESSAGE, P as PostListValidator, S as StatusCode, U as UPDATE_TARGET_NOT_FOUND_MESSAGE, h as deleteTarget, k as getTarget, l as getTargetList, m as getTargetTotalCount, n as handleSupabaseError, o as isCreateTargetAlreadyExistsError, p as isDevEnvironment, q as isOptimisticLockError, s as logDev, t as logDevGroup, v as patchTarget, x as postListCreate, y as postLogListCreate, z as postTarget, E as updateTarget, G as validateWith } from './chunks/list.api-6Q4_-7oN.js';
|
|
4
|
+
import { l as loadEnvFiles, b as readEnv, c as requireEnv, d as createJsonFileStateStore, a as logPersistEnabledFromEnv, e as disableLogPersist, g as getLogPersistStats, s as snapshotLogPersistReady, w as waitForLogPersistReady, f as ensureLogPersistFromEnv } from './chunks/enable-log-persist-CKxXtE3K.js';
|
|
5
|
+
export { C as CLI_PROD_FLAG, S as SERVICE_ENV_PROFILE_ENV_KEY, h as SERVICE_ENV_PROFILE_PROD, i as enableLogPersist, j as envBool, k as envInt, m as envMs, n as envNumber, o as envPort, q as envProfileFromProcess, t as parseEnvFile, u as parseEnvLine, p as pinEnvProfileFromArgv, x as pollUntil, y as resolveDefaultEnvFiles, z as resolveLogPersistRegistryPath, r as resolveProjectRootByPackageName, A as resolveProjectRootFromModule, v as validateLogPersistPreloadEnv } from './chunks/enable-log-persist-CKxXtE3K.js';
|
|
6
6
|
import { access, stat, readFile, mkdir, unlink, writeFile, readdir } from 'node:fs/promises';
|
|
7
7
|
import { resolve, join, dirname, isAbsolute } from 'node:path';
|
|
8
|
-
import { bd as sha256Hex, bi as getErrorMessage, aI as postRegisterNode, am as patchChangeNodeStatus, N as NodeStatus, ax as patchStopNode, au as patchNodeHeartBeat, E as EMPTY_REGISTRY_SLOT_RUNTIME_STATE, b3 as runRegistrySlotGuardCheck, aW as registrySlotRuntimePatchFromGuardResult, d as CategoryNode, L as evaluateBusyNodeLiveness, aw as patchServiceRuntime, k as ServiceRegistryError, v as claimServiceRegistrySlot, f as CategoryRepo, R as ResultCode, bj as LOG_TOPIC_TASK, m as TASK_REPO_USAGE, a4 as getScanRemoteRepoValues, aq as patchClaimTask, bk as CRITICAL_UNKNOWN_TASK_TRACE_ID, ao as patchChangeTaskStatus, o as TaskStatusAction, bl as toError, aQ as postTaskSchema, bm as createTaskRow, n as TaskStatus } from './chunks/task-queue-
|
|
9
|
-
export { A as ApiMethod, C as CategoryConfig, a as CategoryExtraction, b as CategoryIdea, c as CategoryLink, e as CategoryParcel, g as CategoryService, h as CategoryTask, D as DEFAULT_SYSTEM_REGISTRY_SEED_SLOTS, M as Market, P as POST_TASK_DEFAULT_MAX_ATTEMPTS, i as ParcelManager, j as PostLinkValidator, S as ServiceLifecycleStatus, l as ServiceSlotStatus, T as TARGET_SYSTEM_REGISTRY_KEY, p as apiDetailsSchema, q as appendSystemRegistrySlots, r as assertRegistrySlotAvailable, s as assertRegistrySlotOwner, t as buildEmptyServiceSlots, u as buildSystemRegistryConfigDetails, w as classifyNetworkError, x as countTasksByType, y as createActiveServiceLifecycle, z as createClaimedRegistrySlotRuntimeState, B as createStorageProviderRegistry, F as createUploadTracker, G as decodeLogBatch, H as decodeLogBatchList, I as defaultL3ServiceDetails, J as deleteParcel, K as deleteParcelSchema, O as fetchBinaryWithRetry, Q as fetchWithRetry, U as fieldDefinitionSchema, V as flattenLogBatch, W as flattenLogBatches, X as formatNetworkError, Y as getApi, Z as getApiSchema, _ as getConfig, $ as getConfigSchema, a0 as getExtraction, a1 as getExtractionSchema, a2 as getParcel, a3 as getParcelSchema, a5 as getScanRemoteRepoValuesSchema, a6 as getService, a7 as getServiceSchema, a8 as getTargetSystemRegistry, a9 as getValueAtPath, aa as installChunkFetchRegistry, ab as isHttpUrl, ac as isLocalFilesystemPath, ad as isLogBatchList, ae as isLogEntry, af as isOpaqueChunkUrl, ag as isRetryableHttpStatus, ah as parcelDetailsSchema, ai as parseLogBatchMeta, aj as parseProviderPrefixedUrl, ak as parseServiceSlot, al as parseServiceSlots, an as patchChangeNodeStatusSchema, ap as patchChangeTaskStatusSchema, ar as patchClaimTaskSchema, as as patchExtractionObjects, at as patchExtractionObjectsSchema, av as patchNodeHeartBeatSchema, ay as patchStopNodeSchema, az as patchTaskProgress, aA as patchTaskProgressSchema, aB as postApi, aC as postApiSchema, aD as postExtraction, aE as postExtractionSchema, aF as postLinkCreate, aG as postParcel, aH as postParcelSchema, aJ as postRegisterNodeSchema, aK as postService, aL as postServiceInstance, aM as postServiceSchema, aN as postSystemRegistryConfig, aO as postSystemRegistryConfigSchema, aP as postTask, aR as postTaskWithRetry, aS as publishParcel, aT as registerProviderChunkResolver, aU as registerService, aV as registerServiceAtStartup, aX as releaseSystemRegistrySlots, aY as requestHasBody, aZ as resetSystemRegistryConfig, a_ as resetSystemRegistryConfigSchema, a$ as resolveActiveRegistryServiceId, b0 as resolveFetchUrl, b1 as restoreParcel, b2 as restoreParcelById, b4 as sanitizeFileName, b5 as sanitizeParcelFileName, b6 as scanExtractionList, b7 as scanExtractionListSchema, b8 as schemaDefinitionSchema, b9 as serviceDetailsSchema, ba as serviceLifecycleSchema, bb as serviceNodeSnapshotSchema, bc as serviceRuntimeSchema, be as summarizeTaskQueue, bf as systemRegistrySeedSlotSchema, bg as unregisterService, bh as unregisterServiceAtShutdown } from './chunks/task-queue-
|
|
8
|
+
import { bd as sha256Hex, bi as getErrorMessage, aI as postRegisterNode, am as patchChangeNodeStatus, N as NodeStatus, ax as patchStopNode, au as patchNodeHeartBeat, E as EMPTY_REGISTRY_SLOT_RUNTIME_STATE, b3 as runRegistrySlotGuardCheck, aW as registrySlotRuntimePatchFromGuardResult, d as CategoryNode, L as evaluateBusyNodeLiveness, aw as patchServiceRuntime, k as ServiceRegistryError, v as claimServiceRegistrySlot, f as CategoryRepo, R as ResultCode, bj as LOG_TOPIC_TASK, m as TASK_REPO_USAGE, a4 as getScanRemoteRepoValues, aq as patchClaimTask, bk as CRITICAL_UNKNOWN_TASK_TRACE_ID, ao as patchChangeTaskStatus, o as TaskStatusAction, bl as toError, aQ as postTaskSchema, bm as createTaskRow, n as TaskStatus } from './chunks/task-queue-D5uWjqVN.js';
|
|
9
|
+
export { A as ApiMethod, C as CategoryConfig, a as CategoryExtraction, b as CategoryIdea, c as CategoryLink, e as CategoryParcel, g as CategoryService, h as CategoryTask, D as DEFAULT_SYSTEM_REGISTRY_SEED_SLOTS, M as Market, P as POST_TASK_DEFAULT_MAX_ATTEMPTS, i as ParcelManager, j as PostLinkValidator, S as ServiceLifecycleStatus, l as ServiceSlotStatus, T as TARGET_SYSTEM_REGISTRY_KEY, p as apiDetailsSchema, q as appendSystemRegistrySlots, r as assertRegistrySlotAvailable, s as assertRegistrySlotOwner, t as buildEmptyServiceSlots, u as buildSystemRegistryConfigDetails, w as classifyNetworkError, x as countTasksByType, y as createActiveServiceLifecycle, z as createClaimedRegistrySlotRuntimeState, B as createStorageProviderRegistry, F as createUploadTracker, G as decodeLogBatch, H as decodeLogBatchList, I as defaultL3ServiceDetails, J as deleteParcel, K as deleteParcelSchema, O as fetchBinaryWithRetry, Q as fetchWithRetry, U as fieldDefinitionSchema, V as flattenLogBatch, W as flattenLogBatches, X as formatNetworkError, Y as getApi, Z as getApiSchema, _ as getConfig, $ as getConfigSchema, a0 as getExtraction, a1 as getExtractionSchema, a2 as getParcel, a3 as getParcelSchema, a5 as getScanRemoteRepoValuesSchema, a6 as getService, a7 as getServiceSchema, a8 as getTargetSystemRegistry, a9 as getValueAtPath, aa as installChunkFetchRegistry, ab as isHttpUrl, ac as isLocalFilesystemPath, ad as isLogBatchList, ae as isLogEntry, af as isOpaqueChunkUrl, ag as isRetryableHttpStatus, ah as parcelDetailsSchema, ai as parseLogBatchMeta, aj as parseProviderPrefixedUrl, ak as parseServiceSlot, al as parseServiceSlots, an as patchChangeNodeStatusSchema, ap as patchChangeTaskStatusSchema, ar as patchClaimTaskSchema, as as patchExtractionObjects, at as patchExtractionObjectsSchema, av as patchNodeHeartBeatSchema, ay as patchStopNodeSchema, az as patchTaskProgress, aA as patchTaskProgressSchema, aB as postApi, aC as postApiSchema, aD as postExtraction, aE as postExtractionSchema, aF as postLinkCreate, aG as postParcel, aH as postParcelSchema, aJ as postRegisterNodeSchema, aK as postService, aL as postServiceInstance, aM as postServiceSchema, aN as postSystemRegistryConfig, aO as postSystemRegistryConfigSchema, aP as postTask, aR as postTaskWithRetry, aS as publishParcel, aT as registerProviderChunkResolver, aU as registerService, aV as registerServiceAtStartup, aX as releaseSystemRegistrySlots, aY as requestHasBody, aZ as resetSystemRegistryConfig, a_ as resetSystemRegistryConfigSchema, a$ as resolveActiveRegistryServiceId, b0 as resolveFetchUrl, b1 as restoreParcel, b2 as restoreParcelById, b4 as sanitizeFileName, b5 as sanitizeParcelFileName, b6 as scanExtractionList, b7 as scanExtractionListSchema, b8 as schemaDefinitionSchema, b9 as serviceDetailsSchema, ba as serviceLifecycleSchema, bb as serviceNodeSnapshotSchema, bc as serviceRuntimeSchema, be as summarizeTaskQueue, bf as systemRegistrySeedSlotSchema, bg as unregisterService, bh as unregisterServiceAtShutdown } from './chunks/task-queue-D5uWjqVN.js';
|
|
10
10
|
import { spawn } from 'node:child_process';
|
|
11
11
|
import { createHash } from 'node:crypto';
|
|
12
12
|
import { tmpdir } from 'node:os';
|
package/dist/preload.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
|
-
import { r as resolveProjectRootByPackageName, p as pinEnvProfileFromArgv, l as loadEnvFiles, v as validateLogPersistPreloadEnv, a as logPersistEnabledFromEnv } from './chunks/enable-log-persist-
|
|
2
|
+
import { r as resolveProjectRootByPackageName, p as pinEnvProfileFromArgv, l as loadEnvFiles, v as validateLogPersistPreloadEnv, a as logPersistEnabledFromEnv } from './chunks/enable-log-persist-CKxXtE3K.js';
|
|
3
3
|
import 'node:fs';
|
|
4
4
|
import 'node:url';
|
|
5
5
|
import 'node:fs/promises';
|
|
6
|
-
import './chunks/list.api-
|
|
6
|
+
import './chunks/list.api-6Q4_-7oN.js';
|
|
7
7
|
import 'lodash-es';
|
|
8
8
|
import '@supabase/supabase-js';
|
|
9
9
|
import 'node:crypto';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.api.d.ts","sourceRoot":"","sources":["../../src/service/config.api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB,OAAO,EAAkB,KAAK,MAAM,EAAE,KAAK,aAAa,EAA8B,MAAM,oBAAoB,CAAC;AACjH,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,qBAAqB,CAAC;AAI1E,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;EAYvB,CAAC;AAEN,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE/D,wEAAwE;AACxE,eAAO,MAAM,4BAA4B;;;;;;EAEvC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAElF,eAAO,MAAM,8BAA8B;IACvC,wEAAwE;;;;;;;;;;;;;;;;;;;EAG1E,CAAC;AAEH,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAE7F,qGAAqG;AACrG,eAAO,MAAM,+BAA+B;IARxC,wEAAwE;;;;;;;;;;;;;;;;;;;EAQC,CAAC;AAE9E,MAAM,MAAM,gCAAgC,GAAG,+BAA+B,CAAC;AAK/E,uFAAuF;AACvF,eAAO,MAAM,kCAAkC,EAAE,SAAS,sBAAsB,
|
|
1
|
+
{"version":3,"file":"config.api.d.ts","sourceRoot":"","sources":["../../src/service/config.api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB,OAAO,EAAkB,KAAK,MAAM,EAAE,KAAK,aAAa,EAA8B,MAAM,oBAAoB,CAAC;AACjH,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,qBAAqB,CAAC;AAI1E,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;EAYvB,CAAC;AAEN,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE/D,wEAAwE;AACxE,eAAO,MAAM,4BAA4B;;;;;;EAEvC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAElF,eAAO,MAAM,8BAA8B;IACvC,wEAAwE;;;;;;;;;;;;;;;;;;;EAG1E,CAAC;AAEH,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAE7F,qGAAqG;AACrG,eAAO,MAAM,+BAA+B;IARxC,wEAAwE;;;;;;;;;;;;;;;;;;;EAQC,CAAC;AAE9E,MAAM,MAAM,gCAAgC,GAAG,+BAA+B,CAAC;AAK/E,uFAAuF;AACvF,eAAO,MAAM,kCAAkC,EAAE,SAAS,sBAAsB,EAOtE,CAAC;AAkBX,wFAAwF;AACxF,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,SAAS,sBAAsB,EAAE,GAAG,WAAW,EAAE,CAMlG;AAgBD,yEAAyE;AACzE,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,aAAa,CAO7F;AAED,+EAA+E;AAC/E,eAAO,MAAM,SAAS;;;;UAaW,MAAM;;;;;;YA5GnC,CAAC;;;;;;;;;YAAD,CAAC;;;UA4G4B,MAAM;;;;;;YA5GnC,CAAC;;;;;;;;;YAAD,CAAC;;EA+HH,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,wBAAwB;;;;;4FAsBnC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB;;;;;4FA2CpC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "target-supabase-sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "Supabase client initializer and data access APIs",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "KyLoc20",
|
|
@@ -53,6 +53,8 @@
|
|
|
53
53
|
"format": "biome check --write .",
|
|
54
54
|
"format:check": "biome ci",
|
|
55
55
|
"lint": "biome lint .",
|
|
56
|
+
"verify": "pnpm typecheck && pnpm typecheck:scripts && pnpm format:check",
|
|
57
|
+
"prepare": "git config core.hooksPath .githooks",
|
|
56
58
|
"worker:trigger": "tsx scripts/run-trigger-node.ts",
|
|
57
59
|
"post-command": "tsx scripts/post-command.ts",
|
|
58
60
|
"post-trigger": "tsx scripts/post-trigger.ts",
|
package/src/core.api.ts
CHANGED
|
@@ -420,6 +420,18 @@ export interface PatchTargetPayload extends PostTargetPayload {
|
|
|
420
420
|
id: string;
|
|
421
421
|
}
|
|
422
422
|
|
|
423
|
+
export const OPTIMISTIC_LOCK_FAILED_MESSAGE =
|
|
424
|
+
"[updateTargetDetails] Optimistic lock failed: target no longer matches expected state.";
|
|
425
|
+
|
|
426
|
+
/** Thrown when UPDATE matched no row and the target id is gone (or no locks were used). */
|
|
427
|
+
export const UPDATE_TARGET_NOT_FOUND_MESSAGE = "[updateTarget] Target not found or was deleted.";
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* @deprecated Use {@link updateTarget} (narrow RMW + optimistic lock) or {@link updateTargetDetails}.
|
|
431
|
+
*
|
|
432
|
+
* Full-row rewrite of create-shaped fields. Forces callers to resupply name/value/category,
|
|
433
|
+
* has no optimistic lock, and can accidentally mutate identity columns. Unused in-tree.
|
|
434
|
+
*/
|
|
423
435
|
export const patchTarget = async ({ id, ...restPayload }: PatchTargetPayload) => {
|
|
424
436
|
const { data: currentData, error: fetchError } = await supabase.client
|
|
425
437
|
.from("target")
|
|
@@ -448,69 +460,87 @@ export const patchTarget = async ({ id, ...restPayload }: PatchTargetPayload) =>
|
|
|
448
460
|
return generateResponse.success<Target>(data as Target);
|
|
449
461
|
};
|
|
450
462
|
|
|
463
|
+
/** Mutable Target columns allowed by {@link updateTarget} (identity fields excluded). */
|
|
464
|
+
export interface UpdateTargetRowSnapshot<D> {
|
|
465
|
+
tagList: string[];
|
|
466
|
+
details: D;
|
|
467
|
+
extra?: string;
|
|
468
|
+
}
|
|
469
|
+
|
|
451
470
|
/**
|
|
452
|
-
*
|
|
471
|
+
* Narrow patch returned by `updateTarget` updateFn.
|
|
472
|
+
* Omitted keys are left unchanged on the row.
|
|
473
|
+
*/
|
|
474
|
+
export type UpdateTargetPatch<D> = {
|
|
475
|
+
tagList?: string[];
|
|
476
|
+
details?: D;
|
|
477
|
+
extra?: string;
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Read-modify-write mutable Target columns (`tagList` / `details` / `extra`) with optional
|
|
482
|
+
* DB-level optimistic locking. Does not write `name` / `value` / `category`.
|
|
453
483
|
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
* row conditions via `optimisticLockFilterList` so they are applied on the UPDATE statement.
|
|
484
|
+
* Prefer this when the update may touch `tagList` (and optionally `details`/`extra`) in one UPDATE.
|
|
485
|
+
* For details-only flows, {@link updateTargetDetails} remains the thinner API.
|
|
457
486
|
*/
|
|
458
|
-
export interface
|
|
487
|
+
export interface UpdateTargetParams<D> {
|
|
459
488
|
/** Target row id. */
|
|
460
489
|
id: string;
|
|
461
490
|
/**
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
*/
|
|
465
|
-
updateFn: (existing: D) => D;
|
|
466
|
-
/**
|
|
467
|
-
* Optional `target.extra` derived from existing details (written together with details).
|
|
491
|
+
* Builds a narrow patch from the row fetched immediately before UPDATE.
|
|
492
|
+
* Only returned keys are written; omit a key to leave that column unchanged.
|
|
468
493
|
*/
|
|
469
|
-
|
|
494
|
+
updateFn: (existing: UpdateTargetRowSnapshot<D>) => UpdateTargetPatch<D>;
|
|
470
495
|
/**
|
|
471
496
|
* Optimistic lock conditions applied on UPDATE (not on the prior SELECT).
|
|
472
|
-
*
|
|
473
|
-
* Replaces the removed `beforeUpdateValidator`: validators ran in app code between read and
|
|
474
|
-
* write and could not prevent concurrent overwrites. These filters become part of the UPDATE
|
|
475
|
-
* WHERE clause (via `applyQueryFilters`), e.g. `{ field: "details->>status", operator: "eq", value: "TODO" }`.
|
|
476
|
-
*
|
|
477
|
-
* If no row matches after UPDATE, throws "Optimistic lock failed". Empty array = update by id only.
|
|
497
|
+
* Same semantics as {@link UpdateTargetDetailsParams.optimisticLockFilterList}.
|
|
478
498
|
*/
|
|
479
499
|
optimisticLockFilterList?: QueryFilter[];
|
|
480
500
|
}
|
|
481
501
|
|
|
482
|
-
export const
|
|
483
|
-
id,
|
|
484
|
-
updateFn,
|
|
485
|
-
updateExtraFn,
|
|
486
|
-
optimisticLockFilterList = [],
|
|
487
|
-
}: UpdateTargetDetailsParams<D>) => {
|
|
502
|
+
export const updateTarget = async <T, D>({ id, updateFn, optimisticLockFilterList = [] }: UpdateTargetParams<D>) => {
|
|
488
503
|
const { data: currentData, error: fetchError } = await supabase.client
|
|
489
504
|
.from("target")
|
|
490
|
-
.select("details")
|
|
505
|
+
.select("tagList, details, extra")
|
|
491
506
|
.eq("id", id)
|
|
492
507
|
.single();
|
|
493
508
|
|
|
494
509
|
if (fetchError) {
|
|
495
|
-
handleSupabaseError("
|
|
510
|
+
handleSupabaseError("updateTarget", fetchError, "Failed to fetch target.");
|
|
496
511
|
}
|
|
497
512
|
if (!currentData) {
|
|
498
|
-
const msg = `[
|
|
513
|
+
const msg = `[updateTarget] Target NOT exists: ${id}`;
|
|
499
514
|
console.error(msg);
|
|
500
515
|
throw new Error(msg);
|
|
501
516
|
}
|
|
502
517
|
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
518
|
+
const existing: UpdateTargetRowSnapshot<D> = {
|
|
519
|
+
tagList: Array.isArray(currentData.tagList) ? (currentData.tagList as string[]) : [],
|
|
520
|
+
details: currentData.details as D,
|
|
521
|
+
extra: typeof currentData.extra === "string" ? currentData.extra : undefined,
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
const patch = updateFn(existing);
|
|
525
|
+
const updated: {
|
|
526
|
+
tagList?: string[];
|
|
527
|
+
details?: D;
|
|
528
|
+
extra?: string;
|
|
529
|
+
} = {};
|
|
530
|
+
|
|
531
|
+
if (patch.tagList !== undefined) {
|
|
532
|
+
updated.tagList = patch.tagList;
|
|
533
|
+
}
|
|
534
|
+
if (patch.details !== undefined) {
|
|
535
|
+
updated.details = patch.details;
|
|
536
|
+
}
|
|
537
|
+
if (patch.extra !== undefined) {
|
|
538
|
+
updated.extra = patch.extra;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (Object.keys(updated).length === 0) {
|
|
542
|
+
throw new Error("[updateTarget] updateFn returned an empty patch");
|
|
543
|
+
}
|
|
514
544
|
|
|
515
545
|
const updateQuery = applyQueryFilters(
|
|
516
546
|
supabase.client.from("target").update(updated).eq("id", id),
|
|
@@ -520,21 +550,88 @@ export const updateTargetDetails = async <T, D>({
|
|
|
520
550
|
const { data, error } = await updateQuery.select().maybeSingle();
|
|
521
551
|
|
|
522
552
|
if (error) {
|
|
523
|
-
handleSupabaseError("
|
|
553
|
+
handleSupabaseError("updateTarget", error, "Failed to update target.");
|
|
524
554
|
}
|
|
525
555
|
if (!data) {
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
556
|
+
if (optimisticLockFilterList.length === 0) {
|
|
557
|
+
throw new Error(UPDATE_TARGET_NOT_FOUND_MESSAGE);
|
|
558
|
+
}
|
|
559
|
+
// Empty UPDATE with locks is ambiguous: concurrent delete vs lock predicate miss.
|
|
560
|
+
// Re-SELECT by id only to disambiguate (same id, no lock filters).
|
|
561
|
+
const { data: stillThere, error: recheckError } = await supabase.client
|
|
562
|
+
.from("target")
|
|
563
|
+
.select("id")
|
|
564
|
+
.eq("id", id)
|
|
565
|
+
.maybeSingle();
|
|
566
|
+
if (recheckError) {
|
|
567
|
+
handleSupabaseError("updateTarget", recheckError, "Failed to recheck target after lock miss.");
|
|
568
|
+
}
|
|
569
|
+
if (!stillThere) {
|
|
570
|
+
throw new Error(UPDATE_TARGET_NOT_FOUND_MESSAGE);
|
|
571
|
+
}
|
|
572
|
+
throw new Error(OPTIMISTIC_LOCK_FAILED_MESSAGE);
|
|
531
573
|
}
|
|
532
574
|
|
|
533
575
|
return data as T;
|
|
534
576
|
};
|
|
535
577
|
|
|
536
|
-
|
|
537
|
-
|
|
578
|
+
/**
|
|
579
|
+
* Read-modify-write `target.details` with optional DB-level optimistic locking on UPDATE.
|
|
580
|
+
*
|
|
581
|
+
* Do not use application-layer pre-update validators (e.g. checking state after SELECT then
|
|
582
|
+
* UPDATE with only `id`). That pattern is not atomic and loses under concurrency. Pass expected
|
|
583
|
+
* row conditions via `optimisticLockFilterList` so they are applied on the UPDATE statement.
|
|
584
|
+
*
|
|
585
|
+
* For updates that also need `tagList`, use {@link updateTarget}.
|
|
586
|
+
*/
|
|
587
|
+
export interface UpdateTargetDetailsParams<D> {
|
|
588
|
+
/** Target row id. */
|
|
589
|
+
id: string;
|
|
590
|
+
/**
|
|
591
|
+
* Computes new details from the row fetched immediately before UPDATE.
|
|
592
|
+
* Runs after SELECT; the write still relies on `optimisticLockFilterList` for atomic guards.
|
|
593
|
+
*/
|
|
594
|
+
updateFn: (existing: D) => D;
|
|
595
|
+
/**
|
|
596
|
+
* Optional `target.extra` derived from existing details (written together with details).
|
|
597
|
+
*/
|
|
598
|
+
updateExtraFn?: (existing: D) => string;
|
|
599
|
+
/**
|
|
600
|
+
* Optimistic lock conditions applied on UPDATE (not on the prior SELECT).
|
|
601
|
+
*
|
|
602
|
+
* Replaces the removed `beforeUpdateValidator`: validators ran in app code between read and
|
|
603
|
+
* write and could not prevent concurrent overwrites. These filters become part of the UPDATE
|
|
604
|
+
* WHERE clause (via `applyQueryFilters`), e.g. `{ field: "details->>status", operator: "eq", value: "TODO" }`.
|
|
605
|
+
*
|
|
606
|
+
* If no row matches after UPDATE:
|
|
607
|
+
* - empty locks → not-found (`UPDATE_TARGET_NOT_FOUND_MESSAGE`)
|
|
608
|
+
* - non-empty locks → re-SELECT by id; gone → not-found, still present → `OPTIMISTIC_LOCK_FAILED_MESSAGE`
|
|
609
|
+
* Empty array = update by id only.
|
|
610
|
+
*/
|
|
611
|
+
optimisticLockFilterList?: QueryFilter[];
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
export const updateTargetDetails = async <T, D>({
|
|
615
|
+
id,
|
|
616
|
+
updateFn,
|
|
617
|
+
updateExtraFn,
|
|
618
|
+
optimisticLockFilterList = [],
|
|
619
|
+
}: UpdateTargetDetailsParams<D>) => {
|
|
620
|
+
return updateTarget<T, D>({
|
|
621
|
+
id,
|
|
622
|
+
optimisticLockFilterList,
|
|
623
|
+
updateFn: (existing) => {
|
|
624
|
+
const nextDetails = updateFn(existing.details);
|
|
625
|
+
if (updateExtraFn == null) {
|
|
626
|
+
return { details: nextDetails };
|
|
627
|
+
}
|
|
628
|
+
return {
|
|
629
|
+
details: nextDetails,
|
|
630
|
+
extra: updateExtraFn(existing.details),
|
|
631
|
+
};
|
|
632
|
+
},
|
|
633
|
+
});
|
|
634
|
+
};
|
|
538
635
|
|
|
539
636
|
export const OPTIMISTIC_LOCK_ERROR_CODE = "OPTIMISTIC_LOCK" as const;
|
|
540
637
|
|
|
@@ -60,6 +60,7 @@ export const DEFAULT_SYSTEM_REGISTRY_SEED_SLOTS: readonly SystemRegistrySeedSlot
|
|
|
60
60
|
{ serviceValue: "download-service" },
|
|
61
61
|
{ serviceValue: "storage-service" },
|
|
62
62
|
{ serviceValue: "gc-service" },
|
|
63
|
+
{ serviceValue: "upload-service" },
|
|
63
64
|
] as const;
|
|
64
65
|
|
|
65
66
|
const configCategoryFilter: QueryFilter = {
|