target-supabase-sdk 0.2.0 → 0.2.2
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 +130 -11
- package/dist/browser.d.ts +44 -36
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +6 -45
- package/dist/browser.js.map +1 -1
- package/dist/chunks/create-logger-DyH3mZ8p.js +1028 -0
- package/dist/chunks/create-logger-DyH3mZ8p.js.map +1 -0
- package/dist/chunks/enable-log-persist-BH-tbKEj.js +1481 -0
- package/dist/chunks/enable-log-persist-BH-tbKEj.js.map +1 -0
- package/dist/chunks/word.interface-DLgRobKV.js +1973 -0
- package/dist/chunks/word.interface-DLgRobKV.js.map +1 -0
- package/dist/command/command.api.d.ts +1 -1
- package/dist/command/command.api.d.ts.map +1 -1
- package/dist/command/command.interface.d.ts +1 -1
- package/dist/command/command.interface.d.ts.map +1 -1
- package/dist/core.api.d.ts +10 -6
- package/dist/core.api.d.ts.map +1 -1
- package/dist/core.interface.d.ts +3 -2
- package/dist/core.interface.d.ts.map +1 -1
- package/dist/core.utils.d.ts +1 -1
- package/dist/core.utils.d.ts.map +1 -1
- package/dist/idea/idea.interface.d.ts +1 -1
- package/dist/idea/idea.interface.d.ts.map +1 -1
- package/dist/link/link.api.d.ts +1 -1
- package/dist/link/link.api.d.ts.map +1 -1
- package/dist/link/link.interface.d.ts +2 -2
- package/dist/link/link.interface.d.ts.map +1 -1
- package/dist/list/list.api.d.ts +3 -1
- package/dist/list/list.api.d.ts.map +1 -1
- package/dist/list/list.interface.d.ts +2 -2
- package/dist/list/list.interface.d.ts.map +1 -1
- package/dist/node/env/env-parsers.d.ts +19 -0
- package/dist/node/env/env-parsers.d.ts.map +1 -0
- package/dist/node/env/index.d.ts +11 -0
- package/dist/node/env/index.d.ts.map +1 -0
- package/dist/node/env/init-supabase-from-env.d.ts +17 -0
- package/dist/node/env/init-supabase-from-env.d.ts.map +1 -0
- package/dist/node/env/load-env.d.ts +20 -0
- package/dist/node/env/load-env.d.ts.map +1 -0
- package/dist/node/env/project-root.d.ts +11 -0
- package/dist/node/env/project-root.d.ts.map +1 -0
- package/dist/node/env/public-base-url.d.ts +10 -0
- package/dist/node/env/public-base-url.d.ts.map +1 -0
- package/dist/node/env/require-env.d.ts +3 -0
- package/dist/node/env/require-env.d.ts.map +1 -0
- package/dist/node/fs/json-state-store.d.ts +19 -0
- package/dist/node/fs/json-state-store.d.ts.map +1 -0
- package/dist/node/fs/read-source-file.d.ts +19 -0
- package/dist/node/fs/read-source-file.d.ts.map +1 -0
- package/dist/node/node-liveness.d.ts +30 -0
- package/dist/node/node-liveness.d.ts.map +1 -0
- package/dist/node/node-runtime.base.d.ts +21 -3
- package/dist/node/node-runtime.base.d.ts.map +1 -1
- package/dist/node/node.api.d.ts +1 -1
- package/dist/node/node.api.d.ts.map +1 -1
- package/dist/node/node.interface.d.ts +1 -6
- package/dist/node/node.interface.d.ts.map +1 -1
- package/dist/node/preload/run-service-preload.d.ts +14 -0
- package/dist/node/preload/run-service-preload.d.ts.map +1 -0
- package/dist/node/preload/service-preload.interface.d.ts +15 -0
- package/dist/node/preload/service-preload.interface.d.ts.map +1 -0
- package/dist/node/process/index.d.ts +5 -0
- package/dist/node/process/index.d.ts.map +1 -0
- package/dist/node/process/managed-child-processes.d.ts +37 -0
- package/dist/node/process/managed-child-processes.d.ts.map +1 -0
- package/dist/node/process/process-spawn.d.ts +27 -0
- package/dist/node/process/process-spawn.d.ts.map +1 -0
- package/dist/node/readiness/index.d.ts +9 -0
- package/dist/node/readiness/index.d.ts.map +1 -0
- package/dist/node/readiness/poll-until.d.ts +11 -0
- package/dist/node/readiness/poll-until.d.ts.map +1 -0
- package/dist/node/readiness/readiness-checks.d.ts +22 -0
- package/dist/node/readiness/readiness-checks.d.ts.map +1 -0
- package/dist/node/readiness/readiness.types.d.ts +12 -0
- package/dist/node/readiness/readiness.types.d.ts.map +1 -0
- package/dist/node/readiness/run-readiness-checks.d.ts +4 -0
- package/dist/node/readiness/run-readiness-checks.d.ts.map +1 -0
- package/dist/node/readiness/service-ready-gate.d.ts +26 -0
- package/dist/node/readiness/service-ready-gate.d.ts.map +1 -0
- package/dist/node.d.ts +26 -12
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +2482 -18
- package/dist/node.js.map +1 -1
- package/dist/parcel/chunk-fetch-registry.d.ts +14 -0
- package/dist/parcel/chunk-fetch-registry.d.ts.map +1 -0
- package/dist/parcel/chunk-url.utils.d.ts +9 -0
- package/dist/parcel/chunk-url.utils.d.ts.map +1 -0
- package/dist/parcel/parcel-manager.d.ts +44 -20
- package/dist/parcel/parcel-manager.d.ts.map +1 -1
- package/dist/parcel/parcel.api.d.ts +306 -0
- package/dist/parcel/parcel.api.d.ts.map +1 -0
- package/dist/parcel/parcel.interface.d.ts +26 -5
- package/dist/parcel/parcel.interface.d.ts.map +1 -1
- package/dist/parcel/parcel.service.d.ts +38 -0
- package/dist/parcel/parcel.service.d.ts.map +1 -0
- package/dist/parcel/storage-provider-registry.d.ts +17 -0
- package/dist/parcel/storage-provider-registry.d.ts.map +1 -0
- package/dist/parcel/storage-provider.types.d.ts +31 -0
- package/dist/parcel/storage-provider.types.d.ts.map +1 -0
- package/dist/preload.d.ts +7 -0
- package/dist/preload.d.ts.map +1 -0
- package/dist/preload.js +47 -0
- package/dist/preload.js.map +1 -0
- package/dist/repo/repo-context.utils.d.ts.map +1 -1
- package/dist/repo/repo-manager.d.ts +1 -1
- package/dist/repo/repo-manager.d.ts.map +1 -1
- package/dist/repo/repo.api.d.ts +1 -1
- package/dist/repo/repo.api.d.ts.map +1 -1
- package/dist/repo/repo.interface.d.ts +1 -1
- package/dist/repo/repo.interface.d.ts.map +1 -1
- package/dist/repo/repo.script-loader.d.ts +3 -3
- package/dist/repo/repo.script-loader.d.ts.map +1 -1
- package/dist/service/base.interface.d.ts +54 -57
- package/dist/service/base.interface.d.ts.map +1 -1
- package/dist/service/index.d.ts +21 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/service.api.d.ts +503 -0
- package/dist/service/service.api.d.ts.map +1 -0
- package/dist/service/service.interface.d.ts +36 -9
- package/dist/service/service.interface.d.ts.map +1 -1
- package/dist/shared/http/fetch-retry.d.ts +21 -0
- package/dist/shared/http/fetch-retry.d.ts.map +1 -0
- package/dist/shared/log/create-logger.d.ts +27 -0
- package/dist/shared/log/create-logger.d.ts.map +1 -0
- package/dist/shared/log/enable-log-persist.d.ts +28 -0
- package/dist/shared/log/enable-log-persist.d.ts.map +1 -0
- package/dist/shared/log/index.d.ts +6 -6
- package/dist/shared/log/index.d.ts.map +1 -1
- package/dist/shared/log/log-manager.d.ts +25 -27
- package/dist/shared/log/log-manager.d.ts.map +1 -1
- package/dist/shared/log/log-persist-batch-id.d.ts +13 -0
- package/dist/shared/log/log-persist-batch-id.d.ts.map +1 -0
- package/dist/shared/log/log-persist-flush.d.ts +8 -0
- package/dist/shared/log/log-persist-flush.d.ts.map +1 -0
- package/dist/shared/log/log-persist-hook.d.ts +6 -0
- package/dist/shared/log/log-persist-hook.d.ts.map +1 -0
- package/dist/shared/log/log-persist-logger.d.ts +15 -0
- package/dist/shared/log/log-persist-logger.d.ts.map +1 -0
- package/dist/shared/log/log-persist-registry.d.ts +18 -0
- package/dist/shared/log/log-persist-registry.d.ts.map +1 -0
- package/dist/shared/log/log-persist.config.d.ts +10 -0
- package/dist/shared/log/log-persist.config.d.ts.map +1 -0
- package/dist/shared/log/log-persist.d.ts +55 -0
- package/dist/shared/log/log-persist.d.ts.map +1 -0
- package/dist/shared/log/log-persist.interface.d.ts +116 -0
- package/dist/shared/log/log-persist.interface.d.ts.map +1 -0
- package/dist/shared/log/log-scope.d.ts +25 -18
- package/dist/shared/log/log-scope.d.ts.map +1 -1
- package/dist/shared/utils/fetch-url.d.ts +3 -0
- package/dist/shared/utils/fetch-url.d.ts.map +1 -0
- package/dist/shared/utils/network-error.d.ts +14 -0
- package/dist/shared/utils/network-error.d.ts.map +1 -0
- package/dist/shared/utils/safe-file-name.d.ts +14 -0
- package/dist/shared/utils/safe-file-name.d.ts.map +1 -0
- package/dist/shared/utils/sha256.d.ts +3 -0
- package/dist/shared/utils/sha256.d.ts.map +1 -0
- package/dist/supabase.d.ts +7 -2
- package/dist/supabase.d.ts.map +1 -1
- package/dist/task/index.d.ts +8 -7
- package/dist/task/index.d.ts.map +1 -1
- package/dist/task/local-task-registry.d.ts +1 -1
- package/dist/task/local-task-registry.d.ts.map +1 -1
- package/dist/task/task-manager.d.ts +7 -9
- package/dist/task/task-manager.d.ts.map +1 -1
- package/dist/{node → task}/task-node.d.ts +2 -3
- package/dist/task/task-node.d.ts.map +1 -0
- package/dist/task/task-post-validated.api.d.ts +19 -0
- package/dist/task/task-post-validated.api.d.ts.map +1 -0
- package/dist/task/task-post.api.d.ts +10 -5
- package/dist/task/task-post.api.d.ts.map +1 -1
- package/dist/task/task-queue.d.ts +7 -0
- package/dist/task/task-queue.d.ts.map +1 -0
- package/dist/task/task-repo-context.d.ts.map +1 -1
- package/dist/task/task-repo-validation.d.ts +2 -2
- package/dist/task/task-repo-validation.d.ts.map +1 -1
- package/dist/task/task.api.d.ts +13 -13
- package/dist/task/task.api.d.ts.map +1 -1
- package/dist/task/task.constant.d.ts +4 -0
- package/dist/task/task.constant.d.ts.map +1 -0
- package/dist/task/task.interface.d.ts +1 -1
- package/dist/task/task.interface.d.ts.map +1 -1
- package/dist/trigger/trigger-manager.d.ts +25 -0
- package/dist/trigger/trigger-manager.d.ts.map +1 -0
- package/dist/trigger/trigger-node.d.ts +23 -0
- package/dist/trigger/trigger-node.d.ts.map +1 -0
- package/dist/trigger/trigger.api.d.ts +4 -4
- package/dist/trigger/trigger.api.d.ts.map +1 -1
- package/dist/trigger/trigger.constant.d.ts +8 -0
- package/dist/trigger/trigger.constant.d.ts.map +1 -0
- package/dist/trigger/trigger.interface.d.ts +46 -2
- package/dist/trigger/trigger.interface.d.ts.map +1 -1
- package/dist/word/word.api.d.ts +1 -1
- package/dist/word/word.api.d.ts.map +1 -1
- package/dist/word/word.interface.d.ts +2 -2
- package/dist/word/word.interface.d.ts.map +1 -1
- package/package.json +84 -74
- package/src/browser.ts +144 -79
- package/src/command/command.api.ts +19 -17
- package/src/command/command.interface.ts +2 -3
- package/src/core.api.ts +466 -477
- package/src/core.interface.ts +63 -62
- package/src/core.utils.ts +64 -64
- package/src/idea/idea.interface.ts +3 -3
- package/src/link/link.api.ts +28 -30
- package/src/link/link.interface.ts +3 -4
- package/src/list/list.api.ts +50 -29
- package/src/list/list.interface.ts +3 -4
- package/src/node/env/env-parsers.ts +77 -0
- package/src/node/env/index.ts +10 -0
- package/src/node/env/init-supabase-from-env.ts +38 -0
- package/src/node/env/load-env.ts +67 -0
- package/src/node/env/project-root.ts +34 -0
- package/src/node/env/public-base-url.ts +18 -0
- package/src/node/env/require-env.ts +15 -0
- package/src/node/fs/json-state-store.ts +97 -0
- package/src/node/fs/read-source-file.ts +75 -0
- package/src/node/node-liveness.ts +80 -0
- package/src/node/node-runtime.base.ts +135 -104
- package/src/node/node.api.ts +11 -10
- package/src/node/node.interface.ts +1 -8
- package/src/node/node.utils.ts +1 -1
- package/src/node/preload/run-service-preload.ts +48 -0
- package/src/node/preload/service-preload.interface.ts +14 -0
- package/src/node/process/index.ts +8 -0
- package/src/node/process/managed-child-processes.ts +121 -0
- package/src/node/process/process-spawn.ts +61 -0
- package/src/node/readiness/index.ts +20 -0
- package/src/node/readiness/poll-until.ts +27 -0
- package/src/node/readiness/readiness-checks.ts +79 -0
- package/src/node/readiness/readiness.types.ts +13 -0
- package/src/node/readiness/run-readiness-checks.ts +20 -0
- package/src/node/readiness/service-ready-gate.ts +65 -0
- package/src/node.ts +138 -47
- package/src/parcel/chunk-fetch-registry.ts +96 -0
- package/src/parcel/chunk-url.utils.ts +30 -0
- package/src/parcel/parcel-manager.ts +431 -173
- package/src/parcel/parcel.api.ts +103 -0
- package/src/parcel/parcel.interface.ts +44 -23
- package/src/parcel/parcel.service.ts +79 -0
- package/src/parcel/storage-provider-registry.ts +49 -0
- package/src/parcel/storage-provider.types.ts +45 -0
- package/src/preload.ts +7 -0
- package/src/repo/repo-context.utils.ts +3 -4
- package/src/repo/repo-manager.ts +7 -20
- package/src/repo/repo.api.ts +5 -5
- package/src/repo/repo.interface.ts +1 -2
- package/src/repo/repo.script-loader.ts +4 -8
- package/src/service/base.interface.ts +81 -90
- package/src/service/index.ts +173 -0
- package/src/service/service.api.ts +294 -0
- package/src/service/service.interface.ts +49 -17
- package/src/shared/http/fetch-retry.ts +145 -0
- package/src/shared/log/create-logger.ts +51 -0
- package/src/shared/log/enable-log-persist.ts +225 -0
- package/src/shared/log/index.ts +19 -11
- package/src/shared/log/log-manager.ts +65 -69
- package/src/shared/log/log-persist-batch-id.ts +43 -0
- package/src/shared/log/log-persist-flush.ts +128 -0
- package/src/shared/log/log-persist-hook.ts +13 -0
- package/src/shared/log/log-persist-logger.ts +33 -0
- package/src/shared/log/log-persist-registry.ts +252 -0
- package/src/shared/log/log-persist.config.ts +97 -0
- package/src/shared/log/log-persist.interface.ts +132 -0
- package/src/shared/log/log-persist.ts +704 -0
- package/src/shared/log/log-scope.ts +46 -46
- package/src/shared/utils/config-path.utils.ts +1 -1
- package/src/shared/utils/fetch-url.ts +13 -0
- package/src/shared/utils/network-error.ts +152 -0
- package/src/shared/utils/safe-file-name.ts +37 -0
- package/src/shared/utils/sha256.ts +15 -0
- package/src/supabase.ts +125 -119
- package/src/task/index.ts +31 -34
- package/src/task/local-task-registry.ts +9 -17
- package/src/task/task-manager.ts +34 -35
- package/src/{node → task}/task-node.ts +91 -73
- package/src/task/task-post-validated.api.ts +47 -0
- package/src/task/task-post.api.ts +81 -98
- package/src/task/task-queue.ts +18 -0
- package/src/task/task-repo-context.ts +2 -1
- package/src/task/task-repo-validation.ts +6 -8
- package/src/task/task.api.ts +61 -25
- package/src/task/task.constant.ts +4 -0
- package/src/task/task.interface.ts +4 -7
- package/src/trigger/trigger-manager.ts +287 -0
- package/src/trigger/trigger-node.ts +80 -0
- package/src/trigger/trigger.api.ts +11 -11
- package/src/trigger/trigger.constant.ts +10 -0
- package/src/trigger/trigger.interface.ts +52 -2
- package/src/trigger/trigger.utils.ts +1 -1
- package/src/word/word.api.ts +28 -30
- package/src/word/word.interface.ts +3 -4
- package/dist/auth/auth.api.d.ts +0 -28
- package/dist/auth/auth.api.d.ts.map +0 -1
- package/dist/auth/auth.api.js +0 -51
- package/dist/auth/auth.api.js.map +0 -1
- package/dist/command/command.api.js +0 -58
- package/dist/command/command.api.js.map +0 -1
- package/dist/command/command.interface.js +0 -9
- package/dist/command/command.interface.js.map +0 -1
- package/dist/core.api.js +0 -412
- package/dist/core.api.js.map +0 -1
- package/dist/core.interface.js +0 -46
- package/dist/core.interface.js.map +0 -1
- package/dist/core.utils.js +0 -81
- package/dist/core.utils.js.map +0 -1
- package/dist/feed/feed.interface.d.ts +0 -27
- package/dist/feed/feed.interface.d.ts.map +0 -1
- package/dist/feed/feed.interface.js +0 -17
- package/dist/feed/feed.interface.js.map +0 -1
- package/dist/file/file-manager.d.ts +0 -24
- package/dist/file/file-manager.d.ts.map +0 -1
- package/dist/file/file-manager.js +0 -109
- package/dist/file/file-manager.js.map +0 -1
- package/dist/file/file.api.d.ts +0 -15
- package/dist/file/file.api.d.ts.map +0 -1
- package/dist/file/file.api.js +0 -30
- package/dist/file/file.api.js.map +0 -1
- package/dist/file/file.interface.d.ts +0 -25
- package/dist/file/file.interface.d.ts.map +0 -1
- package/dist/file/file.interface.js +0 -9
- package/dist/file/file.interface.js.map +0 -1
- package/dist/file-list/file-list.api.d.ts +0 -15
- package/dist/file-list/file-list.api.d.ts.map +0 -1
- package/dist/file-list/file-list.api.js +0 -54
- package/dist/file-list/file-list.api.js.map +0 -1
- package/dist/file-list/file-list.interface.d.ts +0 -22
- package/dist/file-list/file-list.interface.d.ts.map +0 -1
- package/dist/file-list/file-list.interface.js +0 -5
- package/dist/file-list/file-list.interface.js.map +0 -1
- package/dist/idea/idea.interface.js +0 -15
- package/dist/idea/idea.interface.js.map +0 -1
- package/dist/index.js +0 -3
- package/dist/index.js.map +0 -1
- package/dist/link/link.api.js +0 -30
- package/dist/link/link.api.js.map +0 -1
- package/dist/link/link.interface.js +0 -7
- package/dist/link/link.interface.js.map +0 -1
- package/dist/list/list.api.js +0 -30
- package/dist/list/list.api.js.map +0 -1
- package/dist/list/list.interface.js +0 -6
- package/dist/list/list.interface.js.map +0 -1
- package/dist/node/node-log-scope.d.ts +0 -11
- package/dist/node/node-log-scope.d.ts.map +0 -1
- package/dist/node/node-log-scope.js +0 -7
- package/dist/node/node-log-scope.js.map +0 -1
- package/dist/node/node-runtime.base.js +0 -397
- package/dist/node/node-runtime.base.js.map +0 -1
- package/dist/node/node-task.preset.d.ts +0 -1
- package/dist/node/node-task.preset.d.ts.map +0 -1
- package/dist/node/node-task.preset.js +0 -14
- package/dist/node/node-task.preset.js.map +0 -1
- package/dist/node/node.api.js +0 -100
- package/dist/node/node.api.js.map +0 -1
- package/dist/node/node.interface.js +0 -19
- package/dist/node/node.interface.js.map +0 -1
- package/dist/node/node.utils.js +0 -36
- package/dist/node/node.utils.js.map +0 -1
- package/dist/node/task-node.d.ts.map +0 -1
- package/dist/node/task-node.js +0 -245
- package/dist/node/task-node.js.map +0 -1
- package/dist/node/trigger-node.d.ts +0 -18
- package/dist/node/trigger-node.d.ts.map +0 -1
- package/dist/node/trigger-node.js +0 -150
- package/dist/node/trigger-node.js.map +0 -1
- package/dist/parcel/parcel-manager.js +0 -156
- package/dist/parcel/parcel-manager.js.map +0 -1
- package/dist/parcel/parcel.interface.js +0 -11
- package/dist/parcel/parcel.interface.js.map +0 -1
- package/dist/question-list/question-list.api.d.ts +0 -13
- package/dist/question-list/question-list.api.d.ts.map +0 -1
- package/dist/question-list/question-list.api.js +0 -35
- package/dist/question-list/question-list.api.js.map +0 -1
- package/dist/question-list/question-list.interface.d.ts +0 -18
- package/dist/question-list/question-list.interface.d.ts.map +0 -1
- package/dist/question-list/question-list.interface.js +0 -5
- package/dist/question-list/question-list.interface.js.map +0 -1
- package/dist/repo/repo-context.utils.js +0 -81
- package/dist/repo/repo-context.utils.js.map +0 -1
- package/dist/repo/repo-manager.js +0 -166
- package/dist/repo/repo-manager.js.map +0 -1
- package/dist/repo/repo.api.js +0 -40
- package/dist/repo/repo.api.js.map +0 -1
- package/dist/repo/repo.interface.js +0 -8
- package/dist/repo/repo.interface.js.map +0 -1
- package/dist/repo/repo.script-loader.js +0 -108
- package/dist/repo/repo.script-loader.js.map +0 -1
- package/dist/review/review.api.d.ts +0 -14
- package/dist/review/review.api.d.ts.map +0 -1
- package/dist/review/review.api.js +0 -133
- package/dist/review/review.api.js.map +0 -1
- package/dist/review/review.interface.d.ts +0 -24
- package/dist/review/review.interface.d.ts.map +0 -1
- package/dist/review/review.interface.js +0 -10
- package/dist/review/review.interface.js.map +0 -1
- package/dist/review-v2/apis/post-review-setting.api.d.ts +0 -12
- package/dist/review-v2/apis/post-review-setting.api.d.ts.map +0 -1
- package/dist/review-v2/apis/post-review-setting.api.js +0 -27
- package/dist/review-v2/apis/post-review-setting.api.js.map +0 -1
- package/dist/review-v2/apis/post-review.api.d.ts +0 -13
- package/dist/review-v2/apis/post-review.api.d.ts.map +0 -1
- package/dist/review-v2/apis/post-review.api.js +0 -46
- package/dist/review-v2/apis/post-review.api.js.map +0 -1
- package/dist/review-v2/review-setting.interface.d.ts +0 -23
- package/dist/review-v2/review-setting.interface.d.ts.map +0 -1
- package/dist/review-v2/review-setting.interface.js +0 -5
- package/dist/review-v2/review-setting.interface.js.map +0 -1
- package/dist/review-v2/review.interface.d.ts +0 -20
- package/dist/review-v2/review.interface.d.ts.map +0 -1
- package/dist/review-v2/review.interface.js +0 -5
- package/dist/review-v2/review.interface.js.map +0 -1
- package/dist/service/api.interface.d.ts +0 -35
- package/dist/service/api.interface.d.ts.map +0 -1
- package/dist/service/api.interface.js +0 -12
- package/dist/service/api.interface.js.map +0 -1
- package/dist/service/base.interface.js +0 -7
- package/dist/service/base.interface.js.map +0 -1
- package/dist/service/service.interface.js +0 -11
- package/dist/service/service.interface.js.map +0 -1
- package/dist/shared/log/create-api-logger.d.ts +0 -21
- package/dist/shared/log/create-api-logger.d.ts.map +0 -1
- package/dist/shared/log/create-api-logger.js +0 -19
- package/dist/shared/log/create-api-logger.js.map +0 -1
- package/dist/shared/log/index.js +0 -10
- package/dist/shared/log/index.js.map +0 -1
- package/dist/shared/log/log-manager.js +0 -237
- package/dist/shared/log/log-manager.js.map +0 -1
- package/dist/shared/log/log-scope.js +0 -70
- package/dist/shared/log/log-scope.js.map +0 -1
- package/dist/shared/utils/config-path.utils.js +0 -85
- package/dist/shared/utils/config-path.utils.js.map +0 -1
- package/dist/shared/utils/error.utils.js +0 -15
- package/dist/shared/utils/error.utils.js.map +0 -1
- package/dist/shared/utils/id.utils.js +0 -5
- package/dist/shared/utils/id.utils.js.map +0 -1
- package/dist/supabase.js +0 -100
- package/dist/supabase.js.map +0 -1
- package/dist/task/index.js +0 -14
- package/dist/task/index.js.map +0 -1
- package/dist/task/local-task-registry.js +0 -214
- package/dist/task/local-task-registry.js.map +0 -1
- package/dist/task/task-manager.js +0 -196
- package/dist/task/task-manager.js.map +0 -1
- package/dist/task/task-post.api.js +0 -91
- package/dist/task/task-post.api.js.map +0 -1
- package/dist/task/task-repo-context.js +0 -12
- package/dist/task/task-repo-context.js.map +0 -1
- package/dist/task/task-repo-validation.js +0 -96
- package/dist/task/task-repo-validation.js.map +0 -1
- package/dist/task/task.api.js +0 -303
- package/dist/task/task.api.js.map +0 -1
- package/dist/task/task.interface.js +0 -36
- package/dist/task/task.interface.js.map +0 -1
- package/dist/task/task.utils.js +0 -2
- package/dist/task/task.utils.js.map +0 -1
- package/dist/trigger/trigger.api.js +0 -125
- package/dist/trigger/trigger.api.js.map +0 -1
- package/dist/trigger/trigger.interface.js +0 -11
- package/dist/trigger/trigger.interface.js.map +0 -1
- package/dist/trigger/trigger.utils.js +0 -39
- package/dist/trigger/trigger.utils.js.map +0 -1
- package/dist/word/word.api.js +0 -30
- package/dist/word/word.api.js.map +0 -1
- package/dist/word/word.interface.js +0 -6
- package/dist/word/word.interface.js.map +0 -1
- package/src/auth/auth.api.ts +0 -87
- package/src/feed/feed.interface.ts +0 -33
- package/src/file/file-manager.ts +0 -145
- package/src/file/file.api.ts +0 -43
- package/src/file/file.interface.ts +0 -30
- package/src/file-list/file-list.api.ts +0 -64
- package/src/file-list/file-list.interface.ts +0 -24
- package/src/node/node-log-scope.ts +0 -15
- package/src/node/node-task.preset.ts +0 -13
- package/src/node/trigger-node.ts +0 -180
- package/src/question-list/question-list.api.ts +0 -42
- package/src/question-list/question-list.interface.ts +0 -21
- package/src/review/review.api.ts +0 -145
- package/src/review/review.interface.ts +0 -26
- package/src/review-v2/apis/post-review-setting.api.ts +0 -35
- package/src/review-v2/apis/post-review.api.ts +0 -59
- package/src/review-v2/review-setting.interface.ts +0 -26
- package/src/review-v2/review.interface.ts +0 -23
- package/src/service/api.interface.ts +0 -47
- package/src/shared/log/create-api-logger.ts +0 -36
package/src/core.api.ts
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
const supabase = SupabaseInitializer.getInstance();
|
|
1
|
+
import type { PostgrestFilterBuilder } from "@supabase/postgrest-js";
|
|
2
|
+
import type { ZodError, ZodType } from "zod";
|
|
3
|
+
import { generateResponse, type Target, type TargetDraft } from "./core.interface";
|
|
5
4
|
import { BaseValidator, handleSupabaseError } from "./core.utils";
|
|
6
|
-
import {
|
|
7
|
-
import type { ZodType } from "zod";
|
|
8
|
-
import { ZodError } from "zod";
|
|
5
|
+
import { supabase } from "./supabase";
|
|
9
6
|
|
|
10
7
|
export interface QueryFilter {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
field: string;
|
|
9
|
+
operator: "eq" | "neq" | "in";
|
|
10
|
+
value: unknown;
|
|
14
11
|
}
|
|
15
12
|
|
|
16
13
|
export const MAX_TARGET_LIST_PAGE_SIZE = 100;
|
|
@@ -24,41 +21,37 @@ const TARGET_LIST_ORDER_FIELDS = new Set<string>(["created_at", "name", "value",
|
|
|
24
21
|
export type TargetFilterBuilder = PostgrestFilterBuilder<any, any, any[], "target", unknown>;
|
|
25
22
|
|
|
26
23
|
function validateTargetListPagination(pageNum: number, pageSize: number): void {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
if (!Number.isInteger(pageNum) || pageNum < 0) {
|
|
25
|
+
throw new Error(`[getTargetList] pageNum must be a non-negative integer, got ${pageNum}`);
|
|
26
|
+
}
|
|
27
|
+
if (!Number.isInteger(pageSize) || pageSize < 1 || pageSize > MAX_TARGET_LIST_PAGE_SIZE) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`[getTargetList] pageSize must be an integer between 1 and ${MAX_TARGET_LIST_PAGE_SIZE}, got ${pageSize}`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
35
32
|
}
|
|
36
33
|
|
|
37
|
-
function resolveTargetListPagination(params: {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
limit?: number;
|
|
41
|
-
}): {
|
|
42
|
-
pageNum: number;
|
|
43
|
-
pageSize: number;
|
|
34
|
+
function resolveTargetListPagination(params: { pageNum?: number; pageSize?: number; limit?: number }): {
|
|
35
|
+
pageNum: number;
|
|
36
|
+
pageSize: number;
|
|
44
37
|
} {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
38
|
+
if (params.limit != null) {
|
|
39
|
+
validateTargetListPagination(0, params.limit);
|
|
40
|
+
return { pageNum: 0, pageSize: params.limit };
|
|
41
|
+
}
|
|
42
|
+
if (params.pageNum === undefined || params.pageSize === undefined) {
|
|
43
|
+
throw new Error("[getTargetList] Provide pageNum and pageSize, or limit.");
|
|
44
|
+
}
|
|
45
|
+
validateTargetListPagination(params.pageNum, params.pageSize);
|
|
46
|
+
return { pageNum: params.pageNum, pageSize: params.pageSize };
|
|
54
47
|
}
|
|
55
48
|
|
|
56
49
|
function validateTargetListOrderBy(orderBy: QueryOrderBy): void {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
50
|
+
if (!TARGET_LIST_ORDER_FIELDS.has(orderBy.field)) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`[getTargetList] Unsupported orderBy.field "${orderBy.field}"; allowed: ${[...TARGET_LIST_ORDER_FIELDS].join(", ")}`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
62
55
|
}
|
|
63
56
|
|
|
64
57
|
/**
|
|
@@ -70,146 +63,143 @@ function validateTargetListOrderBy(orderBy: QueryOrderBy): void {
|
|
|
70
63
|
* 3. 统一 select 普通列表与 count head 两种查询形态,再叠加 filterList,避免三处复制分支逻辑。
|
|
71
64
|
*/
|
|
72
65
|
function buildCategoryScopedQuery({
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
66
|
+
category,
|
|
67
|
+
filterList,
|
|
68
|
+
filterBuilder,
|
|
69
|
+
select,
|
|
70
|
+
selectOptions,
|
|
78
71
|
}: {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
category: Target["category"];
|
|
73
|
+
filterList: QueryFilter[];
|
|
74
|
+
filterBuilder?: TargetFilterBuilder;
|
|
75
|
+
select: string;
|
|
76
|
+
selectOptions?: { count: "exact"; head: true };
|
|
84
77
|
}) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
78
|
+
const base =
|
|
79
|
+
filterBuilder != null
|
|
80
|
+
? filterBuilder.eq("category", category)
|
|
81
|
+
: selectOptions != null
|
|
82
|
+
? supabase.client.from("target").select(select, selectOptions).eq("category", category)
|
|
83
|
+
: supabase.client.from("target").select(select).eq("category", category);
|
|
84
|
+
|
|
85
|
+
return applyQueryFilters(base, filterList);
|
|
93
86
|
}
|
|
94
87
|
|
|
95
88
|
// biome-ignore lint/suspicious/noExplicitAny: PostgrestFilterBuilder is generic over schema
|
|
96
|
-
function applyQueryFilter<Q extends PostgrestFilterBuilder<any, any, any, any, any>>(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
throw new Error(`[applyQueryFilter] Unsupported operator: ${unsupportedOperator}`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
89
|
+
function applyQueryFilter<Q extends PostgrestFilterBuilder<any, any, any, any, any>>(query: Q, filter: QueryFilter): Q {
|
|
90
|
+
switch (filter.operator) {
|
|
91
|
+
case "eq":
|
|
92
|
+
return query.eq(filter.field, filter.value) as Q;
|
|
93
|
+
case "neq":
|
|
94
|
+
return query.neq(filter.field, filter.value) as Q;
|
|
95
|
+
case "in":
|
|
96
|
+
return query.in(filter.field, filter.value as unknown[]) as Q;
|
|
97
|
+
default: {
|
|
98
|
+
const unsupportedOperator: never = filter.operator;
|
|
99
|
+
throw new Error(`[applyQueryFilter] Unsupported operator: ${unsupportedOperator}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
112
102
|
}
|
|
113
103
|
|
|
114
104
|
// biome-ignore lint/suspicious/noExplicitAny: PostgrestFilterBuilder is generic over schema
|
|
115
105
|
function applyQueryFilters<Q extends PostgrestFilterBuilder<any, any, any, any, any>>(
|
|
116
|
-
|
|
117
|
-
|
|
106
|
+
query: Q,
|
|
107
|
+
filterList: QueryFilter[],
|
|
118
108
|
): Q {
|
|
119
|
-
|
|
109
|
+
return filterList.reduce((q, filter) => applyQueryFilter(q, filter), query);
|
|
120
110
|
}
|
|
121
111
|
|
|
122
112
|
export interface QueryOrderBy {
|
|
123
|
-
|
|
124
|
-
|
|
113
|
+
field: string;
|
|
114
|
+
ascending: boolean;
|
|
125
115
|
}
|
|
126
116
|
|
|
127
117
|
export interface BaseQueryParams {
|
|
128
|
-
|
|
129
|
-
|
|
118
|
+
filterList?: QueryFilter[];
|
|
119
|
+
orderBy?: QueryOrderBy;
|
|
130
120
|
}
|
|
131
121
|
|
|
132
122
|
export const getTarget = async ({ id, filterList }: { id: string; filterList?: QueryFilter[] }) => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
123
|
+
const query =
|
|
124
|
+
filterList != null && filterList.length > 0
|
|
125
|
+
? applyQueryFilters(supabase.client.from("target").select().eq("id", id), filterList)
|
|
126
|
+
: supabase.client.from("target").select().eq("id", id);
|
|
127
|
+
|
|
128
|
+
const { data, error } = await query.single();
|
|
129
|
+
if (error) {
|
|
130
|
+
handleSupabaseError("getTarget", error, "Failed to fetch target.");
|
|
131
|
+
}
|
|
132
|
+
return generateResponse.success<Target>(data as Target);
|
|
143
133
|
};
|
|
144
134
|
|
|
145
135
|
export const getPossibleTarget = async ({ filterList }: { filterList: QueryFilter[] }) => {
|
|
146
|
-
|
|
136
|
+
const query = applyQueryFilters(supabase.client.from("target").select(), filterList);
|
|
147
137
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
138
|
+
const { data, error } = await query.maybeSingle();
|
|
139
|
+
if (error) {
|
|
140
|
+
handleSupabaseError("getPossibleTarget", error, "Failed to fetch target.");
|
|
141
|
+
}
|
|
142
|
+
return generateResponse.success<Target | null>(data);
|
|
153
143
|
};
|
|
154
144
|
|
|
155
145
|
export interface GetTargetListParams extends BaseQueryParams {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
146
|
+
category: Target["category"];
|
|
147
|
+
/** 0-based page index. Required with pageSize unless `limit` is set. */
|
|
148
|
+
pageNum?: number;
|
|
149
|
+
pageSize?: number;
|
|
150
|
+
/** Shorthand for `{ pageNum: 0, pageSize: limit }`. Max {@link MAX_TARGET_LIST_PAGE_SIZE}. */
|
|
151
|
+
limit?: number;
|
|
152
|
+
/** PostgREST select clause; defaults to `"*"`. */
|
|
153
|
+
selectFields?: string;
|
|
154
|
+
/** Custom query builder; `category` and `filterList` are still applied. */
|
|
155
|
+
filterBuilder?: TargetFilterBuilder;
|
|
166
156
|
}
|
|
167
157
|
|
|
168
158
|
/**
|
|
169
159
|
* Paginated target list by category. Failures throw via `handleSupabaseError` (no `{ error }` envelope).
|
|
170
160
|
*/
|
|
171
161
|
export const getTargetList = async <T extends Target = Target>({
|
|
172
|
-
pageNum,
|
|
173
|
-
pageSize,
|
|
174
|
-
limit,
|
|
175
|
-
category,
|
|
176
|
-
filterList = [],
|
|
177
|
-
orderBy = { field: "created_at", ascending: false },
|
|
178
|
-
selectFields = "*",
|
|
179
|
-
filterBuilder,
|
|
180
|
-
}: GetTargetListParams) => {
|
|
181
|
-
const { pageNum: resolvedPageNum, pageSize: resolvedPageSize } = resolveTargetListPagination({
|
|
182
162
|
pageNum,
|
|
183
163
|
pageSize,
|
|
184
164
|
limit,
|
|
185
|
-
});
|
|
186
|
-
validateTargetListOrderBy(orderBy);
|
|
187
|
-
|
|
188
|
-
const query = buildCategoryScopedQuery({
|
|
189
165
|
category,
|
|
190
|
-
filterList,
|
|
166
|
+
filterList = [],
|
|
167
|
+
orderBy = { field: "created_at", ascending: false },
|
|
168
|
+
selectFields = "*",
|
|
191
169
|
filterBuilder,
|
|
192
|
-
|
|
193
|
-
|
|
170
|
+
}: GetTargetListParams) => {
|
|
171
|
+
const { pageNum: resolvedPageNum, pageSize: resolvedPageSize } = resolveTargetListPagination({
|
|
172
|
+
pageNum,
|
|
173
|
+
pageSize,
|
|
174
|
+
limit,
|
|
175
|
+
});
|
|
176
|
+
validateTargetListOrderBy(orderBy);
|
|
194
177
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
178
|
+
const query = buildCategoryScopedQuery({
|
|
179
|
+
category,
|
|
180
|
+
filterList,
|
|
181
|
+
filterBuilder,
|
|
182
|
+
select: selectFields,
|
|
183
|
+
});
|
|
198
184
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
185
|
+
const { data, error } = await query
|
|
186
|
+
.order(orderBy.field, { ascending: orderBy.ascending })
|
|
187
|
+
.range(resolvedPageNum * resolvedPageSize, (resolvedPageNum + 1) * resolvedPageSize - 1);
|
|
188
|
+
|
|
189
|
+
if (error) {
|
|
190
|
+
handleSupabaseError("getTargetList", error, "Failed to fetch target list.");
|
|
191
|
+
}
|
|
192
|
+
return generateResponse.success<T[]>((data ?? []) as T[]);
|
|
203
193
|
};
|
|
204
194
|
|
|
205
195
|
export interface ScanTargetListParams {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
196
|
+
category: Target["category"];
|
|
197
|
+
filterList?: QueryFilter[];
|
|
198
|
+
orderBy?: QueryOrderBy;
|
|
199
|
+
selectFields?: string;
|
|
200
|
+
filterBuilder?: TargetFilterBuilder;
|
|
201
|
+
/** Stop after this many rows (optional guard against runaway scans). */
|
|
202
|
+
maxRows?: number;
|
|
213
203
|
}
|
|
214
204
|
|
|
215
205
|
/**
|
|
@@ -225,102 +215,98 @@ export interface ScanTargetListParams {
|
|
|
225
215
|
* for large tables under concurrent writes, consider a DB RPC or keyset pagination later.
|
|
226
216
|
*/
|
|
227
217
|
export const scanTargetList = async <T extends Target = Target>({
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
218
|
+
category,
|
|
219
|
+
filterList = [],
|
|
220
|
+
orderBy = { field: "created_at", ascending: false },
|
|
221
|
+
selectFields = "*",
|
|
222
|
+
filterBuilder,
|
|
223
|
+
maxRows,
|
|
234
224
|
}: ScanTargetListParams) => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
225
|
+
const batchSize = MAX_TARGET_LIST_PAGE_SIZE;
|
|
226
|
+
validateTargetListOrderBy(orderBy);
|
|
227
|
+
if (maxRows != null && (!Number.isInteger(maxRows) || maxRows < 1)) {
|
|
228
|
+
throw new Error(`[scanTargetList] maxRows must be a positive integer, got ${maxRows}`);
|
|
229
|
+
}
|
|
240
230
|
|
|
241
|
-
|
|
242
|
-
|
|
231
|
+
const rows: T[] = [];
|
|
232
|
+
let pageNum = 0;
|
|
243
233
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
234
|
+
while (true) {
|
|
235
|
+
const query = buildCategoryScopedQuery({
|
|
236
|
+
category,
|
|
237
|
+
filterList,
|
|
238
|
+
filterBuilder,
|
|
239
|
+
select: selectFields,
|
|
240
|
+
});
|
|
251
241
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
242
|
+
const { data, error } = await query
|
|
243
|
+
.order(orderBy.field, { ascending: orderBy.ascending })
|
|
244
|
+
.range(pageNum * batchSize, (pageNum + 1) * batchSize - 1);
|
|
255
245
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
246
|
+
if (error) {
|
|
247
|
+
handleSupabaseError("scanTargetList", error, "Failed to scan target list.");
|
|
248
|
+
}
|
|
259
249
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
250
|
+
const page = (data ?? []) as T[];
|
|
251
|
+
if (page.length === 0) {
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
264
254
|
|
|
265
|
-
|
|
255
|
+
rows.push(...page);
|
|
266
256
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
257
|
+
if (maxRows != null && rows.length >= maxRows) {
|
|
258
|
+
rows.length = maxRows;
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
271
261
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
262
|
+
if (page.length < batchSize) {
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
275
265
|
|
|
276
|
-
|
|
277
|
-
|
|
266
|
+
pageNum += 1;
|
|
267
|
+
}
|
|
278
268
|
|
|
279
|
-
|
|
269
|
+
return generateResponse.success(rows);
|
|
280
270
|
};
|
|
281
271
|
|
|
282
272
|
export interface GetTargetTotalCountParams extends BaseQueryParams {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
273
|
+
category: Target["category"];
|
|
274
|
+
/** Custom query builder; `category` and `filterList` are still applied. */
|
|
275
|
+
filterBuilder?: TargetFilterBuilder;
|
|
286
276
|
}
|
|
287
|
-
export const getTargetTotalCount = async ({
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
filterBuilder,
|
|
296
|
-
select: "id",
|
|
297
|
-
selectOptions: { count: "exact", head: true },
|
|
298
|
-
});
|
|
277
|
+
export const getTargetTotalCount = async ({ category, filterList = [], filterBuilder }: GetTargetTotalCountParams) => {
|
|
278
|
+
const query = buildCategoryScopedQuery({
|
|
279
|
+
category,
|
|
280
|
+
filterList,
|
|
281
|
+
filterBuilder,
|
|
282
|
+
select: "id",
|
|
283
|
+
selectOptions: { count: "exact", head: true },
|
|
284
|
+
});
|
|
299
285
|
|
|
300
|
-
|
|
286
|
+
const { count, error } = await query;
|
|
301
287
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
288
|
+
if (error) {
|
|
289
|
+
handleSupabaseError("getTargetTotalCount", error, "Failed to fetch target count.");
|
|
290
|
+
}
|
|
291
|
+
return generateResponse.success<number>(count ?? 0);
|
|
306
292
|
};
|
|
307
293
|
|
|
308
294
|
function validatePollTargetListSize(size: number): void {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
295
|
+
if (!Number.isInteger(size) || size < 1 || size > MAX_POLL_TARGET_LIST_SIZE) {
|
|
296
|
+
throw new Error(
|
|
297
|
+
`[pollTargetList] size must be an integer between 1 and ${MAX_POLL_TARGET_LIST_SIZE}, got ${size}`,
|
|
298
|
+
);
|
|
299
|
+
}
|
|
314
300
|
}
|
|
315
301
|
|
|
316
302
|
export interface PollTargetListParams {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
303
|
+
category: Target["category"];
|
|
304
|
+
/** Max rows to read and attempt dequeue (not offset pagination). */
|
|
305
|
+
size: number;
|
|
306
|
+
filterList?: QueryFilter[];
|
|
307
|
+
/** Order by `created_at`. Default `true` (oldest first). */
|
|
308
|
+
ascending?: boolean;
|
|
309
|
+
selectFields?: string;
|
|
324
310
|
}
|
|
325
311
|
|
|
326
312
|
/**
|
|
@@ -340,122 +326,126 @@ export interface PollTargetListParams {
|
|
|
340
326
|
* - 短期加固:DELETE 后校验影响行数,0 行则不 push 到 polled
|
|
341
327
|
*/
|
|
342
328
|
export const pollTargetList = async <T extends Target = Target>({
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
329
|
+
category,
|
|
330
|
+
size,
|
|
331
|
+
filterList = [],
|
|
332
|
+
ascending = true,
|
|
333
|
+
selectFields = "*",
|
|
348
334
|
}: PollTargetListParams) => {
|
|
349
|
-
|
|
335
|
+
validatePollTargetListSize(size);
|
|
350
336
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
337
|
+
const query = buildCategoryScopedQuery({
|
|
338
|
+
category,
|
|
339
|
+
filterList,
|
|
340
|
+
select: selectFields,
|
|
341
|
+
});
|
|
356
342
|
|
|
357
|
-
|
|
343
|
+
const { data, error } = await query.order("created_at", { ascending }).limit(size);
|
|
358
344
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
345
|
+
if (error) {
|
|
346
|
+
handleSupabaseError("pollTargetList", error, "Failed to fetch targets for poll.");
|
|
347
|
+
}
|
|
362
348
|
|
|
363
|
-
|
|
364
|
-
|
|
349
|
+
const candidates = (data ?? []) as T[];
|
|
350
|
+
const polled: T[] = [];
|
|
365
351
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
352
|
+
for (const row of candidates) {
|
|
353
|
+
try {
|
|
354
|
+
await deleteTarget({ id: row.id });
|
|
355
|
+
polled.push(row);
|
|
356
|
+
} catch {
|
|
357
|
+
// Concurrent dequeue — row already removed
|
|
358
|
+
}
|
|
372
359
|
}
|
|
373
|
-
}
|
|
374
360
|
|
|
375
|
-
|
|
361
|
+
return generateResponse.success<T[]>(polled);
|
|
376
362
|
};
|
|
377
363
|
|
|
378
364
|
export const deleteTarget = async ({ id, filterList }: { id: string; filterList?: QueryFilter[] }) => {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
365
|
+
// Check whether the target exists given filterList
|
|
366
|
+
if (filterList != null && filterList.length > 0) {
|
|
367
|
+
const query = applyQueryFilters(supabase.client.from("target").select().eq("id", id), filterList);
|
|
368
|
+
const { data: existingTarget, error: existingError } = await query.single();
|
|
369
|
+
if (existingError || existingTarget == null) {
|
|
370
|
+
const msg = `[deleteTarget] Cannot find the target ${id}`;
|
|
371
|
+
console.error(msg, { filterList }, existingError);
|
|
372
|
+
throw new Error(msg);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const { error } = await supabase.client.from("target").delete().eq("id", id);
|
|
376
|
+
if (error) {
|
|
377
|
+
handleSupabaseError("deleteTarget", error, `Failed to delete target ${id}.`);
|
|
378
|
+
}
|
|
379
|
+
return generateResponse.success();
|
|
394
380
|
};
|
|
395
381
|
|
|
396
382
|
export interface PostTargetPayload {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
383
|
+
name: Target["name"];
|
|
384
|
+
category: Target["category"];
|
|
385
|
+
value: Target["value"];
|
|
386
|
+
tagList: Target["tagList"];
|
|
387
|
+
extra?: Target["extra"];
|
|
388
|
+
details?: Target["details"];
|
|
403
389
|
}
|
|
404
390
|
|
|
405
391
|
class PostTargetPayloadValidator extends BaseValidator<PostTargetPayload> {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
392
|
+
protected requiredFields: (keyof PostTargetPayload)[] = ["category", "name", "value", "tagList"];
|
|
393
|
+
protected optionalFields: (keyof PostTargetPayload)[] = ["extra", "details"];
|
|
394
|
+
|
|
395
|
+
constructor() {
|
|
396
|
+
super();
|
|
397
|
+
// Add custom
|
|
398
|
+
this.addCustomValidator((_val) => {
|
|
399
|
+
return true;
|
|
400
|
+
});
|
|
401
|
+
}
|
|
416
402
|
}
|
|
417
403
|
|
|
418
404
|
export const postTarget = async (payload: PostTargetPayload) => {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
405
|
+
const validPayload = new PostTargetPayloadValidator().validate(payload);
|
|
406
|
+
|
|
407
|
+
const { data, error } = await supabase.client
|
|
408
|
+
.from("target")
|
|
409
|
+
.insert([{ ...validPayload }])
|
|
410
|
+
.select()
|
|
411
|
+
.single();
|
|
412
|
+
|
|
413
|
+
if (error) {
|
|
414
|
+
handleSupabaseError("postTarget", error, "Failed to create target.");
|
|
415
|
+
}
|
|
416
|
+
return generateResponse.success<Target>(data as Target);
|
|
431
417
|
};
|
|
432
418
|
|
|
433
419
|
export interface PatchTargetPayload extends PostTargetPayload {
|
|
434
|
-
|
|
420
|
+
id: string;
|
|
435
421
|
}
|
|
436
422
|
|
|
437
423
|
export const patchTarget = async ({ id, ...restPayload }: PatchTargetPayload) => {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
.
|
|
449
|
-
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
424
|
+
const { data: currentData, error: fetchError } = await supabase.client
|
|
425
|
+
.from("target")
|
|
426
|
+
.select()
|
|
427
|
+
.eq("id", id)
|
|
428
|
+
.single();
|
|
429
|
+
if (!currentData) {
|
|
430
|
+
throw new Error("Target NOT exists");
|
|
431
|
+
}
|
|
432
|
+
if (fetchError) handleSupabaseError("patchTarget", fetchError, "Failed to fetch target.");
|
|
433
|
+
|
|
434
|
+
const updatedTarget = new PostTargetPayloadValidator().validate(restPayload);
|
|
435
|
+
|
|
436
|
+
const { data, error } = await supabase.client
|
|
437
|
+
.from("target")
|
|
438
|
+
.update({
|
|
439
|
+
...updatedTarget,
|
|
440
|
+
})
|
|
441
|
+
.eq("id", id)
|
|
442
|
+
.select()
|
|
443
|
+
.single();
|
|
444
|
+
|
|
445
|
+
if (error) {
|
|
446
|
+
handleSupabaseError("patchTarget", error, "Failed to update target.");
|
|
447
|
+
}
|
|
448
|
+
return generateResponse.success<Target>(data as Target);
|
|
459
449
|
};
|
|
460
450
|
|
|
461
451
|
/**
|
|
@@ -466,122 +456,125 @@ export const patchTarget = async ({ id, ...restPayload }: PatchTargetPayload) =>
|
|
|
466
456
|
* row conditions via `optimisticLockFilterList` so they are applied on the UPDATE statement.
|
|
467
457
|
*/
|
|
468
458
|
export interface UpdateTargetDetailsParams<D> {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
459
|
+
/** Target row id. */
|
|
460
|
+
id: string;
|
|
461
|
+
/**
|
|
462
|
+
* Computes new details from the row fetched immediately before UPDATE.
|
|
463
|
+
* Runs after SELECT; the write still relies on `optimisticLockFilterList` for atomic guards.
|
|
464
|
+
*/
|
|
465
|
+
updateFn: (existing: D) => D;
|
|
466
|
+
/**
|
|
467
|
+
* Optional `target.extra` derived from existing details (written together with details).
|
|
468
|
+
*/
|
|
469
|
+
updateExtraFn?: (existing: D) => string;
|
|
470
|
+
/**
|
|
471
|
+
* 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.
|
|
478
|
+
*/
|
|
479
|
+
optimisticLockFilterList?: QueryFilter[];
|
|
490
480
|
}
|
|
491
481
|
|
|
492
482
|
export const updateTargetDetails = async <T, D>({
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
483
|
+
id,
|
|
484
|
+
updateFn,
|
|
485
|
+
updateExtraFn,
|
|
486
|
+
optimisticLockFilterList = [],
|
|
497
487
|
}: UpdateTargetDetailsParams<D>) => {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
488
|
+
const { data: currentData, error: fetchError } = await supabase.client
|
|
489
|
+
.from("target")
|
|
490
|
+
.select("details")
|
|
491
|
+
.eq("id", id)
|
|
492
|
+
.single();
|
|
493
|
+
|
|
494
|
+
if (fetchError) {
|
|
495
|
+
handleSupabaseError("updateTargetDetails", fetchError, "Failed to fetch target.");
|
|
496
|
+
}
|
|
497
|
+
if (!currentData) {
|
|
498
|
+
const msg = `[updateTargetDetails] Target NOT exists: ${id}`;
|
|
499
|
+
console.error(msg);
|
|
500
|
+
throw new Error(msg);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const currentDetails = currentData.details as D;
|
|
504
|
+
const updatedDetails: D = updateFn(currentDetails);
|
|
505
|
+
const updated =
|
|
506
|
+
updateExtraFn == null
|
|
507
|
+
? {
|
|
508
|
+
details: updatedDetails,
|
|
509
|
+
}
|
|
510
|
+
: {
|
|
511
|
+
details: updatedDetails,
|
|
512
|
+
extra: updateExtraFn(currentDetails),
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
const updateQuery = applyQueryFilters(
|
|
516
|
+
supabase.client.from("target").update(updated).eq("id", id),
|
|
517
|
+
optimisticLockFilterList,
|
|
518
|
+
);
|
|
519
|
+
|
|
520
|
+
const { data, error } = await updateQuery.select().maybeSingle();
|
|
521
|
+
|
|
522
|
+
if (error) {
|
|
523
|
+
handleSupabaseError("updateTargetDetails", error, "Failed to update target details.");
|
|
524
|
+
}
|
|
525
|
+
if (!data) {
|
|
526
|
+
const msg =
|
|
527
|
+
optimisticLockFilterList.length > 0
|
|
528
|
+
? OPTIMISTIC_LOCK_FAILED_MESSAGE
|
|
529
|
+
: "[updateTargetDetails] Target not found or was deleted.";
|
|
530
|
+
throw new Error(msg);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return data as T;
|
|
544
534
|
};
|
|
545
535
|
|
|
546
536
|
export const OPTIMISTIC_LOCK_FAILED_MESSAGE =
|
|
547
|
-
|
|
537
|
+
"[updateTargetDetails] Optimistic lock failed: target no longer matches expected state.";
|
|
538
|
+
|
|
539
|
+
export const OPTIMISTIC_LOCK_ERROR_CODE = "OPTIMISTIC_LOCK" as const;
|
|
540
|
+
|
|
541
|
+
export function isOptimisticLockError(error: unknown): boolean {
|
|
542
|
+
return error instanceof Error && error.message === OPTIMISTIC_LOCK_FAILED_MESSAGE;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
export function isOptimisticLockResponse(error: { code?: string } | null | undefined): boolean {
|
|
546
|
+
return error?.code === OPTIMISTIC_LOCK_ERROR_CODE;
|
|
547
|
+
}
|
|
548
548
|
|
|
549
549
|
export const CREATE_TARGET_ALREADY_EXISTS_MESSAGE = "[createTarget] Target already exists";
|
|
550
550
|
|
|
551
551
|
const CREATE_TARGET_REDUNDANCY_MISMATCH_MESSAGE =
|
|
552
|
-
|
|
552
|
+
"[createTarget] Inserted row does not match checkRedundancyFilterList; verify createFn aligns with filters.";
|
|
553
553
|
|
|
554
554
|
/** Max rows to fetch during post-verify — only need to detect one other match. */
|
|
555
555
|
const REDUNDANCY_VERIFY_ROW_LIMIT = 2;
|
|
556
556
|
|
|
557
|
-
export function isOptimisticLockError(error: unknown): boolean {
|
|
558
|
-
return error instanceof Error && error.message === OPTIMISTIC_LOCK_FAILED_MESSAGE;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
557
|
export function isCreateTargetAlreadyExistsError(error: unknown): boolean {
|
|
562
|
-
|
|
558
|
+
return error instanceof Error && error.message === CREATE_TARGET_ALREADY_EXISTS_MESSAGE;
|
|
563
559
|
}
|
|
564
560
|
|
|
565
561
|
/** Roll back an optimistic insert when redundancy filters match other rows. */
|
|
566
562
|
async function rollbackCreateTargetInsert(id: string) {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
563
|
+
const { error } = await supabase.client.from("target").delete().eq("id", id);
|
|
564
|
+
if (error) {
|
|
565
|
+
handleSupabaseError("createTarget", error, "Failed to rollback conflicting insert.");
|
|
566
|
+
}
|
|
571
567
|
}
|
|
572
568
|
|
|
573
569
|
/** Roll back the new row and signal a redundancy conflict to the caller. */
|
|
574
570
|
function throwCreateTargetAlreadyExists(checkRedundancyFilterList: QueryFilter[]): never {
|
|
575
|
-
|
|
576
|
-
|
|
571
|
+
console.error(CREATE_TARGET_ALREADY_EXISTS_MESSAGE, checkRedundancyFilterList);
|
|
572
|
+
throw new Error(CREATE_TARGET_ALREADY_EXISTS_MESSAGE);
|
|
577
573
|
}
|
|
578
574
|
|
|
579
|
-
async function failCreateTargetRedundancy(
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
): Promise<never> {
|
|
583
|
-
await rollbackCreateTargetInsert(selfId);
|
|
584
|
-
return throwCreateTargetAlreadyExists(checkRedundancyFilterList);
|
|
575
|
+
async function failCreateTargetRedundancy(selfId: string, checkRedundancyFilterList: QueryFilter[]): Promise<never> {
|
|
576
|
+
await rollbackCreateTargetInsert(selfId);
|
|
577
|
+
return throwCreateTargetAlreadyExists(checkRedundancyFilterList);
|
|
585
578
|
}
|
|
586
579
|
|
|
587
580
|
/**
|
|
@@ -591,104 +584,100 @@ async function failCreateTargetRedundancy(
|
|
|
591
584
|
* See `.cursor/skills/create-target-redundancy/SKILL.md`.
|
|
592
585
|
*/
|
|
593
586
|
export const createTarget = async <T extends Target, P extends object>({
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
587
|
+
payload,
|
|
588
|
+
validator,
|
|
589
|
+
createFn,
|
|
590
|
+
checkRedundancyFilterList,
|
|
591
|
+
upsert = false,
|
|
599
592
|
}: {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
593
|
+
payload: P;
|
|
594
|
+
validator?: new () => BaseValidator<P>;
|
|
595
|
+
createFn: (validPayload: P) => TargetDraft<T>;
|
|
596
|
+
/** Business-key filters; if another row matches after insert, conflict handling runs. */
|
|
597
|
+
checkRedundancyFilterList?: QueryFilter[];
|
|
598
|
+
/**
|
|
599
|
+
* @deprecated Not supported — ignored at runtime. Use domain patch APIs or future RPC upsert.
|
|
600
|
+
* Reserved for a later release; do not pass `true`.
|
|
601
|
+
*/
|
|
602
|
+
upsert?: boolean;
|
|
610
603
|
}) => {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
return failCreateTargetRedundancy(selfId, checkRedundancyFilterList);
|
|
604
|
+
if (upsert) {
|
|
605
|
+
console.warn("[createTarget] `upsert` is deprecated and has no effect.");
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const validPayload = validator != null ? new validator().validate(payload) : payload;
|
|
609
|
+
const newTarget = createFn(validPayload);
|
|
610
|
+
|
|
611
|
+
const hasRedundancyCheck = checkRedundancyFilterList != null && checkRedundancyFilterList.length > 0;
|
|
612
|
+
|
|
613
|
+
// 1. Optimistic insert (see create-target-redundancy skill)
|
|
614
|
+
const { data, error } = await supabase.client.from("target").insert([newTarget]).select().single();
|
|
615
|
+
if (error) {
|
|
616
|
+
handleSupabaseError("createTarget", error, "Failed to create target.");
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (!hasRedundancyCheck) {
|
|
620
|
+
return generateResponse.success<T>(data);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// 2. Post-verify: limit(2) — enough to detect one other row matching the business-key filters
|
|
624
|
+
const { data: matches, error: matchError } = await applyQueryFilters(
|
|
625
|
+
supabase.client.from("target").select("id"),
|
|
626
|
+
checkRedundancyFilterList,
|
|
627
|
+
).limit(REDUNDANCY_VERIFY_ROW_LIMIT);
|
|
628
|
+
if (matchError) {
|
|
629
|
+
handleSupabaseError("createTarget", matchError, "Failed to verify target redundancy.");
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const selfId = data.id as string;
|
|
633
|
+
const rows = matches ?? [];
|
|
634
|
+
const selfMatchesFilters = rows.some((row) => row.id === selfId);
|
|
635
|
+
if (!selfMatchesFilters) {
|
|
636
|
+
console.warn(CREATE_TARGET_REDUNDANCY_MISMATCH_MESSAGE, checkRedundancyFilterList);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
const hasOtherRow = rows.some((row) => row.id !== selfId);
|
|
640
|
+
|
|
641
|
+
// 3. No conflict — keep the inserted row; otherwise rollback and reject
|
|
642
|
+
if (!hasOtherRow) {
|
|
643
|
+
return generateResponse.success<T>(data);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return failCreateTargetRedundancy(selfId, checkRedundancyFilterList);
|
|
655
647
|
};
|
|
656
648
|
|
|
657
649
|
export function validateWith<P extends object, V extends BaseValidator<P>>(ValidatorClass: new () => V) {
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
650
|
+
return <R>(fn: (validPayload: P) => R) => {
|
|
651
|
+
return (payload: P): R => {
|
|
652
|
+
const validPayload = new ValidatorClass().validate(payload);
|
|
653
|
+
return fn(validPayload);
|
|
654
|
+
};
|
|
662
655
|
};
|
|
663
|
-
};
|
|
664
656
|
}
|
|
665
657
|
|
|
666
658
|
function formatZodValidationError(schemaName: string, error: ZodError): Error {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
659
|
+
const errorList = error.issues
|
|
660
|
+
.map((issue, index) => {
|
|
661
|
+
const path = issue.path.length > 0 ? issue.path.join(".") : "(root)";
|
|
662
|
+
return ` ${index + 1}. ${path}: ${issue.message}`;
|
|
663
|
+
})
|
|
664
|
+
.join("\n");
|
|
665
|
+
const errorCount = error.issues.length;
|
|
666
|
+
return new Error(
|
|
667
|
+
`[${schemaName}] Validation failed (${errorCount} error${errorCount > 1 ? "s" : ""}):\n${errorList}`,
|
|
668
|
+
);
|
|
677
669
|
}
|
|
678
670
|
|
|
679
671
|
/** Zod-based counterpart to {@link validateWith} — requires `zod` as a peer dependency. */
|
|
680
|
-
export function validateWithSchema<T extends ZodType>(
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
) {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
}
|
|
691
|
-
return fn(result.data);
|
|
672
|
+
export function validateWithSchema<T extends ZodType>(schema: T, schemaName = "Schema") {
|
|
673
|
+
type Parsed = T["_output"];
|
|
674
|
+
return <R>(fn: (validPayload: Parsed) => R | Promise<R>) => {
|
|
675
|
+
return (payload: Parsed): R | Promise<R> => {
|
|
676
|
+
const result = schema.safeParse(payload);
|
|
677
|
+
if (!result.success) {
|
|
678
|
+
throw formatZodValidationError(schemaName, result.error);
|
|
679
|
+
}
|
|
680
|
+
return fn(result.data);
|
|
681
|
+
};
|
|
692
682
|
};
|
|
693
|
-
};
|
|
694
683
|
}
|