@bitkyc08/opencodex 2.83.0 → 2.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/gui/dist/assets/App-CZtqiGcw.js +56 -0
- package/gui/dist/assets/Tray-C9TGtwad.js +1 -0
- package/gui/dist/assets/{index-BAbcj51J.css → index-BB6uK6tU.css} +1 -1
- package/gui/dist/assets/index-CTm4l-HQ.js +94 -0
- package/gui/dist/assets/{quota-summary-DiJO6sYY.js → quota-summary-BbEeRfPY.js} +1 -1
- package/gui/dist/index.html +2 -2
- package/package.json +2 -2
- package/src/adapters/coding-agent/protocol.ts +15 -8
- package/src/adapters/ollama-native.ts +29 -1
- package/src/adapters/openai-chat/messages.ts +8 -4
- package/src/adapters/openai-responses/empty-assistant.ts +32 -0
- package/src/adapters/openai-responses/passthrough.ts +3 -0
- package/src/adapters/openai-responses/request-strips.ts +10 -2
- package/src/adapters/qoder/adapter.ts +16 -14
- package/src/bridge/errors.ts +19 -0
- package/src/bridge.ts +1 -1
- package/src/claude/context-windows.ts +54 -1
- package/src/claude/intercept/connect-proxy.ts +10 -3
- package/src/claude/intercept/picker-ca-persistence.ts +3 -1
- package/src/claude/intercept/picker-listener.ts +49 -1
- package/src/claude/intercept/settings-no-proxy.ts +146 -0
- package/src/claude/intercept/settings.ts +101 -9
- package/src/cli/account-api.ts +65 -0
- package/src/cli/account-auth.ts +26 -2
- package/src/cli/account.ts +41 -5
- package/src/cli/capabilities-access-remote.ts +8 -0
- package/src/cli/capabilities-base.ts +13 -1
- package/src/cli/catalog-command-result.ts +2 -1
- package/src/cli/claude.ts +15 -6
- package/src/cli/config-command.ts +8 -2
- package/src/cli/debug.ts +8 -0
- package/src/cli/dispatch.ts +16 -3
- package/src/cli/export-command.ts +14 -1
- package/src/cli/hub-disable.ts +99 -0
- package/src/cli/hub.ts +4 -2
- package/src/cli/index.ts +13 -4
- package/src/cli/link-child.ts +104 -0
- package/src/cli/link-enrollment.ts +96 -0
- package/src/cli/link.ts +39 -24
- package/src/cli/observe-stream.ts +6 -1
- package/src/cli/observe.ts +10 -2
- package/src/cli/provider.ts +12 -0
- package/src/cli/registry.ts +5 -4
- package/src/cli/runtime-api.ts +27 -2
- package/src/cli/status.ts +104 -20
- package/src/client/connect.ts +39 -4
- package/src/client/hub-client.ts +14 -7
- package/src/client/hub-state.ts +25 -14
- package/src/client/link-home.ts +248 -0
- package/src/client/link-management-relay.ts +61 -0
- package/src/client/link-relay.ts +6 -1
- package/src/client/link-status.ts +14 -0
- package/src/client/machine-api.ts +14 -7
- package/src/client/machine-listener.ts +29 -4
- package/src/clients/config-export.ts +46 -16
- package/src/clients/omo-role-models.ts +6 -3
- package/src/codex/agent-role-models.ts +26 -8
- package/src/codex/auth-api/account-list.ts +17 -2
- package/src/codex/auth-api/account-selection.ts +17 -7
- package/src/codex/auth-api/routes.ts +5 -1
- package/src/codex/autostart-health.ts +3 -1
- package/src/codex/catalog/bundled.ts +5 -1
- package/src/codex/catalog/effort.ts +2 -2
- package/src/codex/catalog/metadata.ts +4 -2
- package/src/codex/catalog/native-models.ts +16 -2
- package/src/codex/native-profile-startup.ts +4 -1
- package/src/codex/prompt-journal.ts +20 -2
- package/src/codex/prompt-layers/encoding.ts +49 -0
- package/src/codex/prompt-layers/import-source.ts +30 -0
- package/src/codex/prompt-layers/toml-edit.ts +269 -37
- package/src/codex/prompt-layers/toml-read.ts +52 -4
- package/src/codex/prompt-layers.ts +383 -20
- package/src/codex/prompt-lock-claim.ts +13 -3
- package/src/codex/prompt-lock-evidence.ts +3 -3
- package/src/codex/prompt-lock-owner.ts +14 -6
- package/src/codex/prompt-text-probe.ts +34 -5
- package/src/codex/quota.ts +13 -6
- package/src/codex/role-auto-assign.ts +2 -5
- package/src/codex/routing/active-account.ts +21 -0
- package/src/codex/routing.ts +1 -1
- package/src/codex/runtime.ts +196 -8
- package/src/codex/shim-overlay.ts +8 -4
- package/src/codex/shim.ts +1 -1
- package/src/combos/failover.ts +3 -0
- package/src/config/api-key-reconcile.ts +34 -0
- package/src/config/diagnostics.ts +16 -0
- package/src/config/feature-flags.ts +5 -0
- package/src/config/live-reconcile.ts +43 -29
- package/src/config/live-topology.ts +29 -0
- package/src/config/load-degrade.ts +2 -1
- package/src/config/paths.ts +3 -0
- package/src/config/salvage.ts +3 -1
- package/src/config/schema/config-schema.ts +2 -0
- package/src/generated/compatibility-version.json +311 -171
- package/src/grok/grpc-web.ts +23 -1
- package/src/grok/reset-coupon-ledger.ts +75 -5
- package/src/grok/reset-coupons.ts +4 -2
- package/src/integrations/mutation-plan.ts +13 -7
- package/src/integrations/registry.ts +45 -11
- package/src/integrations/state.ts +19 -7
- package/src/integrations/target.ts +42 -5
- package/src/integrations/writer.ts +14 -6
- package/src/lib/app-owned-memory-stores.ts +4 -0
- package/src/lib/app-owned-memory.ts +11 -0
- package/src/lib/json-byte-size.ts +31 -0
- package/src/lib/optional-shutdown-hooks.ts +35 -0
- package/src/lib/outbound-credential-registry.ts +210 -0
- package/src/lib/passive-read.ts +35 -0
- package/src/lib/shadow-call.ts +44 -5
- package/src/link/codex-settings.ts +155 -0
- package/src/link/management-routes.ts +89 -0
- package/src/link/remote-probe.ts +38 -0
- package/src/link/ssh-argv.ts +26 -5
- package/src/link/ssh-runner.ts +58 -27
- package/src/link/status-projection.ts +22 -4
- package/src/link/supervisor.ts +144 -49
- package/src/link/tunnel-state.ts +11 -4
- package/src/oauth/anthropic-continuity.ts +4 -3
- package/src/oauth/anthropic-identity.ts +13 -2
- package/src/oauth/anthropic-model-quota.ts +13 -1
- package/src/oauth/anthropic-routing.ts +230 -23
- package/src/oauth/anthropic.ts +18 -4
- package/src/oauth/google-antigravity.ts +24 -7
- package/src/oauth/index.ts +24 -15
- package/src/oauth/kiro-account-identity.ts +106 -0
- package/src/oauth/kiro.ts +48 -5
- package/src/oauth/plan.ts +29 -0
- package/src/oauth/store.ts +40 -3
- package/src/oauth/types.ts +2 -0
- package/src/plugins/loader.ts +11 -0
- package/src/providers/anthropic-billing-ownership.ts +74 -0
- package/src/providers/anthropic-billing-recovery.ts +31 -0
- package/src/providers/anthropic-billing-refusal.ts +55 -0
- package/src/providers/anthropic-reset-admission.ts +62 -0
- package/src/providers/anthropic-reset-grant-ledger.ts +28 -6
- package/src/providers/api-key-resolve.ts +17 -2
- package/src/providers/key-failover.ts +52 -5
- package/src/providers/model-rename-startup.ts +5 -3
- package/src/providers/quota/account-cache.ts +11 -0
- package/src/providers/quota/anthropic-account-quota.ts +4 -2
- package/src/providers/quota/report-cache.ts +14 -0
- package/src/providers/quota/vendor-probes-oauth.ts +3 -3
- package/src/providers/quota.ts +4 -1
- package/src/providers/registry/entries-core.ts +14 -14
- package/src/providers/registry/entries-extended.ts +0 -1
- package/src/providers/registry/model-seeds.ts +17 -0
- package/src/providers/request-pacing.ts +9 -0
- package/src/providers/stale-no-vision-seed-migration.ts +72 -0
- package/src/responses/compaction.ts +14 -0
- package/src/responses/parser.ts +7 -1
- package/src/server/auth-cors.ts +42 -0
- package/src/server/configured-credentials.ts +194 -0
- package/src/server/index/link-management.ts +58 -0
- package/src/server/index/optional-listeners.ts +5 -1
- package/src/server/index/serve-options.ts +13 -0
- package/src/server/lifecycle.ts +2 -1
- package/src/server/management/agent-settings-routes.ts +28 -10
- package/src/server/management/anthropic-reset-grant-routes.ts +17 -1
- package/src/server/management/codex-agent-role-routes.ts +19 -6
- package/src/server/management/codex-prompt-routes.ts +136 -5
- package/src/server/management/codex-role-auto-assign.ts +1 -1
- package/src/server/management/grok-coupon-routes.ts +78 -27
- package/src/server/management/link-enrollment.ts +192 -0
- package/src/server/management/link-route-state.ts +185 -0
- package/src/server/management/link-routes.ts +82 -402
- package/src/server/management/model-rows.ts +3 -1
- package/src/server/management/provider-overwrite-carry.ts +10 -0
- package/src/server/management/provider-routes.ts +1 -0
- package/src/server/management/route-registry.ts +5 -3
- package/src/server/management/shared.ts +3 -0
- package/src/server/management-api.ts +3 -1
- package/src/server/messages-native.ts +68 -42
- package/src/server/relay-eager.ts +2 -0
- package/src/server/request-log-filter.ts +6 -1
- package/src/server/request-log-terminal-status.ts +63 -6
- package/src/server/responses/adapter-dispatch.ts +232 -79
- package/src/server/responses/code-mode-collab-surface.ts +205 -0
- package/src/server/responses/codex-ws-exchange.ts +147 -6
- package/src/server/responses/codex-ws-wire.ts +203 -0
- package/src/server/responses/collaboration.ts +36 -7
- package/src/server/responses/compact.ts +126 -48
- package/src/server/responses/context-overflow.ts +13 -1
- package/src/server/responses/core-codex-account.ts +105 -1
- package/src/server/responses/core-combo-failure.ts +14 -0
- package/src/server/responses/core-combo.ts +7 -2
- package/src/server/responses/core-errors.ts +29 -1
- package/src/server/responses/core-options.ts +2 -0
- package/src/server/responses/deferred-collab-surface.ts +158 -0
- package/src/server/responses/deferred-send-reporter.ts +25 -0
- package/src/server/responses/fetch-helpers.ts +12 -1
- package/src/server/responses/passthrough-delivery.ts +4 -1
- package/src/server/responses/passthrough-dispatch.ts +15 -4
- package/src/server/responses/request-prepare.ts +6 -4
- package/src/server/responses/request-transport.ts +6 -8
- package/src/server/responses/sidecar-execution.ts +11 -2
- package/src/server/responses/ws-upstream.ts +9 -1
- package/src/server/startup-action-control.ts +22 -2
- package/src/server/startup-health-cache.ts +4 -0
- package/src/server/system-env-shell.ts +7 -2
- package/src/server/system-env.ts +11 -1
- package/src/service/cli.ts +5 -1
- package/src/service/desktop-startup.ts +147 -34
- package/src/service/desktop-supervision.d.mts +27 -1
- package/src/service/desktop-supervision.mjs +111 -5
- package/src/service/health-sentinel-launch.ts +176 -0
- package/src/service/health-sentinel-main.ts +447 -0
- package/src/service/health-sentinel-policy.ts +241 -0
- package/src/service/health-sentinel-probe.ts +54 -0
- package/src/service/health-sentinel-windows.ts +87 -0
- package/src/service/linux-linger.ts +20 -0
- package/src/types/config.ts +5 -0
- package/src/usage/expected-prices.ts +4 -0
- package/src/usage/log.ts +19 -1
- package/gui/dist/assets/App-Ba8uG696.js +0 -54
- package/gui/dist/assets/Tray-IImbNPRy.js +0 -1
- package/gui/dist/assets/index-BHRZdJuv.js +0 -94
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { atomicWriteFile } from "../../config/atomic-write";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { linkKnownHostsPath, linkStorePath } from "../../link/paths";
|
|
5
|
+
import { clearCompensationFailed, compensationPath, markCompensationFailed } from "../../link/compensation";
|
|
6
|
+
import { readLinkStore, writeLinkStore, type LinkStore } from "../../link/store";
|
|
7
|
+
import { boundHint, createSshRunner, type SshRunner } from "../../link/ssh-runner";
|
|
8
|
+
import { withConfigMutationLockSync } from "../../config/mutation-lock";
|
|
9
|
+
import type { ManagementContext } from "./context";
|
|
10
|
+
import { issueApiKeyInProcess, revokeApiKeyInProcess, type IssuedApiKey } from "./oauth-account-routes";
|
|
11
|
+
|
|
12
|
+
export interface PendingLinkHost {
|
|
13
|
+
alias: string;
|
|
14
|
+
fingerprint: string;
|
|
15
|
+
keyType: string;
|
|
16
|
+
knownHostLine: string;
|
|
17
|
+
probedAt: number;
|
|
18
|
+
sshLatencyMs?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ConfirmedLinkHost extends PendingLinkHost {
|
|
22
|
+
ocxVersion: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface LinkRouteListener {
|
|
26
|
+
ensureStarted(): Promise<void>;
|
|
27
|
+
status(): { state: "off" | "listening" | "failed"; port: number | null; reason: string | null };
|
|
28
|
+
close(): Promise<void>;
|
|
29
|
+
onAuthenticatedCatalog(listener: (apiKeyId: string) => void): () => void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface LinkRouteState {
|
|
33
|
+
pendingHosts: Map<string, PendingLinkHost>;
|
|
34
|
+
operations?: Set<string>;
|
|
35
|
+
confirmedHosts?: Map<string, ConfirmedLinkHost>;
|
|
36
|
+
compensationFailures?: Map<string, { since: string; reason: "compensation_failed" }>;
|
|
37
|
+
supervisor: import("../../link/supervisor").LinkSupervisor;
|
|
38
|
+
listener: LinkRouteListener;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function fail(code: string, message: string, status: number, hint?: string): Response {
|
|
42
|
+
return Response.json({ error: { code, message, ...(hint ? { hint } : {}) } }, { status, headers: { "cache-control": "no-store" } });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
46
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function exactBody(body: unknown, keys: readonly string[]): Record<string, unknown> | null {
|
|
50
|
+
if (!isRecord(body)) return null;
|
|
51
|
+
const actual = Object.keys(body).sort();
|
|
52
|
+
const expected = [...keys].sort();
|
|
53
|
+
return actual.length === expected.length && actual.every((key, index) => key === expected[index]) ? body : null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function port(value: unknown): value is number {
|
|
57
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= 65535;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A GUI session redeemed from an operator-created, one-use pairing grant. */
|
|
61
|
+
export function pairedSession(ctx: ManagementContext): boolean {
|
|
62
|
+
return ctx.principal === "gui-session"
|
|
63
|
+
&& ctx.sessionControl?.isPaired(ctx.req, ctx.config) === true;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* A paired session, or on a standalone runtime the current loopback-issued session that reached
|
|
68
|
+
* the public listener bound to a loopback hostname. The loopback bootstrap mints that session
|
|
69
|
+
* without a credential, so this is casual-path protection like POST /api/github/star, not a
|
|
70
|
+
* secret-backed boundary like the admin token. Hubs keep the paired-only rule. Durable operations
|
|
71
|
+
* that require operator approval, such as joining this machine as a Child, use pairedSession.
|
|
72
|
+
*/
|
|
73
|
+
export function dashboardSession(ctx: ManagementContext): boolean {
|
|
74
|
+
if (pairedSession(ctx)) return true;
|
|
75
|
+
return ctx.principal === "gui-session"
|
|
76
|
+
&& (ctx.config.runtimeRole ?? "standalone") === "standalone"
|
|
77
|
+
&& ctx.guiSessionIssuance === "loopback"
|
|
78
|
+
&& ctx.trustedLoopbackIngress
|
|
79
|
+
&& ctx.sessionControl?.isCurrent(ctx.req, ctx.config) === true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function adminLoopback(ctx: ManagementContext): boolean {
|
|
83
|
+
return ctx.principal === "admin-token" && ctx.trustedLoopbackIngress;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function auth(ctx: ManagementContext, kind: "dashboard" | "paired" | "admin" | "either"): Response | null {
|
|
87
|
+
if (ctx.guiSessionIssuance === "tailscale-identity") return fail("tailscale_session_refused", "Tailscale identity sessions cannot use link routes.", 403);
|
|
88
|
+
const allowed = kind === "dashboard" ? dashboardSession(ctx)
|
|
89
|
+
: kind === "paired" ? pairedSession(ctx)
|
|
90
|
+
: kind === "admin" ? adminLoopback(ctx)
|
|
91
|
+
: dashboardSession(ctx) || adminLoopback(ctx);
|
|
92
|
+
return allowed ? null : fail("forbidden", "The required link authorization was not present.", 403);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function runnerFor(ctx: ManagementContext): SshRunner {
|
|
96
|
+
return ctx.deps.sshRunner ?? createSshRunner();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function readStoreFor(ctx: ManagementContext): LinkStore {
|
|
100
|
+
return ctx.deps.readLinkStore?.() ?? readLinkStore(linkStorePath());
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function writeStoreFor(ctx: ManagementContext, store: LinkStore): void {
|
|
104
|
+
(ctx.deps.writeLinkStore ?? (value => writeLinkStore(linkStorePath(), value)))(store);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function knownHostsFile(ctx: ManagementContext): string {
|
|
108
|
+
return ctx.deps.linkKnownHostsPath?.() ?? linkKnownHostsPath();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function putKnownHost(path: string, alias: string, line: string): string {
|
|
112
|
+
const before = (() => { try { return readFileSync(path, "utf8"); } catch { return ""; } })();
|
|
113
|
+
const lines = before.split(/\r?\n/).filter(value => value && !value.startsWith(`${alias} `) && !value.startsWith(`${alias},`));
|
|
114
|
+
lines.push(line.trim());
|
|
115
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
116
|
+
atomicWriteFile(path, `${lines.join("\n")}\n`);
|
|
117
|
+
return before;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function issueKey(ctx: ManagementContext, name: string): IssuedApiKey {
|
|
121
|
+
return (ctx.deps.issueApiKey ?? issueApiKeyInProcess)(ctx.config, name);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function revokeKey(ctx: ManagementContext, id: string): boolean {
|
|
125
|
+
return (ctx.deps.revokeApiKey ?? revokeApiKeyInProcess)(ctx.config, id);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Revocation that a retry can repeat. A key that is no longer in the live config is already
|
|
130
|
+
* revoked, which is exactly the state a partially completed cleanup leaves behind; without this
|
|
131
|
+
* a retried DELETE would fail forever on the key it removed the first time.
|
|
132
|
+
*/
|
|
133
|
+
export function revokeKeyIdempotent(ctx: ManagementContext, id: string): boolean {
|
|
134
|
+
let revoked = false;
|
|
135
|
+
try { revoked = revokeKey(ctx, id); } catch { revoked = false; }
|
|
136
|
+
if (revoked) return true;
|
|
137
|
+
return !(ctx.config.apiKeys ?? []).some(entry => entry.id === id);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function compensationFailure(ctx: ManagementContext, state: LinkRouteState, record: LinkStore["links"][number], phase: string): Response {
|
|
141
|
+
const since = new Date((ctx.deps.now ?? Date.now)()).toISOString();
|
|
142
|
+
(state.compensationFailures ??= new Map()).set(record.id, { since, reason: "compensation_failed" });
|
|
143
|
+
try { markCompensationFailed(record.id, since, compensationPath()); } catch (error) {
|
|
144
|
+
console.warn(`[link] compensation marker persistence failed linkId=${record.id}: ${error instanceof Error ? error.message : String(error)}`);
|
|
145
|
+
}
|
|
146
|
+
console.warn(`[link] compensation_failed linkId=${record.id} phase=${phase}`);
|
|
147
|
+
return fail("compensation_failed", "The link compensation could not be completed.", 500);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export async function compensateNewLink(ctx: ManagementContext, state: LinkRouteState, record: LinkStore["links"][number]): Promise<Response | null> {
|
|
151
|
+
const revoked = revokeKeyIdempotent(ctx, record.apiKeyId);
|
|
152
|
+
if (!revoked) {
|
|
153
|
+
try { await state.supervisor.stopLink(record.id); } catch { /* retain the record and failure marker */ }
|
|
154
|
+
try {
|
|
155
|
+
withConfigMutationLockSync(() => {
|
|
156
|
+
const current = readStoreFor(ctx);
|
|
157
|
+
if (!current.links.some(link => link.id === record.id)) {
|
|
158
|
+
writeStoreFor(ctx, { ...current, links: [...current.links, record] });
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
} catch {
|
|
162
|
+
// The in-memory marker still makes the residual visible when persistence is unavailable.
|
|
163
|
+
}
|
|
164
|
+
return compensationFailure(ctx, state, record, "revoke");
|
|
165
|
+
}
|
|
166
|
+
try { await state.supervisor.stopLink(record.id); } catch { return compensationFailure(ctx, state, record, "stop"); }
|
|
167
|
+
try {
|
|
168
|
+
// Read→filter→write stays one section of the shared mutation lock: a sibling
|
|
169
|
+
// route's create must not land between the read and the rename and vanish.
|
|
170
|
+
const next = withConfigMutationLockSync(() => {
|
|
171
|
+
const current = readStoreFor(ctx);
|
|
172
|
+
const filtered = { ...current, links: current.links.filter(link => link.id !== record.id) };
|
|
173
|
+
if (filtered.links.length !== current.links.length) {
|
|
174
|
+
writeStoreFor(ctx, filtered);
|
|
175
|
+
}
|
|
176
|
+
return filtered;
|
|
177
|
+
});
|
|
178
|
+
clearCompensationFailed(record.id, compensationPath());
|
|
179
|
+
state.compensationFailures?.delete(record.id);
|
|
180
|
+
if (next.links.length === 0) await state.listener.close();
|
|
181
|
+
return null;
|
|
182
|
+
} catch {
|
|
183
|
+
return compensationFailure(ctx, state, record, "store");
|
|
184
|
+
}
|
|
185
|
+
}
|