@rex0220/ksql-flownet 1.0.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/LICENSE +21 -0
- package/README.ja.md +81 -0
- package/README.md +117 -0
- package/dist/bundle/bundle-builder.d.ts +49 -0
- package/dist/bundle/bundle-builder.js +208 -0
- package/dist/bundle/index.d.ts +4 -0
- package/dist/bundle/index.js +4 -0
- package/dist/bundle/upload.d.ts +28 -0
- package/dist/bundle/upload.js +72 -0
- package/dist/bundle/zip-store.d.ts +17 -0
- package/dist/bundle/zip-store.js +175 -0
- package/dist/cli/archive-run-command.d.ts +12 -0
- package/dist/cli/archive-run-command.js +131 -0
- package/dist/cli/cancel-run-command.d.ts +9 -0
- package/dist/cli/cancel-run-command.js +77 -0
- package/dist/cli/force-unlock-network-command.d.ts +8 -0
- package/dist/cli/force-unlock-network-command.js +129 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +132 -0
- package/dist/cli/plan-command.d.ts +2 -0
- package/dist/cli/plan-command.js +100 -0
- package/dist/cli/poll-requests-command.d.ts +3 -0
- package/dist/cli/poll-requests-command.js +74 -0
- package/dist/cli/record-job-unlock-command.d.ts +11 -0
- package/dist/cli/record-job-unlock-command.js +78 -0
- package/dist/cli/resolve-node-command.d.ts +13 -0
- package/dist/cli/resolve-node-command.js +174 -0
- package/dist/cli/run-network-command.d.ts +14 -0
- package/dist/cli/run-network-command.js +418 -0
- package/dist/cli/status-command.d.ts +5 -0
- package/dist/cli/status-command.js +137 -0
- package/dist/cli/validate-command.d.ts +6 -0
- package/dist/cli/validate-command.js +17 -0
- package/dist/dag/descendants.d.ts +9 -0
- package/dist/dag/descendants.js +67 -0
- package/dist/dag/topological-sort.d.ts +7 -0
- package/dist/dag/topological-sort.js +32 -0
- package/dist/domain/business-key.d.ts +15 -0
- package/dist/domain/business-key.js +249 -0
- package/dist/domain/canonical-lock-key.d.ts +17 -0
- package/dist/domain/canonical-lock-key.js +60 -0
- package/dist/domain/canonical-record-key.d.ts +18 -0
- package/dist/domain/canonical-record-key.js +70 -0
- package/dist/domain/load-network.d.ts +4 -0
- package/dist/domain/load-network.js +47 -0
- package/dist/domain/network-definition.d.ts +47 -0
- package/dist/domain/network-definition.js +7 -0
- package/dist/domain/persistence-model.d.ts +198 -0
- package/dist/domain/persistence-model.js +2 -0
- package/dist/domain/run-aggregate.d.ts +3 -0
- package/dist/domain/run-aggregate.js +15 -0
- package/dist/domain/validate-network-path.d.ts +11 -0
- package/dist/domain/validate-network-path.js +33 -0
- package/dist/domain/validate-network.d.ts +3 -0
- package/dist/domain/validate-network.js +180 -0
- package/dist/executor/attempt-executor.d.ts +43 -0
- package/dist/executor/attempt-executor.js +236 -0
- package/dist/executor/job-log-reader.d.ts +37 -0
- package/dist/executor/job-log-reader.js +91 -0
- package/dist/executor/ksql-flow-cli.d.ts +86 -0
- package/dist/executor/ksql-flow-cli.js +161 -0
- package/dist/executor/preflight.d.ts +41 -0
- package/dist/executor/preflight.js +150 -0
- package/dist/executor/result-classifier.d.ts +69 -0
- package/dist/executor/result-classifier.js +237 -0
- package/dist/executor/run-subprocess.d.ts +64 -0
- package/dist/executor/run-subprocess.js +175 -0
- package/dist/io/input-baseline.d.ts +19 -0
- package/dist/io/input-baseline.js +214 -0
- package/dist/io/io-config.d.ts +6 -0
- package/dist/io/io-config.js +33 -0
- package/dist/io/io-path.d.ts +37 -0
- package/dist/io/io-path.js +279 -0
- package/dist/orchestration/archive-run.d.ts +53 -0
- package/dist/orchestration/archive-run.js +323 -0
- package/dist/orchestration/cancel-request.d.ts +18 -0
- package/dist/orchestration/cancel-request.js +67 -0
- package/dist/orchestration/ensure-run.d.ts +83 -0
- package/dist/orchestration/ensure-run.js +632 -0
- package/dist/orchestration/job-lock-audit.d.ts +24 -0
- package/dist/orchestration/job-lock-audit.js +123 -0
- package/dist/orchestration/orphan-attempt-adjudication.d.ts +39 -0
- package/dist/orchestration/orphan-attempt-adjudication.js +167 -0
- package/dist/orchestration/reconciliation.d.ts +41 -0
- package/dist/orchestration/reconciliation.js +526 -0
- package/dist/orchestration/resolve-node.d.ts +29 -0
- package/dist/orchestration/resolve-node.js +105 -0
- package/dist/orchestration/run-activity.d.ts +13 -0
- package/dist/orchestration/run-activity.js +14 -0
- package/dist/orchestration/sequential-scheduler.d.ts +79 -0
- package/dist/orchestration/sequential-scheduler.js +706 -0
- package/dist/orchestration/status.d.ts +91 -0
- package/dist/orchestration/status.js +171 -0
- package/dist/persistence/in-memory-repository.d.ts +41 -0
- package/dist/persistence/in-memory-repository.js +333 -0
- package/dist/persistence/kintone/client.d.ts +36 -0
- package/dist/persistence/kintone/client.js +93 -0
- package/dist/persistence/kintone/design-notes.d.ts +38 -0
- package/dist/persistence/kintone/design-notes.js +38 -0
- package/dist/persistence/kintone/repository.d.ts +44 -0
- package/dist/persistence/kintone/repository.js +836 -0
- package/dist/persistence/kintone/schema.d.ts +116 -0
- package/dist/persistence/kintone/schema.js +115 -0
- package/dist/persistence/network-lock-reader.d.ts +24 -0
- package/dist/persistence/network-lock-reader.js +43 -0
- package/dist/persistence/network-lock-recovery.d.ts +66 -0
- package/dist/persistence/network-lock-recovery.js +392 -0
- package/dist/persistence/network-lock.d.ts +97 -0
- package/dist/persistence/network-lock.js +408 -0
- package/dist/persistence/repository.d.ts +101 -0
- package/dist/persistence/repository.js +11 -0
- package/dist/persistence/state-transition.d.ts +4 -0
- package/dist/persistence/state-transition.js +25 -0
- package/dist/requests/flownet-child-client.d.ts +78 -0
- package/dist/requests/flownet-child-client.js +243 -0
- package/dist/requests/kintone-request-store.d.ts +44 -0
- package/dist/requests/kintone-request-store.js +202 -0
- package/dist/requests/poll-requests-config.d.ts +26 -0
- package/dist/requests/poll-requests-config.js +105 -0
- package/dist/requests/request-model.d.ts +57 -0
- package/dist/requests/request-model.js +305 -0
- package/dist/requests/request-poller.d.ts +33 -0
- package/dist/requests/request-poller.js +353 -0
- package/dist/requests/request-result.d.ts +18 -0
- package/dist/requests/request-result.js +215 -0
- package/dist/requests/start-request.d.ts +26 -0
- package/dist/requests/start-request.js +83 -0
- package/package.json +63 -0
- package/schemas/.gitkeep +1 -0
- package/schemas/network-definition.schema.json +121 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { NetworkRun, NodeAttempt, NodeState, RunInvocation } from "../domain/persistence-model.js";
|
|
2
|
+
import type { NetworkLockStatus, NetworkLockStatusReader } from "../persistence/network-lock-reader.js";
|
|
3
|
+
import type { StatusReadRepository } from "../persistence/repository.js";
|
|
4
|
+
import { type RunActivity } from "./run-activity.js";
|
|
5
|
+
export { deriveRunActivity, type ActivityInput, type RunActivity, } from "./run-activity.js";
|
|
6
|
+
export interface StatusInput {
|
|
7
|
+
readonly networkId: string;
|
|
8
|
+
readonly profile: string;
|
|
9
|
+
readonly runId?: string;
|
|
10
|
+
readonly businessKey?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface StatusDependencies {
|
|
13
|
+
readonly repository: StatusReadRepository;
|
|
14
|
+
readonly lockReader: NetworkLockStatusReader;
|
|
15
|
+
readonly now?: () => Date;
|
|
16
|
+
}
|
|
17
|
+
export interface StatusOutput {
|
|
18
|
+
readonly network_id: string;
|
|
19
|
+
readonly profile: string;
|
|
20
|
+
readonly lock: (NetworkLockStatus & {
|
|
21
|
+
readonly stale_candidate: boolean;
|
|
22
|
+
}) | null;
|
|
23
|
+
readonly runs: readonly RunStatusOutput[];
|
|
24
|
+
}
|
|
25
|
+
export interface RunSummaryOutput {
|
|
26
|
+
readonly run_id: string;
|
|
27
|
+
readonly business_key: string;
|
|
28
|
+
readonly status: NetworkRun["status"];
|
|
29
|
+
readonly resume_allowed: boolean;
|
|
30
|
+
readonly lifecycle_status: NetworkRun["lifecycle_status"];
|
|
31
|
+
readonly created_at: string;
|
|
32
|
+
readonly started_at: string | null;
|
|
33
|
+
readonly finished_at: string | null;
|
|
34
|
+
readonly updated_at: string;
|
|
35
|
+
readonly hold: {
|
|
36
|
+
readonly state: "REQUESTED" | "ACCEPTED";
|
|
37
|
+
readonly requested_by: string;
|
|
38
|
+
readonly requested_at: string;
|
|
39
|
+
} | null;
|
|
40
|
+
readonly activity?: RunActivity;
|
|
41
|
+
}
|
|
42
|
+
export interface RunStatusOutput extends RunSummaryOutput {
|
|
43
|
+
readonly invocations?: readonly InvocationOutput[];
|
|
44
|
+
readonly node_states?: readonly NodeStateOutput[];
|
|
45
|
+
readonly reconciliation?: {
|
|
46
|
+
readonly inconsistencies: readonly {
|
|
47
|
+
readonly code: string;
|
|
48
|
+
readonly node_id?: string;
|
|
49
|
+
readonly detail: string;
|
|
50
|
+
readonly attempt_ids?: readonly string[];
|
|
51
|
+
}[];
|
|
52
|
+
};
|
|
53
|
+
readonly recovery_identifiers?: {
|
|
54
|
+
readonly resolve_node: readonly {
|
|
55
|
+
readonly run_id: string;
|
|
56
|
+
readonly node_id: string;
|
|
57
|
+
}[];
|
|
58
|
+
readonly force_unlock_network: {
|
|
59
|
+
readonly network_id: string;
|
|
60
|
+
readonly profile: string;
|
|
61
|
+
readonly expected_owner_invocation_id: string;
|
|
62
|
+
} | null;
|
|
63
|
+
readonly run_network: {
|
|
64
|
+
readonly resume_run: string;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
interface InvocationOutput {
|
|
69
|
+
readonly invocation_id: string;
|
|
70
|
+
readonly mode: RunInvocation["mode"];
|
|
71
|
+
readonly status: RunInvocation["status"];
|
|
72
|
+
readonly result_code: string;
|
|
73
|
+
}
|
|
74
|
+
interface AttemptSummaryOutput {
|
|
75
|
+
readonly node_attempt_id: string;
|
|
76
|
+
readonly attempt_no: number;
|
|
77
|
+
readonly status: NodeAttempt["status"];
|
|
78
|
+
readonly result_code: string;
|
|
79
|
+
}
|
|
80
|
+
interface NodeStateOutput {
|
|
81
|
+
readonly node_id: string;
|
|
82
|
+
readonly status: NodeState["status"];
|
|
83
|
+
readonly status_reason: string | null;
|
|
84
|
+
readonly idempotent: boolean;
|
|
85
|
+
readonly latest_attempt_no: number;
|
|
86
|
+
readonly active_attempt_id: string | null;
|
|
87
|
+
readonly latest_attempt: AttemptSummaryOutput | null;
|
|
88
|
+
readonly active_attempt: AttemptSummaryOutput | null;
|
|
89
|
+
}
|
|
90
|
+
export declare function inspectStatus(input: StatusInput, dependencies: StatusDependencies): Promise<StatusOutput>;
|
|
91
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { KINTONE_DATETIME_TRUNCATION_MS } from "../persistence/kintone/design-notes.js";
|
|
2
|
+
import { RepositoryError } from "../persistence/repository.js";
|
|
3
|
+
import { detectReconciliation } from "./reconciliation.js";
|
|
4
|
+
import { deriveRunActivity } from "./run-activity.js";
|
|
5
|
+
export { deriveRunActivity, } from "./run-activity.js";
|
|
6
|
+
function summary(run, activity, cancelRequest) {
|
|
7
|
+
return {
|
|
8
|
+
run_id: run.run_id,
|
|
9
|
+
business_key: run.business_key,
|
|
10
|
+
status: run.status,
|
|
11
|
+
resume_allowed: run.resume_allowed,
|
|
12
|
+
lifecycle_status: run.lifecycle_status,
|
|
13
|
+
created_at: run.created_at,
|
|
14
|
+
started_at: run.started_at,
|
|
15
|
+
finished_at: run.finished_at,
|
|
16
|
+
updated_at: run.updated_at,
|
|
17
|
+
hold: cancelRequest !== null &&
|
|
18
|
+
(cancelRequest.value.state === "REQUESTED" ||
|
|
19
|
+
cancelRequest.value.state === "ACCEPTED")
|
|
20
|
+
? {
|
|
21
|
+
state: cancelRequest.value.state,
|
|
22
|
+
requested_by: cancelRequest.value.requested_by,
|
|
23
|
+
requested_at: cancelRequest.value.requested_at,
|
|
24
|
+
}
|
|
25
|
+
: null,
|
|
26
|
+
...(activity === null ? {} : { activity }),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function requireMatchingRun(run, input) {
|
|
30
|
+
if (run.value.network_id !== input.networkId ||
|
|
31
|
+
run.value.resolved_profile_snapshot.profile !== input.profile) {
|
|
32
|
+
throw new RepositoryError("RECORD_NOT_FOUND", "the selected Run does not belong to the requested network and profile");
|
|
33
|
+
}
|
|
34
|
+
return run;
|
|
35
|
+
}
|
|
36
|
+
async function detail(run, lock, repository, currentTime) {
|
|
37
|
+
const runId = run.value.run_id;
|
|
38
|
+
const [invocations, states, attempts, reconciliation, cancelRequest] = await Promise.all([
|
|
39
|
+
repository.getInvocations(runId),
|
|
40
|
+
repository.getNodeStates(runId),
|
|
41
|
+
repository.getAttempts(runId),
|
|
42
|
+
detectReconciliation(repository, runId),
|
|
43
|
+
repository.getCancelRequest(runId),
|
|
44
|
+
]);
|
|
45
|
+
const attemptsById = new Map(attempts.map((attempt) => [attempt.value.node_attempt_id, attempt.value]));
|
|
46
|
+
const attemptsByNodeAndNumber = new Map(attempts.map((attempt) => [
|
|
47
|
+
`${attempt.value.node_id}\0${attempt.value.attempt_no}`,
|
|
48
|
+
attempt.value,
|
|
49
|
+
]));
|
|
50
|
+
return {
|
|
51
|
+
...summary(run.value, deriveRunActivity({
|
|
52
|
+
status: run.value.status,
|
|
53
|
+
startedAt: run.value.started_at,
|
|
54
|
+
invocationIds: invocations.map(({ value }) => value.invocation_id),
|
|
55
|
+
lock,
|
|
56
|
+
cancelState: cancelRequest?.value.state ?? null,
|
|
57
|
+
nowMs: currentTime,
|
|
58
|
+
}), cancelRequest),
|
|
59
|
+
invocations: invocations.map(({ value }) => ({
|
|
60
|
+
invocation_id: value.invocation_id,
|
|
61
|
+
mode: value.mode,
|
|
62
|
+
status: value.status,
|
|
63
|
+
result_code: value.result_code,
|
|
64
|
+
})),
|
|
65
|
+
node_states: states.map(({ value }) => {
|
|
66
|
+
const active = value.active_attempt_id === null
|
|
67
|
+
? undefined
|
|
68
|
+
: attemptsById.get(value.active_attempt_id);
|
|
69
|
+
const latest = value.latest_attempt_no === 0
|
|
70
|
+
? undefined
|
|
71
|
+
: attemptsByNodeAndNumber.get(`${value.node_id}\0${value.latest_attempt_no}`);
|
|
72
|
+
return {
|
|
73
|
+
node_id: value.node_id,
|
|
74
|
+
status: value.status,
|
|
75
|
+
status_reason: value.status_reason,
|
|
76
|
+
idempotent: value.idempotent,
|
|
77
|
+
latest_attempt_no: value.latest_attempt_no,
|
|
78
|
+
active_attempt_id: value.active_attempt_id,
|
|
79
|
+
latest_attempt: latest === undefined ? null : attemptSummary(latest),
|
|
80
|
+
active_attempt: active === undefined ? null : attemptSummary(active),
|
|
81
|
+
};
|
|
82
|
+
}),
|
|
83
|
+
reconciliation: {
|
|
84
|
+
inconsistencies: reconciliation.inconsistencies.map((item) => ({
|
|
85
|
+
code: item.code,
|
|
86
|
+
...(item.nodeId === undefined ? {} : { node_id: item.nodeId }),
|
|
87
|
+
detail: item.detail,
|
|
88
|
+
...(item.attemptIds === undefined
|
|
89
|
+
? {}
|
|
90
|
+
: { attempt_ids: item.attemptIds }),
|
|
91
|
+
})),
|
|
92
|
+
},
|
|
93
|
+
recovery_identifiers: {
|
|
94
|
+
resolve_node: states
|
|
95
|
+
.filter(({ value }) => value.status === "UNKNOWN" ||
|
|
96
|
+
(value.status === "FAILED" && !value.idempotent))
|
|
97
|
+
.map(({ value }) => ({ run_id: runId, node_id: value.node_id })),
|
|
98
|
+
force_unlock_network: lock === null
|
|
99
|
+
? null
|
|
100
|
+
: {
|
|
101
|
+
network_id: run.value.network_id,
|
|
102
|
+
profile: run.value.resolved_profile_snapshot.profile,
|
|
103
|
+
expected_owner_invocation_id: lock.owner_invocation_id,
|
|
104
|
+
},
|
|
105
|
+
run_network: { resume_run: runId },
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function attemptSummary(attempt) {
|
|
110
|
+
return {
|
|
111
|
+
node_attempt_id: attempt.node_attempt_id,
|
|
112
|
+
attempt_no: attempt.attempt_no,
|
|
113
|
+
status: attempt.status,
|
|
114
|
+
result_code: attempt.result_code,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export async function inspectStatus(input, dependencies) {
|
|
118
|
+
const currentTime = (dependencies.now ?? (() => new Date()))().getTime();
|
|
119
|
+
const lockValue = await dependencies.lockReader.getNetworkLock(input.profile, input.networkId);
|
|
120
|
+
const lock = lockValue === null
|
|
121
|
+
? null
|
|
122
|
+
: {
|
|
123
|
+
record_id: lockValue.record_id,
|
|
124
|
+
owner_invocation_id: lockValue.owner_invocation_id,
|
|
125
|
+
owner_instance_id: lockValue.owner_instance_id,
|
|
126
|
+
heartbeat_at: lockValue.heartbeat_at,
|
|
127
|
+
lease_expires_at: lockValue.lease_expires_at,
|
|
128
|
+
// The persisted lease expiry may be truncated by up to 59 seconds, so add the upper bound before marking it stale.
|
|
129
|
+
stale_candidate: currentTime >
|
|
130
|
+
Date.parse(lockValue.lease_expires_at) +
|
|
131
|
+
KINTONE_DATETIME_TRUNCATION_MS,
|
|
132
|
+
revision: lockValue.revision,
|
|
133
|
+
};
|
|
134
|
+
if (input.runId !== undefined || input.businessKey !== undefined) {
|
|
135
|
+
const found = input.runId !== undefined
|
|
136
|
+
? await dependencies.repository.getRun(input.runId)
|
|
137
|
+
: await dependencies.repository.getRunByBusinessKey(input.profile, input.networkId, input.businessKey);
|
|
138
|
+
if (found === null) {
|
|
139
|
+
throw new RepositoryError("RECORD_NOT_FOUND", "Run was not found");
|
|
140
|
+
}
|
|
141
|
+
const run = requireMatchingRun(found, input);
|
|
142
|
+
return {
|
|
143
|
+
network_id: input.networkId,
|
|
144
|
+
profile: input.profile,
|
|
145
|
+
lock,
|
|
146
|
+
runs: [await detail(run, lock, dependencies.repository, currentTime)],
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const runs = await dependencies.repository.listRuns(input.profile, input.networkId);
|
|
150
|
+
const summaries = await Promise.all(runs.map(async (run) => {
|
|
151
|
+
const [invocations, cancelRequest] = await Promise.all([
|
|
152
|
+
dependencies.repository.getInvocations(run.value.run_id),
|
|
153
|
+
dependencies.repository.getCancelRequest(run.value.run_id),
|
|
154
|
+
]);
|
|
155
|
+
return summary(run.value, deriveRunActivity({
|
|
156
|
+
status: run.value.status,
|
|
157
|
+
startedAt: run.value.started_at,
|
|
158
|
+
invocationIds: invocations.map(({ value }) => value.invocation_id),
|
|
159
|
+
lock,
|
|
160
|
+
cancelState: cancelRequest?.value.state ?? null,
|
|
161
|
+
nowMs: currentTime,
|
|
162
|
+
}), cancelRequest);
|
|
163
|
+
}));
|
|
164
|
+
return {
|
|
165
|
+
network_id: input.networkId,
|
|
166
|
+
profile: input.profile,
|
|
167
|
+
lock,
|
|
168
|
+
runs: summaries,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AttemptResolution, CancelRequest, NetworkRun, NodeAttempt, NodeState, OperationAudit, RunInvocation } from "../domain/persistence-model.js";
|
|
2
|
+
import type { AttemptExecutionStart, AttemptInputBaselineWrite, AttemptFinalization, CreateAttemptInput, Inconsistency, InvocationFinalization, NodeStateWrite, PersistenceRepository, RunAggregateUpdate, Versioned } from "./repository.js";
|
|
3
|
+
/** A deterministic component-test fake. It intentionally models unique keys and revisions. */
|
|
4
|
+
export declare class InMemoryPersistenceRepository implements PersistenceRepository {
|
|
5
|
+
private readonly runs;
|
|
6
|
+
private readonly runKeys;
|
|
7
|
+
private readonly invocations;
|
|
8
|
+
private readonly cancelRequests;
|
|
9
|
+
private readonly states;
|
|
10
|
+
private readonly attempts;
|
|
11
|
+
private readonly attemptIds;
|
|
12
|
+
private readonly resolutions;
|
|
13
|
+
private readonly operationAudits;
|
|
14
|
+
createRun(run: NetworkRun): Promise<Versioned<NetworkRun>>;
|
|
15
|
+
getRunByBusinessKey(profile: string, networkId: string, businessKey: string): Promise<Versioned<NetworkRun> | null>;
|
|
16
|
+
getRun(runId: string): Promise<Versioned<NetworkRun>>;
|
|
17
|
+
listRuns(profile: string, networkId: string): Promise<Versioned<NetworkRun>[]>;
|
|
18
|
+
getCancelRequest(runId: string): Promise<Versioned<CancelRequest> | null>;
|
|
19
|
+
createCancelRequest(request: CancelRequest): Promise<Versioned<CancelRequest>>;
|
|
20
|
+
updateCancelRequest(runId: string, expectedRevision: number, request: CancelRequest): Promise<Versioned<CancelRequest>>;
|
|
21
|
+
updateRunAggregate(runId: string, expectedRevision: number, update: RunAggregateUpdate): Promise<Versioned<NetworkRun>>;
|
|
22
|
+
archiveRun(runId: string, expectedRevision: number, at: string): Promise<Versioned<NetworkRun>>;
|
|
23
|
+
createInvocation(invocation: RunInvocation): Promise<Versioned<RunInvocation>>;
|
|
24
|
+
getInvocations(runId: string): Promise<Versioned<RunInvocation>[]>;
|
|
25
|
+
finalizeInvocation(invocationId: string, expectedRevision: number, finalization: InvocationFinalization): Promise<Versioned<RunInvocation>>;
|
|
26
|
+
getNodeStates(runId: string): Promise<Versioned<NodeState>[]>;
|
|
27
|
+
getAttempts(runId: string): Promise<Versioned<NodeAttempt>[]>;
|
|
28
|
+
getResolutions(runId: string): Promise<Versioned<AttemptResolution>[]>;
|
|
29
|
+
upsertNodeState(write: NodeStateWrite): Promise<Versioned<NodeState>>;
|
|
30
|
+
createAttempt(input: CreateAttemptInput): Promise<Versioned<NodeAttempt>>;
|
|
31
|
+
setAttemptExecutionStarted(attemptId: string, expectedRevision: number, start: AttemptExecutionStart): Promise<Versioned<NodeAttempt>>;
|
|
32
|
+
setAttemptInputBaseline(attemptId: string, expectedRevision: number, write: AttemptInputBaselineWrite): Promise<Versioned<NodeAttempt>>;
|
|
33
|
+
finalizeAttempt(attemptId: string, expectedRevision: number, finalization: AttemptFinalization): Promise<Versioned<NodeAttempt>>;
|
|
34
|
+
appendResolution(resolution: AttemptResolution): Promise<Versioned<AttemptResolution>>;
|
|
35
|
+
appendOperationAudit(audit: OperationAudit): Promise<Versioned<OperationAudit>>;
|
|
36
|
+
getOperationAuditByEventId(eventId: string): Promise<Versioned<OperationAudit> | null>;
|
|
37
|
+
listInconsistencies(runId: string): Promise<Inconsistency[]>;
|
|
38
|
+
private required;
|
|
39
|
+
private attemptById;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=in-memory-repository.d.ts.map
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { attemptKey, runKey } from "../domain/canonical-record-key.js";
|
|
2
|
+
import { RepositoryError } from "./repository.js";
|
|
3
|
+
import { isAllowedNodeStateTransition, isAllowedResolutionTransition, } from "./state-transition.js";
|
|
4
|
+
function copy(stored) {
|
|
5
|
+
return structuredClone(stored);
|
|
6
|
+
}
|
|
7
|
+
function next(stored, value) {
|
|
8
|
+
stored.value = structuredClone(value);
|
|
9
|
+
stored.revision += 1;
|
|
10
|
+
return copy(stored);
|
|
11
|
+
}
|
|
12
|
+
function assertRevision(stored, expected) {
|
|
13
|
+
if (stored.revision !== expected) {
|
|
14
|
+
throw new RepositoryError("REVISION_CONFLICT", `expected revision ${expected}, actual ${stored.revision}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function isAllowedCancelTransition(from, to) {
|
|
18
|
+
return ((from === "REQUESTED" && (to === "ACCEPTED" || to === "RELEASED")) ||
|
|
19
|
+
(from === "ACCEPTED" && to === "RELEASED") ||
|
|
20
|
+
(from === "RELEASED" && to === "REQUESTED"));
|
|
21
|
+
}
|
|
22
|
+
/** A deterministic component-test fake. It intentionally models unique keys and revisions. */
|
|
23
|
+
export class InMemoryPersistenceRepository {
|
|
24
|
+
runs = new Map();
|
|
25
|
+
runKeys = new Map();
|
|
26
|
+
invocations = new Map();
|
|
27
|
+
cancelRequests = new Map();
|
|
28
|
+
states = new Map();
|
|
29
|
+
attempts = new Map();
|
|
30
|
+
attemptIds = new Map();
|
|
31
|
+
resolutions = [];
|
|
32
|
+
operationAudits = [];
|
|
33
|
+
async createRun(run) {
|
|
34
|
+
const key = runKey(run.resolved_profile_snapshot.profile, run.network_id, run.business_key);
|
|
35
|
+
if (this.runs.has(run.run_id)) {
|
|
36
|
+
throw new RepositoryError("DUPLICATE_RECORD", `run ${run.run_id} exists`);
|
|
37
|
+
}
|
|
38
|
+
if (this.runKeys.has(key)) {
|
|
39
|
+
throw new RepositoryError("DUPLICATE_RECORD", "profile/network/business key already exists");
|
|
40
|
+
}
|
|
41
|
+
const stored = { value: structuredClone(run), revision: 1 };
|
|
42
|
+
this.runs.set(run.run_id, stored);
|
|
43
|
+
this.runKeys.set(key, run.run_id);
|
|
44
|
+
return copy(stored);
|
|
45
|
+
}
|
|
46
|
+
async getRunByBusinessKey(profile, networkId, businessKey) {
|
|
47
|
+
const runId = this.runKeys.get(runKey(profile, networkId, businessKey));
|
|
48
|
+
return runId ? copy(this.required(this.runs, runId, "run")) : null;
|
|
49
|
+
}
|
|
50
|
+
async getRun(runId) {
|
|
51
|
+
return copy(this.required(this.runs, runId, "run"));
|
|
52
|
+
}
|
|
53
|
+
async listRuns(profile, networkId) {
|
|
54
|
+
return [...this.runs.values()]
|
|
55
|
+
.filter(({ value }) => value.resolved_profile_snapshot.profile === profile &&
|
|
56
|
+
value.network_id === networkId)
|
|
57
|
+
.map(copy)
|
|
58
|
+
.sort((left, right) => left.value.run_id.localeCompare(right.value.run_id));
|
|
59
|
+
}
|
|
60
|
+
async getCancelRequest(runId) {
|
|
61
|
+
const stored = this.cancelRequests.get(runId);
|
|
62
|
+
return stored === undefined ? null : copy(stored);
|
|
63
|
+
}
|
|
64
|
+
async createCancelRequest(request) {
|
|
65
|
+
if (this.cancelRequests.has(request.run_id))
|
|
66
|
+
throw new RepositoryError("DUPLICATE_RECORD", "cancel request exists");
|
|
67
|
+
if (request.state !== "REQUESTED")
|
|
68
|
+
throw new RepositoryError("INVALID_STATE_TRANSITION", "a new cancel request must be REQUESTED");
|
|
69
|
+
const stored = { value: structuredClone(request), revision: 1 };
|
|
70
|
+
this.cancelRequests.set(request.run_id, stored);
|
|
71
|
+
return copy(stored);
|
|
72
|
+
}
|
|
73
|
+
async updateCancelRequest(runId, expectedRevision, request) {
|
|
74
|
+
const stored = this.required(this.cancelRequests, runId, "cancel request");
|
|
75
|
+
assertRevision(stored, expectedRevision);
|
|
76
|
+
if (request.run_id !== runId ||
|
|
77
|
+
!isAllowedCancelTransition(stored.value.state, request.state))
|
|
78
|
+
throw new RepositoryError("INVALID_STATE_TRANSITION", `${stored.value.state} -> ${request.state} is not allowed`);
|
|
79
|
+
return next(stored, request);
|
|
80
|
+
}
|
|
81
|
+
async updateRunAggregate(runId, expectedRevision, update) {
|
|
82
|
+
const stored = this.required(this.runs, runId, "run");
|
|
83
|
+
assertRevision(stored, expectedRevision);
|
|
84
|
+
return next(stored, { ...stored.value, ...update });
|
|
85
|
+
}
|
|
86
|
+
async archiveRun(runId, expectedRevision, at) {
|
|
87
|
+
const stored = this.required(this.runs, runId, "run");
|
|
88
|
+
assertRevision(stored, expectedRevision);
|
|
89
|
+
return next(stored, {
|
|
90
|
+
...stored.value,
|
|
91
|
+
lifecycle_status: "ARCHIVED",
|
|
92
|
+
updated_at: at,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
async createInvocation(invocation) {
|
|
96
|
+
if (this.invocations.has(invocation.invocation_id)) {
|
|
97
|
+
throw new RepositoryError("DUPLICATE_RECORD", "invocation exists");
|
|
98
|
+
}
|
|
99
|
+
const stored = { value: structuredClone(invocation), revision: 1 };
|
|
100
|
+
this.invocations.set(invocation.invocation_id, stored);
|
|
101
|
+
return copy(stored);
|
|
102
|
+
}
|
|
103
|
+
async getInvocations(runId) {
|
|
104
|
+
// 実機の$id順に合わせ、挿入順を保持する(started_atは分精度のため順序に使わない)
|
|
105
|
+
return [...this.invocations.values()]
|
|
106
|
+
.filter(({ value }) => value.run_id === runId)
|
|
107
|
+
.map(copy);
|
|
108
|
+
}
|
|
109
|
+
async finalizeInvocation(invocationId, expectedRevision, finalization) {
|
|
110
|
+
const stored = this.required(this.invocations, invocationId, "invocation");
|
|
111
|
+
assertRevision(stored, expectedRevision);
|
|
112
|
+
const currentStatus = stored.value.status;
|
|
113
|
+
if (currentStatus !== "RUNNING" && currentStatus !== "CREATED") {
|
|
114
|
+
throw new RepositoryError("INVALID_STATE_TRANSITION", "only an unterminated invocation can be finalized");
|
|
115
|
+
}
|
|
116
|
+
const value = {
|
|
117
|
+
...stored.value,
|
|
118
|
+
status: finalization.status,
|
|
119
|
+
result_code: finalization.result_code,
|
|
120
|
+
finished_at: finalization.finished_at,
|
|
121
|
+
selected_node_ids: finalization.selected_node_ids === undefined
|
|
122
|
+
? stored.value.selected_node_ids
|
|
123
|
+
: [...finalization.selected_node_ids],
|
|
124
|
+
preserved_node_ids: finalization.preserved_node_ids === undefined
|
|
125
|
+
? stored.value.preserved_node_ids
|
|
126
|
+
: [...finalization.preserved_node_ids],
|
|
127
|
+
blocked_node_ids: finalization.blocked_node_ids === undefined
|
|
128
|
+
? stored.value.blocked_node_ids
|
|
129
|
+
: [...finalization.blocked_node_ids],
|
|
130
|
+
reason: finalization.reason ?? stored.value.reason,
|
|
131
|
+
};
|
|
132
|
+
return next(stored, value);
|
|
133
|
+
}
|
|
134
|
+
async getNodeStates(runId) {
|
|
135
|
+
return [...this.states.values()]
|
|
136
|
+
.filter(({ value }) => value.run_id === runId)
|
|
137
|
+
.map(copy)
|
|
138
|
+
.sort((a, b) => a.value.node_id.localeCompare(b.value.node_id));
|
|
139
|
+
}
|
|
140
|
+
async getAttempts(runId) {
|
|
141
|
+
return [...this.attempts.values()]
|
|
142
|
+
.filter(({ value }) => value.run_id === runId)
|
|
143
|
+
.map(copy)
|
|
144
|
+
.sort((a, b) => a.value.attempt_no - b.value.attempt_no);
|
|
145
|
+
}
|
|
146
|
+
async getResolutions(runId) {
|
|
147
|
+
const attemptIds = new Set((await this.getAttempts(runId)).map(({ value }) => value.node_attempt_id));
|
|
148
|
+
return this.resolutions
|
|
149
|
+
.filter(({ value }) => attemptIds.has(value.attempt_id))
|
|
150
|
+
.map(copy);
|
|
151
|
+
}
|
|
152
|
+
async upsertNodeState(write) {
|
|
153
|
+
const key = write.value.node_state_key;
|
|
154
|
+
const stored = this.states.get(key);
|
|
155
|
+
if (!stored) {
|
|
156
|
+
if (write.expected_revision !== null) {
|
|
157
|
+
throw new RepositoryError("RECORD_NOT_FOUND", "node state not found");
|
|
158
|
+
}
|
|
159
|
+
if (write.value.status !== "WAITING") {
|
|
160
|
+
throw new RepositoryError("INVALID_STATE_TRANSITION", "a new node state must be WAITING");
|
|
161
|
+
}
|
|
162
|
+
const created = {
|
|
163
|
+
value: structuredClone({ ...write.value, revision: 1 }),
|
|
164
|
+
revision: 1,
|
|
165
|
+
};
|
|
166
|
+
this.states.set(key, created);
|
|
167
|
+
return copy(created);
|
|
168
|
+
}
|
|
169
|
+
if (write.expected_revision === null) {
|
|
170
|
+
throw new RepositoryError("DUPLICATE_RECORD", "node state exists");
|
|
171
|
+
}
|
|
172
|
+
assertRevision(stored, write.expected_revision);
|
|
173
|
+
if (write.resolution_event !== undefined &&
|
|
174
|
+
!this.resolutions.some(({ value }) => value.event_type === write.resolution_event?.event_type &&
|
|
175
|
+
value.attempt_id === write.resolution_event?.attempt_id &&
|
|
176
|
+
value.resolved_outcome === write.resolution_event?.resolved_outcome &&
|
|
177
|
+
value.resolved_at === write.resolution_event?.resolved_at)) {
|
|
178
|
+
throw new RepositoryError("RECORD_NOT_FOUND", "the correlated Attempt Resolution is not durable");
|
|
179
|
+
}
|
|
180
|
+
const resolutionTransition = write.resolution_event !== undefined &&
|
|
181
|
+
write.resolution_event.resolved_outcome === write.value.status &&
|
|
182
|
+
isAllowedResolutionTransition(stored.value.status, write.value.status);
|
|
183
|
+
if (!isAllowedNodeStateTransition(stored.value.status, write.value.status) &&
|
|
184
|
+
!resolutionTransition) {
|
|
185
|
+
throw new RepositoryError("INVALID_STATE_TRANSITION", `${stored.value.status} -> ${write.value.status} is not allowed`);
|
|
186
|
+
}
|
|
187
|
+
if ((stored.value.status === "FAILED" ||
|
|
188
|
+
stored.value.status === "CANCELLED") &&
|
|
189
|
+
write.value.status === "WAITING" &&
|
|
190
|
+
!stored.value.idempotent) {
|
|
191
|
+
throw new RepositoryError("INVALID_STATE_TRANSITION", "a non-idempotent failed/cancelled node cannot resume automatically");
|
|
192
|
+
}
|
|
193
|
+
const revision = stored.revision + 1;
|
|
194
|
+
return next(stored, { ...structuredClone(write.value), revision });
|
|
195
|
+
}
|
|
196
|
+
async createAttempt(input) {
|
|
197
|
+
const { value: state, revision } = input.node_state;
|
|
198
|
+
const attemptNo = state.latest_attempt_no + 1;
|
|
199
|
+
const key = attemptKey(state.run_id, state.node_id, attemptNo);
|
|
200
|
+
const existing = this.attempts.get(key);
|
|
201
|
+
if (existing) {
|
|
202
|
+
if (existing.value.node_attempt_id === input.node_attempt_id) {
|
|
203
|
+
return copy(existing);
|
|
204
|
+
}
|
|
205
|
+
throw new RepositoryError("ATTEMPT_NUMBER_CONFLICT", `attempt number ${attemptNo} was already allocated`);
|
|
206
|
+
}
|
|
207
|
+
if (this.attemptIds.has(input.node_attempt_id)) {
|
|
208
|
+
throw new RepositoryError("DUPLICATE_RECORD", "attempt id exists");
|
|
209
|
+
}
|
|
210
|
+
const attempt = {
|
|
211
|
+
node_attempt_id: input.node_attempt_id,
|
|
212
|
+
attempt_key: key,
|
|
213
|
+
run_id: state.run_id,
|
|
214
|
+
node_id: state.node_id,
|
|
215
|
+
job_id: state.job_id,
|
|
216
|
+
invocation_id: input.invocation_id,
|
|
217
|
+
attempt_no: attemptNo,
|
|
218
|
+
status: "RUNNING",
|
|
219
|
+
result_code: "PENDING",
|
|
220
|
+
execution_started_at: null,
|
|
221
|
+
runner_execution_started_at: null,
|
|
222
|
+
execution_id: null,
|
|
223
|
+
finished_at: null,
|
|
224
|
+
duration_sec: null,
|
|
225
|
+
error_message: null,
|
|
226
|
+
read_count: 0,
|
|
227
|
+
written_count: 0,
|
|
228
|
+
last_successful_chunk_no: null,
|
|
229
|
+
last_written_key: null,
|
|
230
|
+
state_revision_before: revision,
|
|
231
|
+
};
|
|
232
|
+
const stored = { value: attempt, revision: 1 };
|
|
233
|
+
this.attempts.set(key, stored);
|
|
234
|
+
this.attemptIds.set(input.node_attempt_id, key);
|
|
235
|
+
return copy(stored);
|
|
236
|
+
}
|
|
237
|
+
async setAttemptExecutionStarted(attemptId, expectedRevision, start) {
|
|
238
|
+
const stored = this.attemptById(attemptId);
|
|
239
|
+
assertRevision(stored, expectedRevision);
|
|
240
|
+
if (stored.value.status !== "RUNNING") {
|
|
241
|
+
throw new RepositoryError("ATTEMPT_TERMINAL", "attempt is terminal");
|
|
242
|
+
}
|
|
243
|
+
if (stored.value.execution_started_at !== null) {
|
|
244
|
+
throw new RepositoryError("ATTEMPT_LIFECYCLE_VIOLATION", "execution_started_at is already set");
|
|
245
|
+
}
|
|
246
|
+
return next(stored, { ...stored.value, ...start });
|
|
247
|
+
}
|
|
248
|
+
async setAttemptInputBaseline(attemptId, expectedRevision, write) {
|
|
249
|
+
const stored = this.attemptById(attemptId);
|
|
250
|
+
assertRevision(stored, expectedRevision);
|
|
251
|
+
if (stored.value.status !== "RUNNING" ||
|
|
252
|
+
stored.value.execution_started_at !== null)
|
|
253
|
+
throw new RepositoryError("ATTEMPT_LIFECYCLE_VIOLATION", "input baseline must be recorded before execution starts");
|
|
254
|
+
return next(stored, {
|
|
255
|
+
...stored.value,
|
|
256
|
+
error_message: write.error_message,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
async finalizeAttempt(attemptId, expectedRevision, finalization) {
|
|
260
|
+
const stored = this.attemptById(attemptId);
|
|
261
|
+
assertRevision(stored, expectedRevision);
|
|
262
|
+
if (stored.value.status !== "RUNNING") {
|
|
263
|
+
throw new RepositoryError("ATTEMPT_TERMINAL", "attempt is terminal");
|
|
264
|
+
}
|
|
265
|
+
return next(stored, { ...stored.value, ...finalization });
|
|
266
|
+
}
|
|
267
|
+
async appendResolution(resolution) {
|
|
268
|
+
const attempt = this.attemptById(resolution.attempt_id);
|
|
269
|
+
if (attempt.value.status !== "UNKNOWN" &&
|
|
270
|
+
attempt.value.status !== "FAILED") {
|
|
271
|
+
throw new RepositoryError("ATTEMPT_LIFECYCLE_VIOLATION", "only UNKNOWN or FAILED attempts can be resolved");
|
|
272
|
+
}
|
|
273
|
+
const stored = { value: structuredClone(resolution), revision: 1 };
|
|
274
|
+
this.resolutions.push(stored);
|
|
275
|
+
return copy(stored);
|
|
276
|
+
}
|
|
277
|
+
async appendOperationAudit(audit) {
|
|
278
|
+
if (this.operationAudits.some(({ value }) => value.event_id === audit.event_id))
|
|
279
|
+
throw new RepositoryError("DUPLICATE_RECORD", "operation audit exists");
|
|
280
|
+
const stored = { value: structuredClone(audit), revision: 1 };
|
|
281
|
+
this.operationAudits.push(stored);
|
|
282
|
+
return copy(stored);
|
|
283
|
+
}
|
|
284
|
+
async getOperationAuditByEventId(eventId) {
|
|
285
|
+
const stored = this.operationAudits.find(({ value }) => value.event_id === eventId);
|
|
286
|
+
return stored === undefined ? null : copy(stored);
|
|
287
|
+
}
|
|
288
|
+
async listInconsistencies(runId) {
|
|
289
|
+
const result = [];
|
|
290
|
+
for (const state of await this.getNodeStates(runId)) {
|
|
291
|
+
const attempts = [...this.attempts.values()]
|
|
292
|
+
.filter(({ value }) => value.run_id === runId && value.node_id === state.value.node_id)
|
|
293
|
+
.map(copy);
|
|
294
|
+
const running = attempts.filter(({ value }) => value.status === "RUNNING");
|
|
295
|
+
if (running.length > 1) {
|
|
296
|
+
result.push({
|
|
297
|
+
code: "MULTIPLE_RUNNING_ATTEMPTS",
|
|
298
|
+
node_state: state,
|
|
299
|
+
attempts: running,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
if (state.value.active_attempt_id) {
|
|
303
|
+
const active = attempts.find(({ value }) => value.node_attempt_id === state.value.active_attempt_id);
|
|
304
|
+
if (!active) {
|
|
305
|
+
result.push({ code: "ACTIVE_ATTEMPT_MISSING", node_state: state });
|
|
306
|
+
}
|
|
307
|
+
else if (active.value.status !== state.value.status) {
|
|
308
|
+
result.push({
|
|
309
|
+
code: "STATE_ATTEMPT_STATUS_MISMATCH",
|
|
310
|
+
node_state: state,
|
|
311
|
+
attempt: active,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
required(map, key, label) {
|
|
319
|
+
const stored = map.get(key);
|
|
320
|
+
if (!stored) {
|
|
321
|
+
throw new RepositoryError("RECORD_NOT_FOUND", `${label} not found`);
|
|
322
|
+
}
|
|
323
|
+
return stored;
|
|
324
|
+
}
|
|
325
|
+
attemptById(attemptId) {
|
|
326
|
+
const key = this.attemptIds.get(attemptId);
|
|
327
|
+
if (!key) {
|
|
328
|
+
throw new RepositoryError("RECORD_NOT_FOUND", "attempt not found");
|
|
329
|
+
}
|
|
330
|
+
return this.required(this.attempts, key, "attempt");
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=in-memory-repository.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface KintoneClientConfig {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
appId: number;
|
|
4
|
+
apiToken: string;
|
|
5
|
+
fetch?: typeof fetch;
|
|
6
|
+
}
|
|
7
|
+
export type KintoneFieldValue = {
|
|
8
|
+
value: unknown;
|
|
9
|
+
};
|
|
10
|
+
export type KintoneRecord = Record<string, KintoneFieldValue>;
|
|
11
|
+
export declare class KintoneApiError extends Error {
|
|
12
|
+
readonly status: number;
|
|
13
|
+
readonly apiCode: string | null;
|
|
14
|
+
readonly responseBody: unknown;
|
|
15
|
+
constructor(status: number, apiCode: string | null, responseBody: unknown);
|
|
16
|
+
}
|
|
17
|
+
export declare class KintoneTransportError extends Error {
|
|
18
|
+
readonly causeDetail: unknown;
|
|
19
|
+
constructor(causeDetail: unknown);
|
|
20
|
+
}
|
|
21
|
+
export declare class KintoneClient {
|
|
22
|
+
private readonly baseUrl;
|
|
23
|
+
private readonly appId;
|
|
24
|
+
private readonly apiToken;
|
|
25
|
+
private readonly fetchImpl;
|
|
26
|
+
constructor(config: KintoneClientConfig);
|
|
27
|
+
getRecords(query: string): Promise<KintoneRecord[]>;
|
|
28
|
+
postRecord(record: KintoneRecord): Promise<{
|
|
29
|
+
id: string;
|
|
30
|
+
revision: number;
|
|
31
|
+
}>;
|
|
32
|
+
putRecord(recordKey: string, revision: number, record: KintoneRecord): Promise<number>;
|
|
33
|
+
putRecordById(id: string, revision: number, record: KintoneRecord): Promise<number>;
|
|
34
|
+
private request;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=client.d.ts.map
|