@01.software/cli 0.15.1 → 0.17.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/dist/index.js +2117 -669
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -13,18 +13,52 @@ import {
|
|
|
13
13
|
|
|
14
14
|
// src/lib/credentials.ts
|
|
15
15
|
import {
|
|
16
|
+
chmodSync,
|
|
17
|
+
closeSync,
|
|
18
|
+
constants as fsConstants,
|
|
16
19
|
existsSync,
|
|
20
|
+
fchmodSync,
|
|
21
|
+
fstatSync,
|
|
22
|
+
fsyncSync,
|
|
23
|
+
lstatSync,
|
|
17
24
|
mkdirSync,
|
|
25
|
+
openSync,
|
|
18
26
|
readFileSync,
|
|
19
|
-
|
|
27
|
+
renameSync,
|
|
20
28
|
unlinkSync,
|
|
29
|
+
writeFileSync,
|
|
21
30
|
appendFileSync
|
|
22
31
|
} from "fs";
|
|
23
|
-
import {
|
|
32
|
+
import { spawnSync } from "child_process";
|
|
33
|
+
import { randomBytes } from "crypto";
|
|
34
|
+
import { dirname, join } from "path";
|
|
24
35
|
import { homedir } from "os";
|
|
25
36
|
var DIR_NAME = ".01software";
|
|
26
37
|
var FILE_NAME = "credentials.json";
|
|
27
38
|
var TENANTS_FILE = "tenants.json";
|
|
39
|
+
var LOCAL_CREDENTIAL_PATH = `${DIR_NAME}/${FILE_NAME}`;
|
|
40
|
+
var LOCAL_GITIGNORE_ENTRY = `${DIR_NAME}/`;
|
|
41
|
+
var PRIVATE_DIRECTORY_MODE = 448;
|
|
42
|
+
var PRIVATE_FILE_MODE = 384;
|
|
43
|
+
var CURRENT_USER_ID = process.platform !== "win32" && typeof process.getuid === "function" ? process.getuid() : null;
|
|
44
|
+
var HAS_POSIX_FILE_PERMISSIONS = CURRENT_USER_ID !== null;
|
|
45
|
+
var SANITIZED_GIT_ENVIRONMENT_VARIABLES = /* @__PURE__ */ new Set([
|
|
46
|
+
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
47
|
+
"GIT_CEILING_DIRECTORIES",
|
|
48
|
+
"GIT_COMMON_DIR",
|
|
49
|
+
"GIT_CONFIG_COUNT",
|
|
50
|
+
"GIT_CONFIG_PARAMETERS",
|
|
51
|
+
"GIT_DIR",
|
|
52
|
+
"GIT_DISCOVERY_ACROSS_FILESYSTEM",
|
|
53
|
+
"GIT_INDEX_FILE",
|
|
54
|
+
"GIT_ICASE_PATHSPECS",
|
|
55
|
+
"GIT_GLOB_PATHSPECS",
|
|
56
|
+
"GIT_LITERAL_PATHSPECS",
|
|
57
|
+
"GIT_NOGLOB_PATHSPECS",
|
|
58
|
+
"GIT_OBJECT_DIRECTORY",
|
|
59
|
+
"GIT_PREFIX",
|
|
60
|
+
"GIT_WORK_TREE"
|
|
61
|
+
]);
|
|
28
62
|
function getCredentialsPath() {
|
|
29
63
|
return join(homedir(), DIR_NAME, FILE_NAME);
|
|
30
64
|
}
|
|
@@ -32,19 +66,12 @@ function loadCredentials() {
|
|
|
32
66
|
return loadCredentialsFrom(getCredentialsPath());
|
|
33
67
|
}
|
|
34
68
|
function saveCredentials(creds) {
|
|
35
|
-
const dir = join(homedir(), DIR_NAME);
|
|
36
|
-
if (!existsSync(dir)) {
|
|
37
|
-
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
38
|
-
}
|
|
39
69
|
const filePath = getCredentialsPath();
|
|
40
70
|
const data = {
|
|
41
71
|
...creds,
|
|
42
72
|
storedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
43
73
|
};
|
|
44
|
-
|
|
45
|
-
encoding: "utf-8",
|
|
46
|
-
mode: 384
|
|
47
|
-
});
|
|
74
|
+
writeCredentialFile(filePath, JSON.stringify(data, null, 2));
|
|
48
75
|
}
|
|
49
76
|
function deleteCredentials() {
|
|
50
77
|
const filePath = getCredentialsPath();
|
|
@@ -58,21 +85,19 @@ function getLocalCredentialsPath() {
|
|
|
58
85
|
function loadLocalCredentials() {
|
|
59
86
|
return loadCredentialsFrom(getLocalCredentialsPath());
|
|
60
87
|
}
|
|
61
|
-
function saveLocalCredentials(creds) {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
const filePath = getLocalCredentialsPath();
|
|
88
|
+
function saveLocalCredentials(creds, workingDirectory = process.cwd()) {
|
|
89
|
+
const temporaryFileName = createTemporaryCredentialFileName();
|
|
90
|
+
ensureGitignore(workingDirectory, `${DIR_NAME}/${temporaryFileName}`);
|
|
91
|
+
const filePath = join(workingDirectory, DIR_NAME, FILE_NAME);
|
|
67
92
|
const data = {
|
|
68
93
|
...creds,
|
|
69
94
|
storedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
70
95
|
};
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
96
|
+
writeCredentialFile(
|
|
97
|
+
filePath,
|
|
98
|
+
JSON.stringify(data, null, 2),
|
|
99
|
+
temporaryFileName
|
|
100
|
+
);
|
|
76
101
|
}
|
|
77
102
|
function saveTenantList(tenants) {
|
|
78
103
|
const dir = join(homedir(), DIR_NAME);
|
|
@@ -100,6 +125,161 @@ function loadTenantList() {
|
|
|
100
125
|
return null;
|
|
101
126
|
}
|
|
102
127
|
}
|
|
128
|
+
function writeCredentialFile(filePath, content, temporaryFileName = createTemporaryCredentialFileName()) {
|
|
129
|
+
const directoryPath = dirname(filePath);
|
|
130
|
+
const directoryDescriptor = openPrivateCredentialDirectory(directoryPath);
|
|
131
|
+
const initialTarget = inspectCredentialTarget(filePath);
|
|
132
|
+
const tempPath = join(directoryPath, temporaryFileName);
|
|
133
|
+
let tempDescriptor;
|
|
134
|
+
try {
|
|
135
|
+
tempDescriptor = openSync(tempPath, "wx", PRIVATE_FILE_MODE);
|
|
136
|
+
const tempStats = fstatSync(tempDescriptor);
|
|
137
|
+
assertRegularOwnedCredentialFile(tempStats, "temporary credential file");
|
|
138
|
+
if (HAS_POSIX_FILE_PERMISSIONS) {
|
|
139
|
+
fchmodSync(tempDescriptor, PRIVATE_FILE_MODE);
|
|
140
|
+
assertMode(
|
|
141
|
+
fstatSync(tempDescriptor),
|
|
142
|
+
PRIVATE_FILE_MODE,
|
|
143
|
+
"temporary credential file"
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
writeFileSync(tempDescriptor, content, { encoding: "utf-8" });
|
|
147
|
+
fsyncSync(tempDescriptor);
|
|
148
|
+
closeSync(tempDescriptor);
|
|
149
|
+
tempDescriptor = void 0;
|
|
150
|
+
const currentTarget = inspectCredentialTarget(filePath);
|
|
151
|
+
if (!sameFileIdentity(initialTarget, currentTarget)) {
|
|
152
|
+
throw credentialFileProtectionError(
|
|
153
|
+
"credential target changed while being checked"
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
renameSync(tempPath, filePath);
|
|
157
|
+
const finalStats = lstatCredentialPath(filePath);
|
|
158
|
+
if (!finalStats) {
|
|
159
|
+
throw credentialFileProtectionError(
|
|
160
|
+
"credential target disappeared after atomic replacement"
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
assertRegularOwnedCredentialFile(finalStats, "credential target");
|
|
164
|
+
if (HAS_POSIX_FILE_PERMISSIONS) {
|
|
165
|
+
assertMode(finalStats, PRIVATE_FILE_MODE, "credential target");
|
|
166
|
+
if (directoryDescriptor !== void 0) {
|
|
167
|
+
fsyncSync(directoryDescriptor);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
} catch (error) {
|
|
171
|
+
if (tempDescriptor !== void 0) {
|
|
172
|
+
try {
|
|
173
|
+
closeSync(tempDescriptor);
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
unlinkSync(tempPath);
|
|
179
|
+
} catch {
|
|
180
|
+
}
|
|
181
|
+
throw error;
|
|
182
|
+
} finally {
|
|
183
|
+
if (directoryDescriptor !== void 0) {
|
|
184
|
+
closeSync(directoryDescriptor);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function openPrivateCredentialDirectory(directoryPath) {
|
|
189
|
+
let directoryStats = lstatCredentialPath(directoryPath);
|
|
190
|
+
if (!directoryStats) {
|
|
191
|
+
try {
|
|
192
|
+
mkdirSync(directoryPath, { mode: PRIVATE_DIRECTORY_MODE });
|
|
193
|
+
if (HAS_POSIX_FILE_PERMISSIONS) {
|
|
194
|
+
chmodSync(directoryPath, PRIVATE_DIRECTORY_MODE);
|
|
195
|
+
}
|
|
196
|
+
} catch (error) {
|
|
197
|
+
if (error.code !== "EEXIST") throw error;
|
|
198
|
+
}
|
|
199
|
+
directoryStats = lstatCredentialPath(directoryPath);
|
|
200
|
+
}
|
|
201
|
+
if (!directoryStats || directoryStats.isSymbolicLink() || !directoryStats.isDirectory()) {
|
|
202
|
+
throw credentialFileProtectionError(
|
|
203
|
+
"credential directory must be a regular directory, not a symlink"
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
assertCurrentUserOwns(directoryStats, "credential directory");
|
|
207
|
+
if (!HAS_POSIX_FILE_PERMISSIONS) return void 0;
|
|
208
|
+
const descriptor = openSync(
|
|
209
|
+
directoryPath,
|
|
210
|
+
fsConstants.O_RDONLY | fsConstants.O_DIRECTORY | fsConstants.O_NOFOLLOW
|
|
211
|
+
);
|
|
212
|
+
try {
|
|
213
|
+
const openedStats = fstatSync(descriptor);
|
|
214
|
+
if (!openedStats.isDirectory() || openedStats.dev !== directoryStats.dev || openedStats.ino !== directoryStats.ino) {
|
|
215
|
+
throw credentialFileProtectionError(
|
|
216
|
+
"credential directory changed while being checked"
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
assertCurrentUserOwns(openedStats, "credential directory");
|
|
220
|
+
fchmodSync(descriptor, PRIVATE_DIRECTORY_MODE);
|
|
221
|
+
assertMode(
|
|
222
|
+
fstatSync(descriptor),
|
|
223
|
+
PRIVATE_DIRECTORY_MODE,
|
|
224
|
+
"credential directory"
|
|
225
|
+
);
|
|
226
|
+
return descriptor;
|
|
227
|
+
} catch (error) {
|
|
228
|
+
closeSync(descriptor);
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function inspectCredentialTarget(filePath) {
|
|
233
|
+
const stats = lstatCredentialPath(filePath);
|
|
234
|
+
if (!stats) return null;
|
|
235
|
+
assertRegularOwnedCredentialFile(stats, "credential target");
|
|
236
|
+
return { dev: stats.dev, ino: stats.ino };
|
|
237
|
+
}
|
|
238
|
+
function assertRegularOwnedCredentialFile(stats, description) {
|
|
239
|
+
if (stats.isSymbolicLink()) {
|
|
240
|
+
throw credentialFileProtectionError(`${description} must not be a symlink`);
|
|
241
|
+
}
|
|
242
|
+
if (!stats.isFile()) {
|
|
243
|
+
throw credentialFileProtectionError(`${description} must be a regular file`);
|
|
244
|
+
}
|
|
245
|
+
if (HAS_POSIX_FILE_PERMISSIONS && stats.nlink > 1) {
|
|
246
|
+
throw credentialFileProtectionError(
|
|
247
|
+
`${description} must not have multiple hard links`
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
assertCurrentUserOwns(stats, description);
|
|
251
|
+
}
|
|
252
|
+
function assertCurrentUserOwns(stats, description) {
|
|
253
|
+
if (CURRENT_USER_ID !== null && stats.uid !== CURRENT_USER_ID) {
|
|
254
|
+
throw credentialFileProtectionError(
|
|
255
|
+
`${description} must be owned by the current user`
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function assertMode(stats, expectedMode, description) {
|
|
260
|
+
if ((stats.mode & 511) !== expectedMode) {
|
|
261
|
+
throw credentialFileProtectionError(
|
|
262
|
+
`${description} permissions could not be secured`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function sameFileIdentity(initial, current) {
|
|
267
|
+
if (!initial || !current) return initial === current;
|
|
268
|
+
return initial.dev === current.dev && initial.ino === current.ino;
|
|
269
|
+
}
|
|
270
|
+
function lstatCredentialPath(filePath) {
|
|
271
|
+
try {
|
|
272
|
+
return lstatSync(filePath);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
if (error.code === "ENOENT") return null;
|
|
275
|
+
throw credentialFileProtectionError(
|
|
276
|
+
"credential filesystem target could not be inspected"
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
function credentialFileProtectionError(message) {
|
|
281
|
+
return new Error(`Cannot save credentials: ${message}`);
|
|
282
|
+
}
|
|
103
283
|
function loadCredentialsFrom(filePath) {
|
|
104
284
|
if (!existsSync(filePath)) return null;
|
|
105
285
|
try {
|
|
@@ -111,25 +291,160 @@ function loadCredentialsFrom(filePath) {
|
|
|
111
291
|
return null;
|
|
112
292
|
}
|
|
113
293
|
}
|
|
114
|
-
function ensureGitignore() {
|
|
115
|
-
const gitignorePath = join(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
294
|
+
function ensureGitignore(cwd, temporaryCredentialPath) {
|
|
295
|
+
const gitignorePath = join(cwd, ".gitignore");
|
|
296
|
+
assertSafeGitignorePath(gitignorePath);
|
|
297
|
+
const gitState = detectGitWorkTree(cwd);
|
|
298
|
+
if (gitState === "inside") {
|
|
299
|
+
assertCredentialPathIsUntracked(cwd);
|
|
300
|
+
if (areCredentialPathsIgnored(cwd, temporaryCredentialPath)) return;
|
|
301
|
+
ensureTerminalGitignoreEntry(gitignorePath, true);
|
|
302
|
+
if (!areCredentialPathsIgnored(cwd, temporaryCredentialPath)) {
|
|
303
|
+
throw credentialProtectionError(
|
|
304
|
+
"Git still reports a credential path as unignored"
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
ensureTerminalGitignoreEntry(gitignorePath, false);
|
|
310
|
+
}
|
|
311
|
+
function assertSafeGitignorePath(gitignorePath) {
|
|
312
|
+
const stats = lstatIfPresent(gitignorePath);
|
|
313
|
+
if (stats && (!stats.isFile() || stats.isSymbolicLink())) {
|
|
314
|
+
throw credentialProtectionError(".gitignore must be a regular file");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function ensureTerminalGitignoreEntry(gitignorePath, forceAppend) {
|
|
318
|
+
const initialStats = lstatIfPresent(gitignorePath);
|
|
319
|
+
if (!initialStats) {
|
|
320
|
+
try {
|
|
321
|
+
writeFileSync(gitignorePath, `${LOCAL_GITIGNORE_ENTRY}
|
|
322
|
+
`, {
|
|
323
|
+
encoding: "utf-8",
|
|
324
|
+
flag: "wx"
|
|
325
|
+
});
|
|
326
|
+
return;
|
|
327
|
+
} catch (error) {
|
|
328
|
+
if (error.code !== "EEXIST") throw error;
|
|
329
|
+
return ensureTerminalGitignoreEntry(gitignorePath, forceAppend);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (!initialStats.isFile() || initialStats.isSymbolicLink()) {
|
|
333
|
+
throw credentialProtectionError(".gitignore must be a regular file");
|
|
334
|
+
}
|
|
335
|
+
const descriptor = openSync(gitignorePath, "a+");
|
|
336
|
+
try {
|
|
337
|
+
const openedStats = fstatSync(descriptor);
|
|
338
|
+
if (!openedStats.isFile() || openedStats.dev !== initialStats.dev || openedStats.ino !== initialStats.ino) {
|
|
339
|
+
throw credentialProtectionError(".gitignore changed while being checked");
|
|
340
|
+
}
|
|
341
|
+
const content = readFileSync(descriptor, "utf-8");
|
|
342
|
+
const lastNonEmptyLine = content.split(/\r?\n/).filter((line) => line.length > 0).at(-1);
|
|
343
|
+
if (!forceAppend && (lastNonEmptyLine === LOCAL_GITIGNORE_ENTRY || lastNonEmptyLine === `/${LOCAL_GITIGNORE_ENTRY}`)) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const separator = content.length > 0 && !content.endsWith("\n") ? "\n" : "";
|
|
347
|
+
appendFileSync(
|
|
348
|
+
descriptor,
|
|
349
|
+
`${separator}${LOCAL_GITIGNORE_ENTRY}
|
|
350
|
+
`,
|
|
351
|
+
"utf-8"
|
|
352
|
+
);
|
|
353
|
+
} finally {
|
|
354
|
+
closeSync(descriptor);
|
|
126
355
|
}
|
|
127
356
|
}
|
|
357
|
+
function detectGitWorkTree(cwd) {
|
|
358
|
+
const result = runGit(cwd, ["rev-parse", "--is-inside-work-tree"]);
|
|
359
|
+
if (result.error) {
|
|
360
|
+
if (result.error.code === "ENOENT" && !hasGitMarker(cwd)) {
|
|
361
|
+
return "outside";
|
|
362
|
+
}
|
|
363
|
+
throw credentialProtectionError("Git repository detection failed");
|
|
364
|
+
}
|
|
365
|
+
if (result.status === 0) {
|
|
366
|
+
if (result.stdout.trim() === "true") return "inside";
|
|
367
|
+
throw credentialProtectionError(
|
|
368
|
+
"the current directory is not a Git work tree"
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
if (result.status === 128 && !hasGitMarker(cwd)) return "outside";
|
|
372
|
+
throw credentialProtectionError("Git repository detection failed");
|
|
373
|
+
}
|
|
374
|
+
function assertCredentialPathIsUntracked(cwd) {
|
|
375
|
+
const result = runGit(cwd, [
|
|
376
|
+
"ls-files",
|
|
377
|
+
"-z",
|
|
378
|
+
"--",
|
|
379
|
+
`:(icase,literal)${LOCAL_CREDENTIAL_PATH}`
|
|
380
|
+
]);
|
|
381
|
+
if (result.error || result.status !== 0) {
|
|
382
|
+
throw credentialProtectionError("Git tracked-file verification failed");
|
|
383
|
+
}
|
|
384
|
+
if (result.stdout.length > 0) {
|
|
385
|
+
throw credentialProtectionError(
|
|
386
|
+
".01software/credentials.json is already tracked by Git"
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
function createTemporaryCredentialFileName() {
|
|
391
|
+
return `.${FILE_NAME}.${randomBytes(12).toString("hex")}.tmp`;
|
|
392
|
+
}
|
|
393
|
+
function areCredentialPathsIgnored(cwd, temporaryCredentialPath) {
|
|
394
|
+
return isPathIgnored(cwd, LOCAL_CREDENTIAL_PATH) && isPathIgnored(cwd, temporaryCredentialPath);
|
|
395
|
+
}
|
|
396
|
+
function isPathIgnored(cwd, relativePath) {
|
|
397
|
+
const result = runGit(cwd, [
|
|
398
|
+
"check-ignore",
|
|
399
|
+
"--quiet",
|
|
400
|
+
"--no-index",
|
|
401
|
+
"--",
|
|
402
|
+
relativePath
|
|
403
|
+
]);
|
|
404
|
+
if (result.error || result.status !== 0 && result.status !== 1) {
|
|
405
|
+
throw credentialProtectionError("Git ignore verification failed");
|
|
406
|
+
}
|
|
407
|
+
return result.status === 0;
|
|
408
|
+
}
|
|
409
|
+
function runGit(cwd, args) {
|
|
410
|
+
const env = { ...process.env, LC_ALL: "C" };
|
|
411
|
+
for (const key of Object.keys(env)) {
|
|
412
|
+
const normalizedKey = key.toUpperCase();
|
|
413
|
+
if (SANITIZED_GIT_ENVIRONMENT_VARIABLES.has(normalizedKey) || normalizedKey.startsWith("GIT_CONFIG_KEY_") || normalizedKey.startsWith("GIT_CONFIG_VALUE_")) {
|
|
414
|
+
delete env[key];
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return spawnSync("git", args, {
|
|
418
|
+
cwd,
|
|
419
|
+
encoding: "utf-8",
|
|
420
|
+
env
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
function hasGitMarker(startPath) {
|
|
424
|
+
let currentPath = startPath;
|
|
425
|
+
while (true) {
|
|
426
|
+
if (lstatIfPresent(join(currentPath, ".git"))) return true;
|
|
427
|
+
const parentPath = dirname(currentPath);
|
|
428
|
+
if (parentPath === currentPath) return false;
|
|
429
|
+
currentPath = parentPath;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function lstatIfPresent(filePath) {
|
|
433
|
+
try {
|
|
434
|
+
return lstatSync(filePath);
|
|
435
|
+
} catch (error) {
|
|
436
|
+
if (error.code === "ENOENT") return null;
|
|
437
|
+
throw credentialProtectionError("local Git metadata could not be inspected");
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function credentialProtectionError(message) {
|
|
441
|
+
return new Error(`Cannot save local credentials: ${message}`);
|
|
442
|
+
}
|
|
128
443
|
|
|
129
444
|
// src/lib/output.ts
|
|
130
445
|
import pc from "picocolors";
|
|
131
446
|
|
|
132
|
-
//
|
|
447
|
+
// ../../internal/errors/src/admin-error.ts
|
|
133
448
|
var ADMIN_ERROR_CODES = {
|
|
134
449
|
permission: [
|
|
135
450
|
"tenant_mismatch",
|
|
@@ -268,7 +583,7 @@ var CLI_I18N_KO = {
|
|
|
268
583
|
RetiredHexCredentialsRejected: "\uC774\uC804 hex \uC790\uACA9 \uC99D\uBA85\uC740 \uB354 \uC774\uC0C1 \uD5C8\uC6A9\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2014 `01 login`\uC73C\uB85C \uB2E4\uC2DC \uC778\uC99D\uD558\uC138\uC694.",
|
|
269
584
|
InvalidJsonObject: "`--{{label}}` \uC778\uC790\uB294 JSON \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
|
|
270
585
|
InvalidJsonArray: "`--{{label}}` \uC778\uC790\uB294 JSON \uBC30\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4.",
|
|
271
|
-
InvalidJsonValue: "`--{{label}}` \uC778\uC790\uC758 JSON \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4
|
|
586
|
+
InvalidJsonValue: "`--{{label}}` \uC778\uC790\uC758 JSON \uD615\uC2DD\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
272
587
|
Empty: "(\uC5C6\uC74C)",
|
|
273
588
|
Total: "\uCD1D {{n}}\uAC1C",
|
|
274
589
|
PageOf: "{{page}} / {{total}} \uD398\uC774\uC9C0",
|
|
@@ -300,7 +615,7 @@ var CLI_I18N_EN = {
|
|
|
300
615
|
RetiredHexCredentialsRejected: "Retired hex credentials are no longer accepted \u2014 run `01 login` to re-authenticate.",
|
|
301
616
|
InvalidJsonObject: "--{{label}} must be a JSON object.",
|
|
302
617
|
InvalidJsonArray: "--{{label}} must be a JSON array.",
|
|
303
|
-
InvalidJsonValue: "Invalid JSON for --{{label}}
|
|
618
|
+
InvalidJsonValue: "Invalid JSON for --{{label}}.",
|
|
304
619
|
Empty: "(empty)",
|
|
305
620
|
Total: "{{n}} total",
|
|
306
621
|
PageOf: "page {{page}}/{{total}}",
|
|
@@ -552,40 +867,24 @@ function parseSelect(input) {
|
|
|
552
867
|
}
|
|
553
868
|
|
|
554
869
|
// src/lib/parse.ts
|
|
555
|
-
function failArg(label,
|
|
556
|
-
const message = expectedKind === "object" ? t("InvalidJsonObject", { label }) : expectedKind === "array" ? t("InvalidJsonArray", { label }) : t("InvalidJsonValue", { label
|
|
870
|
+
function failArg(label, _value, expectedKind) {
|
|
871
|
+
const message = expectedKind === "object" ? t("InvalidJsonObject", { label }) : expectedKind === "array" ? t("InvalidJsonArray", { label }) : t("InvalidJsonValue", { label });
|
|
557
872
|
exitWithError({
|
|
558
873
|
type: "validation",
|
|
559
874
|
code: "invalid_argument",
|
|
560
875
|
field: label,
|
|
561
|
-
//
|
|
562
|
-
//
|
|
563
|
-
//
|
|
876
|
+
// Keep rejected values out of terminal and structured output. `message`
|
|
877
|
+
// is the stderr headline; `detail` carries only the stable field label for
|
|
878
|
+
// machine consumers.
|
|
564
879
|
message,
|
|
565
|
-
detail: { message,
|
|
880
|
+
detail: { message, field: label }
|
|
566
881
|
});
|
|
567
882
|
}
|
|
568
|
-
function stringifyValue(value) {
|
|
569
|
-
try {
|
|
570
|
-
return JSON.stringify(value);
|
|
571
|
-
} catch {
|
|
572
|
-
return String(value);
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
function formatSchemaIssues(label, issues) {
|
|
576
|
-
return issues.map((issue) => {
|
|
577
|
-
const path = issue.path.length > 0 ? issue.path.join(".") : label;
|
|
578
|
-
return `${path}: ${issue.message}`;
|
|
579
|
-
}).join("; ");
|
|
580
|
-
}
|
|
581
883
|
function parseWithSchema(value, label, schema) {
|
|
582
884
|
const parsed = schema.safeParse(value);
|
|
583
885
|
if (parsed.success) return parsed.data;
|
|
584
|
-
const issues = parsed.error.issues.map((issue) => ({
|
|
585
|
-
|
|
586
|
-
message: issue.message
|
|
587
|
-
}));
|
|
588
|
-
const message = `Invalid value for --${label}: ${formatSchemaIssues(label, issues)}`;
|
|
886
|
+
const issues = parsed.error.issues.map((issue) => ({ code: issue.code }));
|
|
887
|
+
const message = `Invalid value for --${label}.`;
|
|
589
888
|
exitWithError({
|
|
590
889
|
type: "validation",
|
|
591
890
|
code: "invalid_argument",
|
|
@@ -593,7 +892,6 @@ function parseWithSchema(value, label, schema) {
|
|
|
593
892
|
message,
|
|
594
893
|
detail: {
|
|
595
894
|
message,
|
|
596
|
-
value: stringifyValue(value),
|
|
597
895
|
field: label,
|
|
598
896
|
issues
|
|
599
897
|
}
|
|
@@ -804,7 +1102,7 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
804
1102
|
});
|
|
805
1103
|
}
|
|
806
1104
|
|
|
807
|
-
//
|
|
1105
|
+
// ../../internal/contracts/src/tenant/index.ts
|
|
808
1106
|
import { z } from "zod";
|
|
809
1107
|
var tenantFieldConfigStateSchema = z.object({
|
|
810
1108
|
hiddenFields: z.array(z.string()),
|
|
@@ -953,10 +1251,10 @@ var collectionSchemaResponseSchema = z.object({
|
|
|
953
1251
|
}).strict()
|
|
954
1252
|
}).strict();
|
|
955
1253
|
|
|
956
|
-
//
|
|
957
|
-
import { z as
|
|
1254
|
+
// ../../internal/contracts/src/ecommerce/index.ts
|
|
1255
|
+
import { z as z7 } from "zod";
|
|
958
1256
|
|
|
959
|
-
//
|
|
1257
|
+
// ../../internal/contracts/src/ecommerce/product-upsert.ts
|
|
960
1258
|
import { z as z2 } from "zod";
|
|
961
1259
|
var IdSchema = z2.union([z2.string(), z2.number()]).transform(String);
|
|
962
1260
|
var RemovedLegacyMediaFieldSchema = z2.unknown().optional();
|
|
@@ -980,6 +1278,7 @@ var productFieldShape = {
|
|
|
980
1278
|
publishedAt: z2.string().optional().nullable(),
|
|
981
1279
|
categories: z2.array(IdSchema).optional(),
|
|
982
1280
|
tags: z2.array(IdSchema).optional(),
|
|
1281
|
+
markets: z2.array(IdSchema).optional().nullable(),
|
|
983
1282
|
seo: z2.object({
|
|
984
1283
|
title: z2.string().optional().nullable(),
|
|
985
1284
|
description: z2.string().optional().nullable()
|
|
@@ -1035,6 +1334,26 @@ var VariantOptionValueObjectSchema = z2.object({
|
|
|
1035
1334
|
}).refine((data) => Boolean(data.valueSlug ?? data.valueId ?? data.value), {
|
|
1036
1335
|
message: "Variant option value object requires valueSlug, valueId, or value"
|
|
1037
1336
|
});
|
|
1337
|
+
var MAX_CATALOG_AMOUNT_DECIMAL_PLACES = 2;
|
|
1338
|
+
function catalogAmountDecimalPlaces(value) {
|
|
1339
|
+
if (!Number.isFinite(value)) return 0;
|
|
1340
|
+
const text = String(value);
|
|
1341
|
+
const exponential = text.indexOf("e-");
|
|
1342
|
+
if (exponential !== -1) return Number(text.slice(exponential + 2)) || 0;
|
|
1343
|
+
const dot = text.indexOf(".");
|
|
1344
|
+
return dot === -1 ? 0 : text.length - dot - 1;
|
|
1345
|
+
}
|
|
1346
|
+
var CatalogAmountSchema = z2.number().min(0).refine(
|
|
1347
|
+
(value) => catalogAmountDecimalPlaces(value) <= MAX_CATALOG_AMOUNT_DECIMAL_PLACES,
|
|
1348
|
+
{
|
|
1349
|
+
message: `Amount must have at most ${MAX_CATALOG_AMOUNT_DECIMAL_PLACES} decimal places; the store currency may allow fewer.`
|
|
1350
|
+
}
|
|
1351
|
+
);
|
|
1352
|
+
var VariantMarketPriceInputSchema = z2.object({
|
|
1353
|
+
market: IdSchema,
|
|
1354
|
+
price: CatalogAmountSchema,
|
|
1355
|
+
compareAtPrice: CatalogAmountSchema.optional().nullable()
|
|
1356
|
+
});
|
|
1038
1357
|
var VariantInputSchema = z2.object({
|
|
1039
1358
|
id: IdSchema.optional(),
|
|
1040
1359
|
optionValues: z2.union([
|
|
@@ -1046,8 +1365,8 @@ var VariantInputSchema = z2.object({
|
|
|
1046
1365
|
]).optional(),
|
|
1047
1366
|
sku: z2.string().optional().nullable(),
|
|
1048
1367
|
title: z2.string().optional().nullable(),
|
|
1049
|
-
price:
|
|
1050
|
-
compareAtPrice:
|
|
1368
|
+
price: CatalogAmountSchema,
|
|
1369
|
+
compareAtPrice: CatalogAmountSchema.optional().nullable(),
|
|
1051
1370
|
stock: z2.number().int().min(0).optional(),
|
|
1052
1371
|
isUnlimited: z2.boolean().optional(),
|
|
1053
1372
|
inventoryPolicy: z2.enum(["deny", "continue"]).optional(),
|
|
@@ -1057,6 +1376,7 @@ var VariantInputSchema = z2.object({
|
|
|
1057
1376
|
externalId: z2.string().optional().nullable(),
|
|
1058
1377
|
isActive: z2.boolean().optional(),
|
|
1059
1378
|
images: z2.array(IdSchema).optional(),
|
|
1379
|
+
marketPrices: z2.array(VariantMarketPriceInputSchema).optional(),
|
|
1060
1380
|
thumbnail: RemovedLegacyMediaFieldSchema,
|
|
1061
1381
|
featuredMediaItemId: RemovedLegacyMediaFieldSchema,
|
|
1062
1382
|
metadata: z2.unknown().optional()
|
|
@@ -1109,202 +1429,1004 @@ var ProductUpsertSchema = ProductUpsertObjectSchema.superRefine(
|
|
|
1109
1429
|
}
|
|
1110
1430
|
);
|
|
1111
1431
|
|
|
1112
|
-
//
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
var
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1432
|
+
// ../../internal/contracts/src/ecommerce/cart.ts
|
|
1433
|
+
import { z as z4 } from "zod";
|
|
1434
|
+
|
|
1435
|
+
// ../../internal/contracts/src/ecommerce/commerce-common.ts
|
|
1436
|
+
import { z as z3 } from "zod";
|
|
1437
|
+
var currencyCodeSchema = z3.string().regex(
|
|
1438
|
+
/^[A-Z]{3}$/,
|
|
1439
|
+
"currency must be a three-letter uppercase ISO 4217 code"
|
|
1440
|
+
);
|
|
1441
|
+
var minorAmountSchema = z3.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
1442
|
+
var moneySchema = z3.object({
|
|
1443
|
+
amountMinor: minorAmountSchema,
|
|
1444
|
+
currency: currencyCodeSchema
|
|
1445
|
+
}).strict();
|
|
1446
|
+
var MAX_COMMERCE_EXTENSION_ENTRIES = 50;
|
|
1447
|
+
var MAX_COMMERCE_EXTENSION_KEY_LENGTH = 40;
|
|
1448
|
+
var MAX_COMMERCE_EXTENSION_VALUE_LENGTH = 500;
|
|
1449
|
+
var MAX_COMMERCE_RESOURCE_ID_LENGTH = 255;
|
|
1450
|
+
var MAX_COMMERCE_CAPABILITY_LENGTH = 512;
|
|
1451
|
+
var MAX_COMMERCE_CUSTOMER_TOKEN_LENGTH = 4096;
|
|
1452
|
+
var MAX_COMMERCE_SHORT_TEXT_LENGTH = 200;
|
|
1453
|
+
var MAX_COMMERCE_ADDRESS_LENGTH = 500;
|
|
1454
|
+
var MAX_COMMERCE_EMAIL_LENGTH = 254;
|
|
1455
|
+
var MAX_COMMERCE_PHONE_LENGTH = 32;
|
|
1456
|
+
var MAX_COMMERCE_POSTAL_CODE_LENGTH = 32;
|
|
1457
|
+
var commerceResourceIdSchema = z3.string().min(1).max(MAX_COMMERCE_RESOURCE_ID_LENGTH);
|
|
1458
|
+
var commerceCapabilitySchema = z3.string().min(1).max(MAX_COMMERCE_CAPABILITY_LENGTH);
|
|
1459
|
+
var commerceCustomerTokenSchema = z3.string().min(1).max(MAX_COMMERCE_CUSTOMER_TOKEN_LENGTH);
|
|
1460
|
+
var publicAttributeKeySchema = z3.string().min(1).max(MAX_COMMERCE_EXTENSION_KEY_LENGTH).refine((key) => !key.startsWith("__"), {
|
|
1461
|
+
message: "attribute key uses a reserved platform prefix"
|
|
1462
|
+
});
|
|
1463
|
+
var publicAttributeSchema = z3.object({
|
|
1464
|
+
key: publicAttributeKeySchema,
|
|
1465
|
+
value: z3.string().max(MAX_COMMERCE_EXTENSION_VALUE_LENGTH)
|
|
1466
|
+
}).strict();
|
|
1467
|
+
var publicAttributesSchema = z3.array(publicAttributeSchema).max(MAX_COMMERCE_EXTENSION_ENTRIES).superRefine((attributes, ctx) => {
|
|
1468
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1469
|
+
attributes.forEach(({ key }, index) => {
|
|
1470
|
+
if (seen.has(key)) {
|
|
1471
|
+
ctx.addIssue({
|
|
1472
|
+
code: "custom",
|
|
1473
|
+
path: [index, "key"],
|
|
1474
|
+
message: "attribute keys must be unique"
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
seen.add(key);
|
|
1478
|
+
});
|
|
1479
|
+
});
|
|
1480
|
+
var integrationMetadataKeySchema = z3.string().min(1).max(MAX_COMMERCE_EXTENSION_KEY_LENGTH).refine((key) => !key.includes("[") && !key.includes("]"), {
|
|
1481
|
+
message: "integration metadata keys must not use bracket notation"
|
|
1482
|
+
});
|
|
1483
|
+
var integrationMetadataSchema = z3.record(
|
|
1484
|
+
integrationMetadataKeySchema,
|
|
1485
|
+
z3.string().max(MAX_COMMERCE_EXTENSION_VALUE_LENGTH)
|
|
1486
|
+
).superRefine((metadata, ctx) => {
|
|
1487
|
+
if (Object.keys(metadata).length > MAX_COMMERCE_EXTENSION_ENTRIES) {
|
|
1488
|
+
ctx.addIssue({
|
|
1489
|
+
code: "too_big",
|
|
1490
|
+
origin: "object",
|
|
1491
|
+
maximum: MAX_COMMERCE_EXTENSION_ENTRIES,
|
|
1492
|
+
inclusive: true,
|
|
1493
|
+
message: `integration metadata cannot contain more than ${MAX_COMMERCE_EXTENSION_ENTRIES} entries`
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
});
|
|
1497
|
+
var customerSnapshotSchema = z3.object({
|
|
1498
|
+
email: z3.string().email().max(MAX_COMMERCE_EMAIL_LENGTH),
|
|
1499
|
+
name: z3.string().min(1).max(MAX_COMMERCE_SHORT_TEXT_LENGTH).optional(),
|
|
1500
|
+
phone: z3.string().min(1).max(MAX_COMMERCE_PHONE_LENGTH).optional()
|
|
1501
|
+
}).strict();
|
|
1502
|
+
var checkoutShippingAddressSchema = z3.object({
|
|
1503
|
+
recipientName: z3.string().min(1).max(MAX_COMMERCE_SHORT_TEXT_LENGTH),
|
|
1504
|
+
phone: z3.string().min(1).max(MAX_COMMERCE_PHONE_LENGTH),
|
|
1505
|
+
countryCode: z3.string().trim().length(2).optional(),
|
|
1506
|
+
regionCode: z3.string().trim().min(1).max(64).optional(),
|
|
1507
|
+
postalCode: z3.string().min(1).max(MAX_COMMERCE_POSTAL_CODE_LENGTH),
|
|
1508
|
+
address: z3.string().min(1).max(MAX_COMMERCE_ADDRESS_LENGTH),
|
|
1509
|
+
detailAddress: z3.string().min(1).max(MAX_COMMERCE_ADDRESS_LENGTH),
|
|
1510
|
+
deliveryMessage: z3.string().max(MAX_COMMERCE_EXTENSION_VALUE_LENGTH).optional()
|
|
1511
|
+
}).strict();
|
|
1512
|
+
var commerceIdempotencyKeySchema = z3.string().max(255).refine(
|
|
1513
|
+
(value) => /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
|
|
1514
|
+
value
|
|
1515
|
+
) || /^ik_[A-Za-z0-9_-]{22}$/.test(value),
|
|
1516
|
+
"idempotencyKey must be a UUIDv4 or ik_-prefixed 128-bit base64url value"
|
|
1517
|
+
);
|
|
1518
|
+
|
|
1519
|
+
// ../../internal/contracts/src/ecommerce/cart.ts
|
|
1520
|
+
var MAX_CART_LINE_QUANTITY = 99;
|
|
1521
|
+
var MAX_CART_DISCOUNT_CODES = 250;
|
|
1522
|
+
var MAX_CART_DISCOUNT_CODE_LENGTH = 128;
|
|
1523
|
+
var cartDiscountCodeSchema = z4.object({
|
|
1524
|
+
code: z4.string().min(1).max(MAX_CART_DISCOUNT_CODE_LENGTH),
|
|
1525
|
+
applicable: z4.boolean()
|
|
1526
|
+
}).strict();
|
|
1527
|
+
var CART_WARNING_CODES = [
|
|
1528
|
+
"DISCOUNT_CODE_NOT_HONOURED",
|
|
1529
|
+
"DISCOUNT_CURRENTLY_INACTIVE",
|
|
1530
|
+
"DISCOUNT_CUSTOMER_NOT_ELIGIBLE",
|
|
1531
|
+
"DISCOUNT_CUSTOMER_USAGE_LIMIT_REACHED",
|
|
1532
|
+
"DISCOUNT_ELIGIBLE_CUSTOMER_MISSING",
|
|
1533
|
+
"DISCOUNT_NO_ENTITLED_LINE_ITEMS",
|
|
1534
|
+
"DISCOUNT_NO_ENTITLED_SHIPPING_LINES",
|
|
1535
|
+
"DISCOUNT_NOT_FOUND",
|
|
1536
|
+
"DISCOUNT_PURCHASE_NOT_IN_RANGE",
|
|
1537
|
+
"DISCOUNT_USAGE_LIMIT_REACHED",
|
|
1538
|
+
"MERCHANDISE_NOT_ENOUGH_STOCK",
|
|
1539
|
+
"MERCHANDISE_OUT_OF_STOCK"
|
|
1540
|
+
];
|
|
1541
|
+
var cartWarningCodeSchema = z4.enum(CART_WARNING_CODES);
|
|
1542
|
+
var cartWarningSchema = z4.object({
|
|
1543
|
+
code: cartWarningCodeSchema,
|
|
1544
|
+
message: z4.string().min(1),
|
|
1545
|
+
target: z4.string().min(1)
|
|
1546
|
+
}).strict();
|
|
1547
|
+
var updateDiscountCodesBodySchema = z4.object({
|
|
1548
|
+
cartToken: commerceCapabilitySchema,
|
|
1549
|
+
expectedRevision: z4.number().int().nonnegative(),
|
|
1550
|
+
discountCodes: z4.array(z4.string().trim().min(1).max(MAX_CART_DISCOUNT_CODE_LENGTH)).max(
|
|
1551
|
+
MAX_CART_DISCOUNT_CODES,
|
|
1552
|
+
`discountCodes cannot contain more than ${MAX_CART_DISCOUNT_CODES} values`
|
|
1553
|
+
)
|
|
1554
|
+
}).strict();
|
|
1555
|
+
var updateDiscountCodesParamsSchema = updateDiscountCodesBodySchema.extend({
|
|
1556
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
1557
|
+
});
|
|
1558
|
+
var MAX_CART_LINE_ADMISSIONS = 32;
|
|
1559
|
+
var publicMediaSizeSchema = z4.object({
|
|
1560
|
+
width: z4.number().nullable().optional(),
|
|
1561
|
+
height: z4.number().nullable().optional(),
|
|
1562
|
+
mimeType: z4.string().nullable().optional(),
|
|
1563
|
+
filename: z4.string().nullable().optional(),
|
|
1564
|
+
url: z4.string().nullable().optional()
|
|
1565
|
+
}).strict();
|
|
1566
|
+
var publicMediaAssetSchema = z4.union([
|
|
1567
|
+
z4.string(),
|
|
1568
|
+
z4.object({
|
|
1569
|
+
id: z4.union([z4.string(), z4.number()]).nullable().optional(),
|
|
1570
|
+
alt: z4.string().nullable().optional(),
|
|
1571
|
+
width: z4.number().nullable().optional(),
|
|
1572
|
+
height: z4.number().nullable().optional(),
|
|
1573
|
+
mimeType: z4.string().nullable().optional(),
|
|
1574
|
+
filename: z4.string().nullable().optional(),
|
|
1575
|
+
url: z4.string().nullable().optional(),
|
|
1576
|
+
sizes: z4.record(z4.string(), publicMediaSizeSchema).optional()
|
|
1577
|
+
}).strict()
|
|
1133
1578
|
]);
|
|
1134
|
-
var
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1579
|
+
var publicCartReferenceSchema = z4.object({
|
|
1580
|
+
id: z4.string().min(1),
|
|
1581
|
+
title: z4.string().min(1),
|
|
1582
|
+
handle: z4.string().min(1).nullable(),
|
|
1583
|
+
image: publicMediaAssetSchema.nullable()
|
|
1584
|
+
}).strict();
|
|
1585
|
+
var publicCartMarketSchema = z4.object({
|
|
1586
|
+
id: z4.string().min(1),
|
|
1587
|
+
handle: z4.string().min(1),
|
|
1588
|
+
name: z4.string().min(1)
|
|
1589
|
+
}).strict();
|
|
1590
|
+
var publicCartItemAdmissionSchema = z4.object({
|
|
1591
|
+
eventId: z4.string().min(1),
|
|
1592
|
+
occurrenceId: z4.string().min(1),
|
|
1593
|
+
admissionTypeId: z4.string().min(1)
|
|
1594
|
+
}).strict();
|
|
1595
|
+
var cartLineAdmissionsInputSchema = z4.array(publicCartItemAdmissionSchema).max(
|
|
1596
|
+
MAX_CART_LINE_ADMISSIONS,
|
|
1597
|
+
`admissions cannot contain more than ${MAX_CART_LINE_ADMISSIONS} values`
|
|
1598
|
+
).min(1, "admissions must contain at least one value").superRefine((admissions, ctx) => {
|
|
1599
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1600
|
+
admissions.forEach((admission, index) => {
|
|
1601
|
+
const key = `${admission.eventId}:${admission.occurrenceId}:${admission.admissionTypeId}`;
|
|
1602
|
+
if (seen.has(key)) {
|
|
1603
|
+
ctx.addIssue({
|
|
1604
|
+
code: "custom",
|
|
1605
|
+
path: [index],
|
|
1606
|
+
message: "admissions must be unique"
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
seen.add(key);
|
|
1610
|
+
});
|
|
1611
|
+
});
|
|
1612
|
+
var cartTokenField = z4.string().min(1, "cartToken is required");
|
|
1613
|
+
var cartMarketField = z4.string().trim().min(1).optional();
|
|
1614
|
+
var cartEntityIdField = z4.union([z4.string(), z4.number()]).transform(String);
|
|
1615
|
+
var createCartSchema = z4.object({
|
|
1616
|
+
market: cartMarketField,
|
|
1617
|
+
attributes: publicAttributesSchema.optional()
|
|
1618
|
+
}).strict();
|
|
1619
|
+
var getCartSchema = z4.object({ cartToken: cartTokenField }).strict();
|
|
1620
|
+
var addCartItemSchema = z4.object({
|
|
1621
|
+
cartToken: cartTokenField,
|
|
1622
|
+
product: cartEntityIdField,
|
|
1623
|
+
variant: cartEntityIdField,
|
|
1624
|
+
option: cartEntityIdField.optional(),
|
|
1625
|
+
quantity: z4.number().int().positive("quantity must be a positive integer"),
|
|
1626
|
+
market: cartMarketField,
|
|
1627
|
+
admissions: cartLineAdmissionsInputSchema.optional()
|
|
1628
|
+
}).strict();
|
|
1629
|
+
var updateCartItemSchema = z4.object({
|
|
1630
|
+
cartToken: cartTokenField,
|
|
1631
|
+
cartItemId: cartEntityIdField,
|
|
1632
|
+
quantity: z4.number().int().positive("quantity must be a positive integer")
|
|
1633
|
+
}).strict();
|
|
1634
|
+
var removeCartItemSchema = z4.object({
|
|
1635
|
+
cartToken: cartTokenField,
|
|
1636
|
+
cartItemId: cartEntityIdField
|
|
1637
|
+
}).strict();
|
|
1638
|
+
var updateCartAttributesSchema = z4.object({
|
|
1639
|
+
cartToken: cartTokenField,
|
|
1640
|
+
attributes: publicAttributesSchema
|
|
1641
|
+
}).strict();
|
|
1642
|
+
var clearCartSchema = z4.object({ cartToken: cartTokenField }).strict();
|
|
1643
|
+
function compareAdmissions(left, right) {
|
|
1644
|
+
for (const field of ["eventId", "occurrenceId", "admissionTypeId"]) {
|
|
1645
|
+
if (left[field] < right[field]) return -1;
|
|
1646
|
+
if (left[field] > right[field]) return 1;
|
|
1647
|
+
}
|
|
1648
|
+
return 0;
|
|
1649
|
+
}
|
|
1650
|
+
var publicCartItemAdmissionsSchema = z4.array(publicCartItemAdmissionSchema).max(MAX_CART_LINE_ADMISSIONS).superRefine((admissions, ctx) => {
|
|
1651
|
+
let previous;
|
|
1652
|
+
admissions.forEach((admission, index) => {
|
|
1653
|
+
const comparison = previous ? compareAdmissions(admission, previous) : void 0;
|
|
1654
|
+
if (comparison !== void 0 && comparison <= 0) {
|
|
1655
|
+
ctx.addIssue({
|
|
1656
|
+
code: "custom",
|
|
1657
|
+
path: [index],
|
|
1658
|
+
message: comparison === 0 ? "admissions must be unique" : "admissions must be in canonical order"
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1661
|
+
previous = admission;
|
|
1662
|
+
});
|
|
1663
|
+
});
|
|
1664
|
+
var publicCartItemSchema = z4.object({
|
|
1665
|
+
id: z4.string().min(1),
|
|
1666
|
+
product: publicCartReferenceSchema,
|
|
1667
|
+
variant: publicCartReferenceSchema,
|
|
1668
|
+
admissions: publicCartItemAdmissionsSchema,
|
|
1669
|
+
quantity: z4.number().int().positive().max(MAX_CART_LINE_QUANTITY),
|
|
1670
|
+
unitPriceMinor: minorAmountSchema,
|
|
1671
|
+
discountMinor: minorAmountSchema,
|
|
1672
|
+
estimatedLineTotalMinor: minorAmountSchema,
|
|
1673
|
+
requiresShipping: z4.boolean()
|
|
1674
|
+
}).strict().superRefine((item, ctx) => {
|
|
1675
|
+
const expectedLineTotal = BigInt(item.unitPriceMinor) * BigInt(item.quantity) - BigInt(item.discountMinor);
|
|
1676
|
+
if (expectedLineTotal < 0n) {
|
|
1677
|
+
ctx.addIssue({
|
|
1678
|
+
code: "custom",
|
|
1679
|
+
path: ["discountMinor"],
|
|
1680
|
+
message: "discountMinor cannot exceed the undiscounted line total"
|
|
1681
|
+
});
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
if (BigInt(item.estimatedLineTotalMinor) !== expectedLineTotal) {
|
|
1685
|
+
ctx.addIssue({
|
|
1686
|
+
code: "custom",
|
|
1687
|
+
path: ["estimatedLineTotalMinor"],
|
|
1688
|
+
message: "estimatedLineTotalMinor must equal unitPriceMinor * quantity - discountMinor"
|
|
1689
|
+
});
|
|
1690
|
+
}
|
|
1691
|
+
});
|
|
1692
|
+
var publicCartSchema = z4.object({
|
|
1693
|
+
id: z4.string().min(1),
|
|
1694
|
+
status: z4.enum(["active", "completed", "abandoned"]),
|
|
1695
|
+
revision: z4.number().int().nonnegative(),
|
|
1696
|
+
currency: currencyCodeSchema,
|
|
1697
|
+
market: publicCartMarketSchema,
|
|
1698
|
+
subtotalMinor: minorAmountSchema,
|
|
1699
|
+
discountMinor: minorAmountSchema,
|
|
1700
|
+
estimatedTotalMinor: minorAmountSchema,
|
|
1701
|
+
discountCodes: z4.array(cartDiscountCodeSchema),
|
|
1702
|
+
attributes: publicAttributesSchema,
|
|
1703
|
+
items: z4.array(publicCartItemSchema),
|
|
1704
|
+
expiresAt: z4.string().datetime({ offset: true }),
|
|
1705
|
+
createdAt: z4.string().datetime({ offset: true }),
|
|
1706
|
+
updatedAt: z4.string().datetime({ offset: true })
|
|
1707
|
+
}).strict().superRefine((cart, ctx) => {
|
|
1708
|
+
const expectedSubtotal = cart.items.reduce(
|
|
1709
|
+
(total, item) => total + BigInt(item.unitPriceMinor) * BigInt(item.quantity),
|
|
1710
|
+
0n
|
|
1711
|
+
);
|
|
1712
|
+
const expectedTotal = expectedSubtotal - BigInt(cart.discountMinor);
|
|
1713
|
+
const expectedDiscount = cart.items.reduce(
|
|
1714
|
+
(total, item) => total + BigInt(item.discountMinor),
|
|
1715
|
+
0n
|
|
1716
|
+
);
|
|
1717
|
+
if (BigInt(cart.subtotalMinor) !== expectedSubtotal) {
|
|
1718
|
+
ctx.addIssue({
|
|
1719
|
+
code: "custom",
|
|
1720
|
+
path: ["subtotalMinor"],
|
|
1721
|
+
message: "subtotalMinor must equal the sum of undiscounted cart line totals"
|
|
1722
|
+
});
|
|
1723
|
+
}
|
|
1724
|
+
if (BigInt(cart.discountMinor) !== expectedDiscount) {
|
|
1725
|
+
ctx.addIssue({
|
|
1726
|
+
code: "custom",
|
|
1727
|
+
path: ["discountMinor"],
|
|
1728
|
+
message: "discountMinor must equal the sum of cart line discounts"
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
if (expectedTotal < 0n) {
|
|
1732
|
+
ctx.addIssue({
|
|
1733
|
+
code: "custom",
|
|
1734
|
+
path: ["discountMinor"],
|
|
1735
|
+
message: "discountMinor cannot exceed subtotalMinor"
|
|
1736
|
+
});
|
|
1737
|
+
} else if (BigInt(cart.estimatedTotalMinor) !== expectedTotal) {
|
|
1738
|
+
ctx.addIssue({
|
|
1739
|
+
code: "custom",
|
|
1740
|
+
path: ["estimatedTotalMinor"],
|
|
1741
|
+
message: "estimatedTotalMinor must equal subtotalMinor - discountMinor"
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
});
|
|
1745
|
+
var cartMutationResultSchema = z4.object({
|
|
1746
|
+
cart: publicCartSchema,
|
|
1747
|
+
warnings: z4.array(cartWarningSchema)
|
|
1748
|
+
}).strict();
|
|
1749
|
+
var createCartParamsSchema = z4.object({
|
|
1750
|
+
market: commerceResourceIdSchema.optional(),
|
|
1751
|
+
attributes: publicAttributesSchema.optional()
|
|
1752
|
+
}).strict();
|
|
1753
|
+
var createCartResultSchema = z4.object({
|
|
1754
|
+
cart: publicCartSchema,
|
|
1755
|
+
warnings: z4.array(cartWarningSchema),
|
|
1756
|
+
cartToken: commerceCapabilitySchema
|
|
1757
|
+
}).strict().superRefine((result, ctx) => {
|
|
1758
|
+
if (result.cart.revision !== 0) {
|
|
1759
|
+
ctx.addIssue({
|
|
1760
|
+
code: "custom",
|
|
1761
|
+
path: ["cart", "revision"],
|
|
1762
|
+
message: "a newly created Cart must start at revision 0"
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
});
|
|
1766
|
+
var retrieveCartParamsSchema = z4.object({ cartToken: commerceCapabilitySchema }).strict();
|
|
1767
|
+
var addItemAdmissionsSchema = z4.tuple([publicCartItemAdmissionSchema], publicCartItemAdmissionSchema).readonly().superRefine((admissions, ctx) => {
|
|
1768
|
+
if (admissions.length > MAX_CART_LINE_ADMISSIONS) {
|
|
1769
|
+
ctx.addIssue({
|
|
1770
|
+
code: "too_big",
|
|
1771
|
+
origin: "array",
|
|
1772
|
+
maximum: MAX_CART_LINE_ADMISSIONS,
|
|
1773
|
+
inclusive: true,
|
|
1774
|
+
message: `admissions cannot contain more than ${MAX_CART_LINE_ADMISSIONS} values`
|
|
1775
|
+
});
|
|
1776
|
+
}
|
|
1777
|
+
admissions.forEach((admission, index) => {
|
|
1778
|
+
if (index === 0) return;
|
|
1779
|
+
const comparison = compareAdmissions(admission, admissions[index - 1]);
|
|
1780
|
+
if (comparison <= 0) {
|
|
1781
|
+
ctx.addIssue({
|
|
1782
|
+
code: "custom",
|
|
1783
|
+
path: [index],
|
|
1784
|
+
message: comparison === 0 ? "admissions must be unique" : "admissions must be in canonical order"
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
});
|
|
1788
|
+
});
|
|
1789
|
+
var addItemBodySchema = z4.object({
|
|
1790
|
+
cartToken: commerceCapabilitySchema,
|
|
1791
|
+
expectedRevision: z4.number().int().nonnegative(),
|
|
1792
|
+
productId: commerceResourceIdSchema,
|
|
1793
|
+
variantId: commerceResourceIdSchema,
|
|
1794
|
+
quantity: z4.number().int().positive().max(MAX_CART_LINE_QUANTITY),
|
|
1795
|
+
admissions: addItemAdmissionsSchema.optional()
|
|
1796
|
+
}).strict();
|
|
1797
|
+
var addItemParamsSchema = addItemBodySchema.extend({
|
|
1798
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
1799
|
+
});
|
|
1800
|
+
var updateItemBodySchema = z4.object({
|
|
1801
|
+
cartToken: commerceCapabilitySchema,
|
|
1802
|
+
expectedRevision: z4.number().int().nonnegative(),
|
|
1803
|
+
cartItemId: commerceResourceIdSchema,
|
|
1804
|
+
quantity: z4.number().int().positive().max(MAX_CART_LINE_QUANTITY)
|
|
1805
|
+
}).strict();
|
|
1806
|
+
var updateItemParamsSchema = updateItemBodySchema.extend({
|
|
1807
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
1808
|
+
});
|
|
1809
|
+
var removeItemBodySchema = z4.object({
|
|
1810
|
+
cartToken: commerceCapabilitySchema,
|
|
1811
|
+
expectedRevision: z4.number().int().nonnegative(),
|
|
1812
|
+
cartItemId: commerceResourceIdSchema
|
|
1813
|
+
}).strict();
|
|
1814
|
+
var removeItemParamsSchema = removeItemBodySchema.extend({
|
|
1815
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
1816
|
+
});
|
|
1817
|
+
var clearCartBodySchema = z4.object({
|
|
1818
|
+
cartToken: commerceCapabilitySchema,
|
|
1819
|
+
expectedRevision: z4.number().int().nonnegative()
|
|
1820
|
+
}).strict();
|
|
1821
|
+
var clearCartParamsSchema = clearCartBodySchema.extend({
|
|
1822
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
1823
|
+
});
|
|
1824
|
+
var updateCartAttributesBodySchema = z4.object({
|
|
1825
|
+
cartToken: commerceCapabilitySchema,
|
|
1826
|
+
expectedRevision: z4.number().int().nonnegative(),
|
|
1827
|
+
attributes: publicAttributesSchema
|
|
1828
|
+
}).strict();
|
|
1829
|
+
var updateCartAttributesParamsSchema = updateCartAttributesBodySchema.extend({
|
|
1830
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
1831
|
+
});
|
|
1832
|
+
|
|
1833
|
+
// ../../internal/contracts/src/ecommerce/checkout.ts
|
|
1834
|
+
import { z as z6 } from "zod";
|
|
1835
|
+
|
|
1836
|
+
// ../../internal/contracts/src/ecommerce/payment-session.ts
|
|
1837
|
+
import { z as z5 } from "zod";
|
|
1838
|
+
var tossProviderOrderIdSchema = z5.string().min(6).max(64).regex(
|
|
1839
|
+
/^[A-Za-z0-9_-]+$/,
|
|
1840
|
+
"providerOrderId may contain only ASCII letters, digits, underscores, and hyphens"
|
|
1841
|
+
);
|
|
1842
|
+
var accountAliasUuidV4Schema = z5.string().regex(
|
|
1843
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
|
|
1844
|
+
"providerCustomerKey must be ANONYMOUS or a UUIDv4 account alias"
|
|
1845
|
+
);
|
|
1846
|
+
var tossProviderCustomerKeySchema = z5.union([
|
|
1847
|
+
z5.literal("ANONYMOUS"),
|
|
1848
|
+
accountAliasUuidV4Schema
|
|
1141
1849
|
]);
|
|
1142
|
-
var
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
"
|
|
1850
|
+
var createPaymentSessionBaseBodyShape = {
|
|
1851
|
+
checkoutToken: commerceCapabilitySchema
|
|
1852
|
+
};
|
|
1853
|
+
var createTossPaymentSessionBodySchema = z5.object({
|
|
1854
|
+
...createPaymentSessionBaseBodyShape,
|
|
1855
|
+
provider: z5.literal("toss"),
|
|
1856
|
+
providerOptions: z5.object({ profile: z5.literal("widget_v2") }).strict()
|
|
1857
|
+
}).strict();
|
|
1858
|
+
var createPaymentSessionParamsSchema = createTossPaymentSessionBodySchema.extend({
|
|
1859
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
1860
|
+
});
|
|
1861
|
+
var retrieveBrowserPaymentSessionParamsSchema = z5.object({
|
|
1862
|
+
paymentSessionId: commerceResourceIdSchema,
|
|
1863
|
+
checkoutToken: commerceCapabilitySchema
|
|
1864
|
+
}).strict();
|
|
1865
|
+
var retrieveServerPaymentSessionParamsSchema = z5.object({ paymentSessionId: commerceResourceIdSchema }).strict();
|
|
1866
|
+
var cancelBrowserPaymentSessionBodySchema = z5.object({
|
|
1867
|
+
paymentSessionId: commerceResourceIdSchema,
|
|
1868
|
+
checkoutToken: commerceCapabilitySchema
|
|
1869
|
+
}).strict();
|
|
1870
|
+
var cancelBrowserPaymentSessionParamsSchema = cancelBrowserPaymentSessionBodySchema.extend({
|
|
1871
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
1872
|
+
});
|
|
1873
|
+
var cancelServerPaymentSessionBodySchema = z5.object({
|
|
1874
|
+
paymentSessionId: commerceResourceIdSchema
|
|
1875
|
+
}).strict();
|
|
1876
|
+
var cancelServerPaymentSessionParamsSchema = cancelServerPaymentSessionBodySchema.extend({
|
|
1877
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
1878
|
+
});
|
|
1879
|
+
var cancelPaymentSessionParamsSchema = z5.union([
|
|
1880
|
+
cancelBrowserPaymentSessionParamsSchema,
|
|
1881
|
+
cancelServerPaymentSessionParamsSchema
|
|
1148
1882
|
]);
|
|
1149
|
-
var
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1883
|
+
var confirmTossPaymentSessionBodySchema = z5.object({
|
|
1884
|
+
paymentSessionId: commerceResourceIdSchema,
|
|
1885
|
+
action: z5.object({
|
|
1886
|
+
type: z5.literal("toss_authorization"),
|
|
1887
|
+
paymentKey: z5.string().min(1).max(512),
|
|
1888
|
+
providerOrderId: tossProviderOrderIdSchema
|
|
1889
|
+
}).strict()
|
|
1890
|
+
}).strict();
|
|
1891
|
+
var confirmTossPaymentSessionParamsSchema = confirmTossPaymentSessionBodySchema.extend({
|
|
1892
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
1893
|
+
});
|
|
1894
|
+
var paymentNextActionSchema = z5.object({
|
|
1895
|
+
type: z5.literal("toss_widget"),
|
|
1896
|
+
clientKey: z5.string().min(1).max(255),
|
|
1897
|
+
paymentMethodVariantKey: z5.string().min(1).max(255),
|
|
1898
|
+
agreementVariantKey: z5.string().min(1).max(255),
|
|
1899
|
+
providerOrderId: tossProviderOrderIdSchema,
|
|
1900
|
+
providerCustomerKey: tossProviderCustomerKeySchema,
|
|
1901
|
+
orderName: z5.string().min(1).max(200),
|
|
1902
|
+
customerName: z5.string().min(1).max(200).optional(),
|
|
1903
|
+
customerEmail: z5.string().email().max(254).optional()
|
|
1904
|
+
}).strict();
|
|
1905
|
+
var PAYMENT_SESSION_ROLES = [
|
|
1906
|
+
"active",
|
|
1907
|
+
"canonical_candidate",
|
|
1908
|
+
"canonical",
|
|
1909
|
+
"residual",
|
|
1910
|
+
"historical"
|
|
1911
|
+
];
|
|
1912
|
+
var paymentSessionRoleSchema = z5.enum(PAYMENT_SESSION_ROLES);
|
|
1913
|
+
var PAYMENT_PROVIDER_STATUSES = [
|
|
1914
|
+
"requires_payment_method",
|
|
1915
|
+
"requires_action",
|
|
1916
|
+
"requires_confirmation",
|
|
1917
|
+
"initializing",
|
|
1918
|
+
"processing",
|
|
1919
|
+
"authorized",
|
|
1920
|
+
"canceling",
|
|
1921
|
+
"unknown",
|
|
1922
|
+
"captured",
|
|
1923
|
+
"failed",
|
|
1156
1924
|
"canceled"
|
|
1157
|
-
]
|
|
1158
|
-
var
|
|
1159
|
-
|
|
1160
|
-
"
|
|
1161
|
-
"
|
|
1162
|
-
"
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
"
|
|
1166
|
-
"
|
|
1167
|
-
"
|
|
1168
|
-
"
|
|
1169
|
-
"
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1925
|
+
];
|
|
1926
|
+
var paymentProviderStatusSchema = z5.enum(PAYMENT_PROVIDER_STATUSES);
|
|
1927
|
+
var PAYMENT_RECONCILIATION_REASONS = [
|
|
1928
|
+
"provider_outcome_unknown",
|
|
1929
|
+
"local_commit_ambiguous",
|
|
1930
|
+
"amount_mismatch",
|
|
1931
|
+
"currency_mismatch",
|
|
1932
|
+
"excess_capture_pending_order",
|
|
1933
|
+
"inventory_unavailable",
|
|
1934
|
+
"admission_unavailable",
|
|
1935
|
+
"excess_capture",
|
|
1936
|
+
"late_capture",
|
|
1937
|
+
"cross_checkout_duplicate"
|
|
1938
|
+
];
|
|
1939
|
+
var paymentReconciliationReasonSchema = z5.enum(
|
|
1940
|
+
PAYMENT_RECONCILIATION_REASONS
|
|
1941
|
+
);
|
|
1942
|
+
function requiredReconciliationSchema(reasons) {
|
|
1943
|
+
const reasonSchema = z5.enum(reasons);
|
|
1944
|
+
return z5.object({
|
|
1945
|
+
status: z5.literal("required"),
|
|
1946
|
+
reasons: z5.array(reasonSchema).min(1).readonly()
|
|
1947
|
+
}).strict().superRefine((value, ctx) => {
|
|
1948
|
+
const indexes = new Map(reasons.map((reason, index) => [reason, index]));
|
|
1949
|
+
let previous = -1;
|
|
1950
|
+
value.reasons.forEach((reason, index) => {
|
|
1951
|
+
const current = indexes.get(reason) ?? -1;
|
|
1952
|
+
if (current <= previous) {
|
|
1953
|
+
ctx.addIssue({
|
|
1954
|
+
code: "custom",
|
|
1955
|
+
path: ["reasons", index],
|
|
1956
|
+
message: "reconciliation reasons must be unique and canonical-sorted"
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
previous = current;
|
|
1960
|
+
});
|
|
1961
|
+
});
|
|
1962
|
+
}
|
|
1963
|
+
var noReconciliationSchema = z5.object({ status: z5.literal("none") }).strict();
|
|
1964
|
+
var publicCaptureEvidenceSchema = z5.object({
|
|
1965
|
+
amountMinor: z5.number().int().nonnegative(),
|
|
1966
|
+
currency: currencyCodeSchema,
|
|
1967
|
+
observedAt: z5.string().datetime({ offset: true })
|
|
1968
|
+
}).strict();
|
|
1969
|
+
var reconciliationRefundEvidenceSchema = z5.object({
|
|
1970
|
+
providerRefundId: z5.string().min(1),
|
|
1971
|
+
money: moneySchema,
|
|
1972
|
+
observedAt: z5.string().datetime({ offset: true })
|
|
1973
|
+
}).strict();
|
|
1974
|
+
var PAYMENT_FAILURE_REASONS = [
|
|
1975
|
+
"payment_declined",
|
|
1976
|
+
"authentication_failed",
|
|
1977
|
+
"authorization_expired",
|
|
1978
|
+
"payment_method_unavailable",
|
|
1979
|
+
"provider_terminal_failure",
|
|
1980
|
+
"unknown_provider_terminal_failure"
|
|
1981
|
+
];
|
|
1982
|
+
var paymentFailureReasonSchema = z5.enum(PAYMENT_FAILURE_REASONS);
|
|
1983
|
+
var orderReferenceSchema = z5.object({
|
|
1984
|
+
id: z5.string().min(1),
|
|
1985
|
+
orderNumber: z5.string().min(1)
|
|
1986
|
+
}).strict();
|
|
1987
|
+
var paymentSessionBaseShape = {
|
|
1988
|
+
id: z5.string().min(1),
|
|
1989
|
+
money: moneySchema,
|
|
1990
|
+
expiresAt: z5.string().datetime({ offset: true }).nullable()
|
|
1991
|
+
};
|
|
1992
|
+
var suppressedNotReadyShape = {
|
|
1993
|
+
presentationStatus: z5.literal("suppressed"),
|
|
1994
|
+
finalizationStatus: z5.literal("not_ready"),
|
|
1995
|
+
reconciliation: noReconciliationSchema,
|
|
1996
|
+
order: z5.null()
|
|
1997
|
+
};
|
|
1998
|
+
function stateSchemas(nextAction) {
|
|
1999
|
+
return [
|
|
2000
|
+
z5.object({
|
|
2001
|
+
providerStatus: z5.enum(["requires_payment_method", "requires_action"]),
|
|
2002
|
+
sessionRole: z5.literal("active"),
|
|
2003
|
+
presentationStatus: z5.literal("actionable"),
|
|
2004
|
+
finalizationStatus: z5.literal("not_ready"),
|
|
2005
|
+
nextAction,
|
|
2006
|
+
reconciliation: noReconciliationSchema,
|
|
2007
|
+
order: z5.null()
|
|
2008
|
+
}),
|
|
2009
|
+
z5.object({
|
|
2010
|
+
providerStatus: z5.enum(["requires_payment_method", "requires_action"]),
|
|
2011
|
+
sessionRole: z5.literal("residual"),
|
|
2012
|
+
...suppressedNotReadyShape
|
|
2013
|
+
}),
|
|
2014
|
+
z5.object({
|
|
2015
|
+
providerStatus: z5.literal("requires_confirmation"),
|
|
2016
|
+
sessionRole: z5.enum(["active", "residual"]),
|
|
2017
|
+
...suppressedNotReadyShape
|
|
2018
|
+
}),
|
|
2019
|
+
z5.object({
|
|
2020
|
+
providerStatus: z5.enum(["initializing", "processing", "authorized"]),
|
|
2021
|
+
sessionRole: z5.enum(["active", "residual"]),
|
|
2022
|
+
...suppressedNotReadyShape
|
|
2023
|
+
}),
|
|
2024
|
+
z5.object({
|
|
2025
|
+
providerStatus: z5.literal("canceling"),
|
|
2026
|
+
sessionRole: z5.enum(["active", "residual"]),
|
|
2027
|
+
...suppressedNotReadyShape
|
|
2028
|
+
}),
|
|
2029
|
+
z5.object({
|
|
2030
|
+
providerStatus: z5.literal("unknown"),
|
|
2031
|
+
sessionRole: z5.enum(["active", "residual"]),
|
|
2032
|
+
presentationStatus: z5.literal("suppressed"),
|
|
2033
|
+
finalizationStatus: z5.literal("not_ready"),
|
|
2034
|
+
reconciliation: requiredReconciliationSchema([
|
|
2035
|
+
"provider_outcome_unknown"
|
|
2036
|
+
]),
|
|
2037
|
+
order: z5.null()
|
|
2038
|
+
}),
|
|
2039
|
+
z5.object({
|
|
2040
|
+
providerStatus: z5.literal("captured"),
|
|
2041
|
+
sessionRole: z5.enum(["canonical_candidate", "residual"]),
|
|
2042
|
+
presentationStatus: z5.literal("suppressed"),
|
|
2043
|
+
finalizationStatus: z5.literal("pending"),
|
|
2044
|
+
reconciliation: noReconciliationSchema,
|
|
2045
|
+
providerEvidence: publicCaptureEvidenceSchema,
|
|
2046
|
+
order: z5.null()
|
|
2047
|
+
}),
|
|
2048
|
+
z5.object({
|
|
2049
|
+
providerStatus: z5.literal("captured"),
|
|
2050
|
+
sessionRole: z5.enum(["canonical", "historical"]),
|
|
2051
|
+
presentationStatus: z5.literal("suppressed"),
|
|
2052
|
+
finalizationStatus: z5.literal("committed"),
|
|
2053
|
+
reconciliation: noReconciliationSchema,
|
|
2054
|
+
providerEvidence: publicCaptureEvidenceSchema,
|
|
2055
|
+
order: orderReferenceSchema
|
|
2056
|
+
}),
|
|
2057
|
+
z5.object({
|
|
2058
|
+
providerStatus: z5.literal("captured"),
|
|
2059
|
+
sessionRole: z5.enum(["canonical_candidate", "residual"]),
|
|
2060
|
+
presentationStatus: z5.literal("suppressed"),
|
|
2061
|
+
finalizationStatus: z5.literal("pending"),
|
|
2062
|
+
reconciliation: requiredReconciliationSchema([
|
|
2063
|
+
"local_commit_ambiguous",
|
|
2064
|
+
"amount_mismatch",
|
|
2065
|
+
"currency_mismatch",
|
|
2066
|
+
"excess_capture_pending_order"
|
|
2067
|
+
]),
|
|
2068
|
+
providerEvidence: publicCaptureEvidenceSchema,
|
|
2069
|
+
order: z5.null()
|
|
2070
|
+
}),
|
|
2071
|
+
z5.object({
|
|
2072
|
+
providerStatus: z5.literal("captured"),
|
|
2073
|
+
sessionRole: z5.enum(["canonical", "residual"]),
|
|
2074
|
+
presentationStatus: z5.literal("suppressed"),
|
|
2075
|
+
finalizationStatus: z5.literal("committed"),
|
|
2076
|
+
reconciliation: requiredReconciliationSchema([
|
|
2077
|
+
"inventory_unavailable",
|
|
2078
|
+
"admission_unavailable",
|
|
2079
|
+
"amount_mismatch",
|
|
2080
|
+
"currency_mismatch",
|
|
2081
|
+
"excess_capture",
|
|
2082
|
+
"late_capture",
|
|
2083
|
+
"cross_checkout_duplicate"
|
|
2084
|
+
]),
|
|
2085
|
+
providerEvidence: publicCaptureEvidenceSchema,
|
|
2086
|
+
order: orderReferenceSchema
|
|
2087
|
+
}),
|
|
2088
|
+
z5.object({
|
|
2089
|
+
providerStatus: z5.literal("failed"),
|
|
2090
|
+
sessionRole: z5.literal("historical"),
|
|
2091
|
+
presentationStatus: z5.literal("suppressed"),
|
|
2092
|
+
finalizationStatus: z5.literal("not_ready"),
|
|
2093
|
+
reconciliation: noReconciliationSchema,
|
|
2094
|
+
failure: z5.object({
|
|
2095
|
+
reason: paymentFailureReasonSchema,
|
|
2096
|
+
message: z5.string().min(1).optional()
|
|
2097
|
+
}).strict(),
|
|
2098
|
+
order: z5.null()
|
|
2099
|
+
}),
|
|
2100
|
+
z5.object({
|
|
2101
|
+
providerStatus: z5.literal("canceled"),
|
|
2102
|
+
sessionRole: z5.literal("historical"),
|
|
2103
|
+
presentationStatus: z5.literal("suppressed"),
|
|
2104
|
+
finalizationStatus: z5.literal("not_ready"),
|
|
2105
|
+
cancellationReason: z5.enum([
|
|
2106
|
+
"expired",
|
|
2107
|
+
"customer",
|
|
2108
|
+
"operator",
|
|
2109
|
+
"provider"
|
|
2110
|
+
]),
|
|
2111
|
+
reconciliation: noReconciliationSchema,
|
|
2112
|
+
order: z5.null()
|
|
2113
|
+
})
|
|
2114
|
+
];
|
|
2115
|
+
}
|
|
2116
|
+
function providerSessionSchemas(action) {
|
|
2117
|
+
return stateSchemas(action).map(
|
|
2118
|
+
(state) => z5.object({
|
|
2119
|
+
...paymentSessionBaseShape,
|
|
2120
|
+
provider: z5.literal("toss"),
|
|
2121
|
+
...state.shape
|
|
2122
|
+
}).strict()
|
|
2123
|
+
);
|
|
2124
|
+
}
|
|
2125
|
+
var publicPaymentSessionVariants = [
|
|
2126
|
+
...providerSessionSchemas(paymentNextActionSchema)
|
|
2127
|
+
];
|
|
2128
|
+
var publicPaymentSessionSchema = z5.union(publicPaymentSessionVariants);
|
|
2129
|
+
var CreatePaymentSessionParamsSchema = createPaymentSessionParamsSchema;
|
|
2130
|
+
var CancelServerPaymentSessionParamsSchema = cancelServerPaymentSessionParamsSchema;
|
|
2131
|
+
var ConfirmTossPaymentSessionParamsSchema = confirmTossPaymentSessionParamsSchema;
|
|
2132
|
+
|
|
2133
|
+
// ../../internal/contracts/src/ecommerce/checkout.ts
|
|
2134
|
+
var canonicalPublicCheckoutItemSchema = z6.object({
|
|
2135
|
+
id: z6.string().min(1),
|
|
2136
|
+
product: publicCartReferenceSchema,
|
|
2137
|
+
variant: publicCartReferenceSchema,
|
|
2138
|
+
productTitle: z6.string().min(1),
|
|
2139
|
+
variantTitle: z6.string().min(1).nullable(),
|
|
2140
|
+
sku: z6.string().min(1).nullable(),
|
|
2141
|
+
admissions: publicCartItemAdmissionsSchema,
|
|
2142
|
+
quantity: z6.number().int().positive().max(MAX_CART_LINE_QUANTITY),
|
|
2143
|
+
unitPriceMinor: minorAmountSchema,
|
|
2144
|
+
discountMinor: minorAmountSchema,
|
|
2145
|
+
lineTotalMinor: minorAmountSchema,
|
|
2146
|
+
requiresShipping: z6.boolean()
|
|
2147
|
+
}).strict().superRefine((item, ctx) => {
|
|
2148
|
+
const expectedLineTotal = BigInt(item.unitPriceMinor) * BigInt(item.quantity) - BigInt(item.discountMinor);
|
|
2149
|
+
if (expectedLineTotal < 0n) {
|
|
2150
|
+
ctx.addIssue({
|
|
2151
|
+
code: "custom",
|
|
2152
|
+
path: ["discountMinor"],
|
|
2153
|
+
message: "discountMinor cannot exceed the undiscounted line total"
|
|
2154
|
+
});
|
|
2155
|
+
return;
|
|
2156
|
+
}
|
|
2157
|
+
if (BigInt(item.lineTotalMinor) !== expectedLineTotal) {
|
|
2158
|
+
ctx.addIssue({
|
|
2159
|
+
code: "custom",
|
|
2160
|
+
path: ["lineTotalMinor"],
|
|
2161
|
+
message: "lineTotalMinor must equal unitPriceMinor * quantity - discountMinor"
|
|
2162
|
+
});
|
|
2163
|
+
}
|
|
2164
|
+
});
|
|
2165
|
+
var checkoutAmountsSchema = z6.object({
|
|
2166
|
+
currency: currencyCodeSchema,
|
|
2167
|
+
subtotalMinor: minorAmountSchema,
|
|
2168
|
+
shippingMinor: minorAmountSchema,
|
|
2169
|
+
discountMinor: minorAmountSchema,
|
|
2170
|
+
totalMinor: minorAmountSchema
|
|
2171
|
+
}).strict().superRefine((amounts, ctx) => {
|
|
2172
|
+
const expectedTotal = BigInt(amounts.subtotalMinor) + BigInt(amounts.shippingMinor) - BigInt(amounts.discountMinor);
|
|
2173
|
+
if (BigInt(amounts.totalMinor) !== expectedTotal) {
|
|
2174
|
+
ctx.addIssue({
|
|
2175
|
+
code: "custom",
|
|
2176
|
+
path: ["totalMinor"],
|
|
2177
|
+
message: "totalMinor must equal subtotalMinor + shippingMinor - discountMinor"
|
|
2178
|
+
});
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
var checkoutPaymentSessionRefSchema = z6.object({
|
|
2182
|
+
id: z6.string().min(1),
|
|
2183
|
+
provider: z6.literal("toss"),
|
|
2184
|
+
providerStatus: paymentProviderStatusSchema
|
|
1188
2185
|
}).strict();
|
|
1189
|
-
var
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
2186
|
+
var openCheckoutPaymentStateSchema = z6.object({
|
|
2187
|
+
activePaymentSession: checkoutPaymentSessionRefSchema.nullable()
|
|
2188
|
+
}).strict();
|
|
2189
|
+
var spentCheckoutPaymentStateSchema = z6.object({
|
|
2190
|
+
activePaymentSession: z6.null()
|
|
2191
|
+
}).strict();
|
|
2192
|
+
var lightweightOrderReferenceSchema = z6.object({
|
|
2193
|
+
id: z6.string().min(1),
|
|
2194
|
+
orderNumber: z6.string().min(1)
|
|
2195
|
+
}).strict();
|
|
2196
|
+
var publicCheckoutBaseShape = {
|
|
2197
|
+
id: z6.string().min(1),
|
|
2198
|
+
amounts: checkoutAmountsSchema,
|
|
2199
|
+
items: z6.array(canonicalPublicCheckoutItemSchema).min(1),
|
|
2200
|
+
customerSnapshot: customerSnapshotSchema,
|
|
2201
|
+
shippingAddress: checkoutShippingAddressSchema.nullable(),
|
|
2202
|
+
attributes: publicAttributesSchema,
|
|
2203
|
+
expiresAt: z6.string().datetime({ offset: true }),
|
|
2204
|
+
createdAt: z6.string().datetime({ offset: true }),
|
|
2205
|
+
updatedAt: z6.string().datetime({ offset: true })
|
|
2206
|
+
};
|
|
2207
|
+
var abandonedReasonSchema = z6.enum(["expired", "customer", "operator"]);
|
|
2208
|
+
var publicCheckoutVariants = [
|
|
2209
|
+
z6.object({
|
|
2210
|
+
...publicCheckoutBaseShape,
|
|
2211
|
+
status: z6.literal("open"),
|
|
2212
|
+
paymentState: openCheckoutPaymentStateSchema,
|
|
2213
|
+
order: z6.null()
|
|
1197
2214
|
}).strict(),
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
2215
|
+
z6.object({
|
|
2216
|
+
...publicCheckoutBaseShape,
|
|
2217
|
+
status: z6.literal("placed"),
|
|
2218
|
+
placedAt: z6.string().datetime({ offset: true }),
|
|
2219
|
+
paymentState: spentCheckoutPaymentStateSchema,
|
|
2220
|
+
order: lightweightOrderReferenceSchema
|
|
2221
|
+
}).strict(),
|
|
2222
|
+
z6.object({
|
|
2223
|
+
...publicCheckoutBaseShape,
|
|
2224
|
+
status: z6.literal("placed"),
|
|
2225
|
+
placedAt: z6.string().datetime({ offset: true }),
|
|
2226
|
+
placedVia: z6.literal("late_capture"),
|
|
2227
|
+
abandonedAt: z6.string().datetime({ offset: true }),
|
|
2228
|
+
abandonedReason: abandonedReasonSchema,
|
|
2229
|
+
paymentState: spentCheckoutPaymentStateSchema,
|
|
2230
|
+
order: lightweightOrderReferenceSchema
|
|
2231
|
+
}).strict(),
|
|
2232
|
+
z6.object({
|
|
2233
|
+
...publicCheckoutBaseShape,
|
|
2234
|
+
status: z6.literal("abandoned"),
|
|
2235
|
+
abandonedAt: z6.string().datetime({ offset: true }),
|
|
2236
|
+
abandonedReason: abandonedReasonSchema,
|
|
2237
|
+
paymentState: z6.object({
|
|
2238
|
+
activePaymentSession: z6.null()
|
|
2239
|
+
}).strict(),
|
|
2240
|
+
order: z6.null()
|
|
2241
|
+
}).strict()
|
|
2242
|
+
];
|
|
2243
|
+
function validateCheckoutSnapshot(input, ctx) {
|
|
2244
|
+
const checkout = input;
|
|
2245
|
+
const expectedSubtotal = checkout.items.reduce(
|
|
2246
|
+
(total, item) => total + BigInt(item.unitPriceMinor) * BigInt(item.quantity),
|
|
2247
|
+
0n
|
|
2248
|
+
);
|
|
2249
|
+
const expectedDiscount = checkout.items.reduce(
|
|
2250
|
+
(total, item) => total + BigInt(item.discountMinor),
|
|
2251
|
+
0n
|
|
2252
|
+
);
|
|
2253
|
+
if (BigInt(checkout.amounts.subtotalMinor) !== expectedSubtotal) {
|
|
2254
|
+
ctx.addIssue({
|
|
2255
|
+
code: "custom",
|
|
2256
|
+
path: ["amounts", "subtotalMinor"],
|
|
2257
|
+
message: "subtotalMinor must equal the sum of undiscounted checkout line totals"
|
|
2258
|
+
});
|
|
2259
|
+
}
|
|
2260
|
+
if (BigInt(checkout.amounts.discountMinor) !== expectedDiscount) {
|
|
2261
|
+
ctx.addIssue({
|
|
2262
|
+
code: "custom",
|
|
2263
|
+
path: ["amounts", "discountMinor"],
|
|
2264
|
+
message: "discountMinor must equal the sum of checkout line discounts"
|
|
2265
|
+
});
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
var publicCheckoutSchema = z6.union(publicCheckoutVariants).superRefine(validateCheckoutSnapshot);
|
|
2269
|
+
var serverCheckoutExtraShape = {
|
|
2270
|
+
clientReferenceId: commerceResourceIdSchema.nullable(),
|
|
2271
|
+
integrationMetadata: integrationMetadataSchema
|
|
2272
|
+
};
|
|
2273
|
+
var serverCheckoutVariants = publicCheckoutVariants.map(
|
|
2274
|
+
(variant) => variant.extend(serverCheckoutExtraShape)
|
|
2275
|
+
);
|
|
2276
|
+
var serverCheckoutSchema = z6.union(serverCheckoutVariants).superRefine(validateCheckoutSnapshot);
|
|
2277
|
+
var retrieveCheckoutParamsSchema = z6.object({ checkoutToken: commerceCapabilitySchema }).strict();
|
|
2278
|
+
var retrieveServerCheckoutParamsSchema = z6.object({ checkoutId: commerceResourceIdSchema }).strict();
|
|
2279
|
+
var createCheckoutBodySchema = z6.object({
|
|
2280
|
+
cartToken: commerceCapabilitySchema,
|
|
2281
|
+
customer: customerSnapshotSchema,
|
|
2282
|
+
shippingAddress: checkoutShippingAddressSchema.optional()
|
|
1210
2283
|
}).strict();
|
|
1211
|
-
var
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
),
|
|
1216
|
-
|
|
1217
|
-
receiptUrl: z3.string().optional().describe("Receipt URL (optional)"),
|
|
1218
|
-
paymentKey: z3.string().min(1).optional().describe("Provider payment key for verified paid confirmation"),
|
|
1219
|
-
amount: z3.number().int().positive().optional().describe("Provider-confirmed amount for verified paid confirmation")
|
|
2284
|
+
var createCheckoutParamsSchema = createCheckoutBodySchema.extend({
|
|
2285
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
2286
|
+
});
|
|
2287
|
+
var createServerCheckoutBodySchema = createCheckoutBodySchema.safeExtend({
|
|
2288
|
+
clientReferenceId: commerceResourceIdSchema.optional(),
|
|
2289
|
+
integrationMetadata: integrationMetadataSchema.optional()
|
|
1220
2290
|
}).strict();
|
|
1221
|
-
var
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
),
|
|
1228
|
-
pgOrderId: z3.string().min(1).optional(),
|
|
1229
|
-
amount: z3.number().int().nonnegative("amount must be non-negative").describe("Provider-confirmed amount in minor units"),
|
|
1230
|
-
currency: z3.string().min(1).optional(),
|
|
1231
|
-
paymentMethod: z3.string().optional(),
|
|
1232
|
-
receiptUrl: z3.string().url().optional(),
|
|
1233
|
-
approvedAt: z3.string().optional(),
|
|
1234
|
-
providerStatus: z3.string().optional(),
|
|
1235
|
-
providerEventId: z3.string().min(1).optional(),
|
|
1236
|
-
confirmationSource: z3.enum([
|
|
1237
|
-
"provider_webhook",
|
|
1238
|
-
"provider_lookup",
|
|
1239
|
-
"provider_api_confirm",
|
|
1240
|
-
"manual_server"
|
|
1241
|
-
]).optional(),
|
|
1242
|
-
paymentKey: z3.string().min(1).optional().describe(
|
|
1243
|
-
"Optional provider payment key from the client confirm handshake; stored for BFF/provider refund workflows (also accepted as metadata.tossPaymentKey). Local cancel does not read this field."
|
|
1244
|
-
),
|
|
1245
|
-
metadata: z3.record(z3.string(), z3.unknown()).optional()
|
|
2291
|
+
var createServerCheckoutParamsSchema = createServerCheckoutBodySchema.extend({
|
|
2292
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
2293
|
+
});
|
|
2294
|
+
var createCheckoutResultSchema = z6.object({
|
|
2295
|
+
checkout: publicCheckoutSchema,
|
|
2296
|
+
checkoutToken: commerceCapabilitySchema
|
|
1246
2297
|
}).strict();
|
|
1247
|
-
var
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
2298
|
+
var createServerCheckoutResultSchema = z6.object({
|
|
2299
|
+
checkout: serverCheckoutSchema,
|
|
2300
|
+
checkoutToken: commerceCapabilitySchema
|
|
2301
|
+
}).strict();
|
|
2302
|
+
var canonicalCheckoutQuerySchema = z6.object({
|
|
2303
|
+
limit: z6.number().int().min(1).max(100).default(20),
|
|
2304
|
+
cursor: z6.string().min(1).max(512).optional(),
|
|
2305
|
+
status: z6.array(z6.enum(["open", "placed", "abandoned"])).optional(),
|
|
2306
|
+
createdAtFrom: z6.string().datetime({ offset: true }).optional(),
|
|
2307
|
+
createdAtTo: z6.string().datetime({ offset: true }).optional(),
|
|
2308
|
+
clientReferenceId: commerceResourceIdSchema.optional()
|
|
2309
|
+
}).strict();
|
|
2310
|
+
var checkoutListItemVariants = publicCheckoutVariants.map(
|
|
2311
|
+
(variant) => variant.omit({
|
|
2312
|
+
items: true,
|
|
2313
|
+
shippingAddress: true,
|
|
2314
|
+
attributes: true
|
|
2315
|
+
}).extend({ clientReferenceId: commerceResourceIdSchema.nullable() })
|
|
2316
|
+
);
|
|
2317
|
+
var checkoutListItemSchema = z6.union(checkoutListItemVariants);
|
|
2318
|
+
var canonicalCheckoutQueryResultSchema = z6.object({
|
|
2319
|
+
data: z6.array(checkoutListItemSchema),
|
|
2320
|
+
hasMore: z6.boolean(),
|
|
2321
|
+
nextCursor: z6.string().min(1).max(512).nullable()
|
|
1252
2322
|
}).strict();
|
|
2323
|
+
var CreateServerCheckoutParamsSchema = createServerCheckoutParamsSchema;
|
|
2324
|
+
var CanonicalCheckoutQuerySchema = canonicalCheckoutQuerySchema;
|
|
2325
|
+
|
|
2326
|
+
// ../../internal/contracts/src/ecommerce/index.ts
|
|
2327
|
+
var transactionStatusSchema = z7.enum([
|
|
2328
|
+
"pending",
|
|
2329
|
+
"paid",
|
|
2330
|
+
"success",
|
|
2331
|
+
"failed",
|
|
2332
|
+
"error",
|
|
2333
|
+
"canceled",
|
|
2334
|
+
"refunded"
|
|
2335
|
+
]);
|
|
2336
|
+
var transactionKindSchema = z7.enum([
|
|
2337
|
+
"authorization",
|
|
2338
|
+
"sale",
|
|
2339
|
+
"capture",
|
|
2340
|
+
"void",
|
|
2341
|
+
"refund"
|
|
2342
|
+
]);
|
|
1253
2343
|
var RETURN_REASON_CODES = [
|
|
1254
2344
|
"change_of_mind",
|
|
1255
2345
|
"defective",
|
|
1256
2346
|
"wrong_delivery",
|
|
1257
2347
|
"damaged",
|
|
2348
|
+
"size_too_large",
|
|
2349
|
+
"size_too_small",
|
|
2350
|
+
"color",
|
|
2351
|
+
"style",
|
|
2352
|
+
"not_as_described",
|
|
2353
|
+
"wrong_item",
|
|
2354
|
+
"unknown",
|
|
1258
2355
|
"other"
|
|
1259
2356
|
];
|
|
1260
|
-
var returnReasonSchema =
|
|
2357
|
+
var returnReasonSchema = z7.enum(RETURN_REASON_CODES);
|
|
1261
2358
|
var RETURN_REJECTION_REASON_CODES = [
|
|
1262
2359
|
"window_expired",
|
|
1263
2360
|
"used_or_damaged",
|
|
1264
2361
|
"non_returnable",
|
|
1265
2362
|
"other"
|
|
1266
2363
|
];
|
|
1267
|
-
var returnRejectionReasonCodeSchema =
|
|
2364
|
+
var returnRejectionReasonCodeSchema = z7.enum(
|
|
1268
2365
|
RETURN_REJECTION_REASON_CODES
|
|
1269
2366
|
);
|
|
1270
|
-
var
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
2367
|
+
var RETURN_CANCELLATION_REASON_CODES = [
|
|
2368
|
+
"items_not_received",
|
|
2369
|
+
"customer_withdrew",
|
|
2370
|
+
"merchant_decision",
|
|
2371
|
+
"other"
|
|
2372
|
+
];
|
|
2373
|
+
var returnCancellationReasonCodeSchema = z7.enum(
|
|
2374
|
+
RETURN_CANCELLATION_REASON_CODES
|
|
2375
|
+
);
|
|
2376
|
+
var restockActionSchema = z7.enum(["return_to_stock", "discard"]);
|
|
2377
|
+
var returnWithRefundItemSchema = z7.object({
|
|
2378
|
+
orderItem: z7.union([z7.string().min(1), z7.number()]).transform(String),
|
|
2379
|
+
quantity: z7.number().int().positive("quantity must be a positive integer"),
|
|
1274
2380
|
restockAction: restockActionSchema.default("return_to_stock"),
|
|
1275
|
-
restockingFee:
|
|
2381
|
+
restockingFee: z7.number().min(0, "restockingFee must be non-negative").optional().describe("Restocking fee charged for this line (ADR 0005 \xA7Gap 1)")
|
|
1276
2382
|
}).strict();
|
|
1277
|
-
var returnWithRefundSchema =
|
|
1278
|
-
orderNumber:
|
|
2383
|
+
var returnWithRefundSchema = z7.object({
|
|
2384
|
+
orderNumber: z7.string().min(1, "orderNumber is required").describe("Order number (required)"),
|
|
1279
2385
|
reason: returnReasonSchema.optional().describe("Return reason (optional)"),
|
|
1280
|
-
reasonDetail:
|
|
1281
|
-
returnItems:
|
|
1282
|
-
refundAmount:
|
|
1283
|
-
returnShippingFee:
|
|
2386
|
+
reasonDetail: z7.string().optional().describe("Detailed reason text (optional)"),
|
|
2387
|
+
returnItems: z7.array(returnWithRefundItemSchema).min(1, "At least one return item is required").max(100, "Too many return items").describe("Array of products to return (required)"),
|
|
2388
|
+
refundAmount: z7.number().min(0, "refundAmount must be non-negative").describe("Refund amount (required, min 0)"),
|
|
2389
|
+
returnShippingFee: z7.number().min(0, "returnShippingFee must be non-negative").optional().describe(
|
|
1284
2390
|
"Return shipping fee charged to the customer (ADR 0005 \xA7Gap 1)"
|
|
1285
2391
|
),
|
|
1286
|
-
initialShippingRefundAmount:
|
|
1287
|
-
initialShippingRefundOverrideNote:
|
|
2392
|
+
initialShippingRefundAmount: z7.number().min(0, "initialShippingRefundAmount must be non-negative").optional().describe("Initial order shipping amount refunded to the customer"),
|
|
2393
|
+
initialShippingRefundOverrideNote: z7.string().min(1).optional().describe(
|
|
1288
2394
|
"Operator audit note required when overriding policy suggestion"
|
|
1289
2395
|
),
|
|
1290
|
-
pgPaymentId:
|
|
1291
|
-
paymentKey:
|
|
1292
|
-
refundReceiptUrl:
|
|
2396
|
+
pgPaymentId: z7.string().min(1, "pgPaymentId is required").describe("PG payment ID for refund (required)"),
|
|
2397
|
+
paymentKey: z7.string().min(1).optional().describe("Provider payment key for verified refund"),
|
|
2398
|
+
refundReceiptUrl: z7.string().optional().describe("Refund receipt URL (optional)")
|
|
1293
2399
|
}).strict();
|
|
1294
|
-
var createReturnSchema =
|
|
1295
|
-
orderNumber:
|
|
2400
|
+
var createReturnSchema = z7.object({
|
|
2401
|
+
orderNumber: z7.string().min(1, "orderNumber is required").describe("Order number (required)"),
|
|
1296
2402
|
reason: returnReasonSchema.optional().describe("Return reason (optional)"),
|
|
1297
|
-
reasonDetail:
|
|
1298
|
-
returnItems:
|
|
1299
|
-
refundAmount:
|
|
2403
|
+
reasonDetail: z7.string().optional().describe("Detailed reason text (optional)"),
|
|
2404
|
+
returnItems: z7.array(returnWithRefundItemSchema).min(1, "At least one return item is required").max(100, "Too many return items").describe("Array of products to return (required)"),
|
|
2405
|
+
refundAmount: z7.number().min(0, "refundAmount must be non-negative").describe(
|
|
1300
2406
|
"Line refund amount before initial shipping refund (required, min 0)"
|
|
1301
2407
|
),
|
|
1302
|
-
returnShippingFee:
|
|
1303
|
-
initialShippingRefundAmount:
|
|
1304
|
-
initialShippingRefundOverrideNote:
|
|
2408
|
+
returnShippingFee: z7.number().min(0, "returnShippingFee must be non-negative").optional().describe("Return shipping fee charged to the customer"),
|
|
2409
|
+
initialShippingRefundAmount: z7.number().min(0, "initialShippingRefundAmount must be non-negative").optional().describe("Initial order shipping amount refunded to the customer"),
|
|
2410
|
+
initialShippingRefundOverrideNote: z7.string().min(1).optional().describe(
|
|
1305
2411
|
"Operator audit note required when overriding policy suggestion"
|
|
1306
2412
|
)
|
|
1307
2413
|
}).strict();
|
|
2414
|
+
var updateReturnSchema = z7.object({
|
|
2415
|
+
returnId: z7.union([z7.string(), z7.number()]).transform(String),
|
|
2416
|
+
// Only non-financial transitions are accepted here. `completed` is included
|
|
2417
|
+
// so the server can return the canonical `server_derived` error instead of
|
|
2418
|
+
// a generic validation failure.
|
|
2419
|
+
status: z7.enum([
|
|
2420
|
+
"processing",
|
|
2421
|
+
"approved",
|
|
2422
|
+
"rejected",
|
|
2423
|
+
"canceled",
|
|
2424
|
+
"completed"
|
|
2425
|
+
]),
|
|
2426
|
+
reasonCode: returnRejectionReasonCodeSchema.optional(),
|
|
2427
|
+
cancellationReasonCode: returnCancellationReasonCodeSchema.optional(),
|
|
2428
|
+
cancellationReasonDetail: z7.string().trim().min(1).max(2e3).optional()
|
|
2429
|
+
}).strict();
|
|
1308
2430
|
var CANCEL_REASON_CODES = [
|
|
1309
2431
|
"customer",
|
|
1310
2432
|
"inventory",
|
|
@@ -1313,242 +2435,159 @@ var CANCEL_REASON_CODES = [
|
|
|
1313
2435
|
"staff",
|
|
1314
2436
|
"other"
|
|
1315
2437
|
];
|
|
1316
|
-
var cancelReasonCodeSchema =
|
|
2438
|
+
var cancelReasonCodeSchema = z7.enum(CANCEL_REASON_CODES);
|
|
1317
2439
|
var FORCE_RESOLUTION_REASON_CODES = [
|
|
1318
2440
|
"staff_error",
|
|
1319
2441
|
"wrong_fulfillment",
|
|
1320
2442
|
"other"
|
|
1321
2443
|
];
|
|
1322
|
-
var forceResolutionReasonCodeSchema =
|
|
2444
|
+
var forceResolutionReasonCodeSchema = z7.enum(
|
|
1323
2445
|
FORCE_RESOLUTION_REASON_CODES
|
|
1324
2446
|
);
|
|
1325
|
-
var idempotencyKeySchema =
|
|
2447
|
+
var idempotencyKeySchema = z7.string().trim().min(1, "idempotencyKey is required").max(255, "idempotencyKey must be 255 characters or fewer").regex(
|
|
1326
2448
|
/^[\x21-\x7E]+$/,
|
|
1327
2449
|
"idempotencyKey must contain only printable header-safe characters"
|
|
1328
2450
|
);
|
|
1329
|
-
var cancelOrderSchema =
|
|
1330
|
-
orderNumber:
|
|
2451
|
+
var cancelOrderSchema = z7.object({
|
|
2452
|
+
orderNumber: z7.string().min(1, "orderNumber is required").describe("Order number to cancel"),
|
|
1331
2453
|
reasonCode: cancelReasonCodeSchema.default("other").describe("Operator-selected cancel reason code"),
|
|
1332
|
-
reasonDetail:
|
|
2454
|
+
reasonDetail: z7.string().trim().max(2e3, "reasonDetail must be 2000 characters or fewer").optional().describe("Internal cancellation detail stored on the order")
|
|
1333
2455
|
}).strict();
|
|
1334
2456
|
var cancelOrderResponseBaseSchema = {
|
|
1335
|
-
orderId:
|
|
2457
|
+
orderId: z7.string().min(1)
|
|
1336
2458
|
};
|
|
1337
2459
|
var unpaidLocalCancelCommittedResponseFields = {
|
|
1338
|
-
refundedAmount:
|
|
1339
|
-
providerRefunded:
|
|
2460
|
+
refundedAmount: z7.literal(0),
|
|
2461
|
+
providerRefunded: z7.literal(false)
|
|
1340
2462
|
};
|
|
1341
2463
|
var paidLocalCancelCommittedResponseFields = {
|
|
1342
|
-
transactionId:
|
|
1343
|
-
refundedAmount:
|
|
1344
|
-
providerRefunded:
|
|
1345
|
-
refundPending:
|
|
1346
|
-
};
|
|
1347
|
-
var legacyProviderRefundResponseFields = {
|
|
1348
|
-
transactionId: z3.string().min(1),
|
|
1349
|
-
refundedAmount: z3.number().int().positive(),
|
|
1350
|
-
refundSeq: z3.number().int().positive(),
|
|
1351
|
-
providerRefunded: z3.literal(true)
|
|
2464
|
+
transactionId: z7.string().min(1),
|
|
2465
|
+
refundedAmount: z7.literal(0),
|
|
2466
|
+
providerRefunded: z7.literal(false),
|
|
2467
|
+
refundPending: z7.literal(true)
|
|
1352
2468
|
};
|
|
1353
2469
|
var alreadyCanceledResponseFields = {
|
|
1354
|
-
refundedAmount:
|
|
1355
|
-
providerRefunded:
|
|
2470
|
+
refundedAmount: z7.number().int().nonnegative(),
|
|
2471
|
+
providerRefunded: z7.literal(false)
|
|
1356
2472
|
};
|
|
1357
2473
|
var alreadyCanceledRefundPendingResponseFields = {
|
|
1358
|
-
transactionId:
|
|
1359
|
-
refundedAmount:
|
|
1360
|
-
providerRefunded:
|
|
1361
|
-
refundPending:
|
|
2474
|
+
transactionId: z7.string().min(1),
|
|
2475
|
+
refundedAmount: z7.number().int().nonnegative(),
|
|
2476
|
+
providerRefunded: z7.literal(false),
|
|
2477
|
+
refundPending: z7.literal(true)
|
|
1362
2478
|
};
|
|
1363
|
-
var
|
|
1364
|
-
|
|
1365
|
-
"preparing",
|
|
1366
|
-
"shipped",
|
|
1367
|
-
"delivered",
|
|
1368
|
-
"confirmed",
|
|
1369
|
-
"return_requested",
|
|
1370
|
-
"return_processing",
|
|
1371
|
-
"returned",
|
|
1372
|
-
"refunded"
|
|
1373
|
-
]);
|
|
1374
|
-
var cancelOrderResponseSchema = z3.union([
|
|
1375
|
-
z3.object({
|
|
2479
|
+
var cancelOrderResponseSchema = z7.union([
|
|
2480
|
+
z7.object({
|
|
1376
2481
|
...cancelOrderResponseBaseSchema,
|
|
1377
2482
|
...paidLocalCancelCommittedResponseFields,
|
|
1378
|
-
status:
|
|
1379
|
-
cancelCommitted:
|
|
2483
|
+
status: z7.literal("canceled"),
|
|
2484
|
+
cancelCommitted: z7.literal(true)
|
|
1380
2485
|
}).strict(),
|
|
1381
|
-
|
|
2486
|
+
z7.object({
|
|
1382
2487
|
...cancelOrderResponseBaseSchema,
|
|
1383
2488
|
...unpaidLocalCancelCommittedResponseFields,
|
|
1384
|
-
status:
|
|
1385
|
-
cancelCommitted:
|
|
2489
|
+
status: z7.literal("canceled"),
|
|
2490
|
+
cancelCommitted: z7.literal(true)
|
|
1386
2491
|
}).strict(),
|
|
1387
|
-
|
|
2492
|
+
z7.object({
|
|
1388
2493
|
...cancelOrderResponseBaseSchema,
|
|
1389
2494
|
...alreadyCanceledResponseFields,
|
|
1390
|
-
status:
|
|
1391
|
-
cancelCommitted:
|
|
1392
|
-
alreadyCanceled:
|
|
2495
|
+
status: z7.literal("canceled"),
|
|
2496
|
+
cancelCommitted: z7.literal(false),
|
|
2497
|
+
alreadyCanceled: z7.literal(true)
|
|
1393
2498
|
}).strict(),
|
|
1394
|
-
|
|
2499
|
+
z7.object({
|
|
1395
2500
|
...cancelOrderResponseBaseSchema,
|
|
1396
2501
|
...alreadyCanceledRefundPendingResponseFields,
|
|
1397
|
-
status:
|
|
1398
|
-
cancelCommitted:
|
|
1399
|
-
alreadyCanceled:
|
|
1400
|
-
}).strict(),
|
|
1401
|
-
z3.object({
|
|
1402
|
-
...cancelOrderResponseBaseSchema,
|
|
1403
|
-
...legacyProviderRefundResponseFields,
|
|
1404
|
-
status: cancelOrderReconciliationStatusSchema,
|
|
1405
|
-
cancelCommitted: z3.literal(false),
|
|
1406
|
-
reconciliationRequired: z3.literal(true)
|
|
2502
|
+
status: z7.literal("canceled"),
|
|
2503
|
+
cancelCommitted: z7.literal(false),
|
|
2504
|
+
alreadyCanceled: z7.literal(true)
|
|
1407
2505
|
}).strict()
|
|
1408
2506
|
]);
|
|
1409
|
-
var resolveCancelRefundOutcomeSchema =
|
|
1410
|
-
var resolveCancelRefundSchema =
|
|
1411
|
-
orderNumber:
|
|
2507
|
+
var resolveCancelRefundOutcomeSchema = z7.enum(["succeeded", "failed"]);
|
|
2508
|
+
var resolveCancelRefundSchema = z7.object({
|
|
2509
|
+
orderNumber: z7.string().min(1, "orderNumber is required").describe("Order number whose pending cancel refund is being resolved"),
|
|
1412
2510
|
idempotencyKey: idempotencyKeySchema.describe(
|
|
1413
2511
|
"Stable key for this PG refund result report"
|
|
1414
2512
|
),
|
|
1415
2513
|
outcome: resolveCancelRefundOutcomeSchema.describe(
|
|
1416
2514
|
"PG refund result reported by the storefront or BFF"
|
|
1417
2515
|
),
|
|
1418
|
-
refundedAmount:
|
|
1419
|
-
pgProvider:
|
|
2516
|
+
refundedAmount: z7.number().int("refundedAmount must be an integer minor-unit amount").nonnegative("refundedAmount must be nonnegative"),
|
|
2517
|
+
pgProvider: z7.string().trim().min(1, "pgProvider is required").regex(
|
|
1420
2518
|
/^[a-z0-9][a-z0-9_-]*$/,
|
|
1421
2519
|
"pgProvider must be a lowercase provider slug"
|
|
1422
2520
|
),
|
|
1423
|
-
pgRefundId:
|
|
2521
|
+
pgRefundId: z7.string().trim().min(1).optional()
|
|
1424
2522
|
}).strict().superRefine((value, ctx) => {
|
|
1425
2523
|
if (value.outcome === "succeeded" && value.refundedAmount <= 0) {
|
|
1426
2524
|
ctx.addIssue({
|
|
1427
|
-
code:
|
|
2525
|
+
code: z7.ZodIssueCode.custom,
|
|
1428
2526
|
path: ["refundedAmount"],
|
|
1429
2527
|
message: "refundedAmount must be positive when outcome is succeeded"
|
|
1430
2528
|
});
|
|
1431
2529
|
}
|
|
1432
2530
|
if (value.outcome === "succeeded" && !value.pgRefundId) {
|
|
1433
2531
|
ctx.addIssue({
|
|
1434
|
-
code:
|
|
2532
|
+
code: z7.ZodIssueCode.custom,
|
|
1435
2533
|
path: ["pgRefundId"],
|
|
1436
2534
|
message: "pgRefundId is required when outcome is succeeded"
|
|
1437
2535
|
});
|
|
1438
2536
|
}
|
|
1439
2537
|
if (value.outcome === "failed" && value.refundedAmount !== 0) {
|
|
1440
2538
|
ctx.addIssue({
|
|
1441
|
-
code:
|
|
2539
|
+
code: z7.ZodIssueCode.custom,
|
|
1442
2540
|
path: ["refundedAmount"],
|
|
1443
2541
|
message: "refundedAmount must be 0 when outcome is failed"
|
|
1444
2542
|
});
|
|
1445
2543
|
}
|
|
1446
2544
|
});
|
|
1447
|
-
var resolveCancelRefundResponseSchema =
|
|
1448
|
-
|
|
1449
|
-
orderId:
|
|
1450
|
-
transactionId:
|
|
1451
|
-
refundTransactionId:
|
|
1452
|
-
refundedAmount:
|
|
1453
|
-
refundStatus:
|
|
1454
|
-
transactionStatus:
|
|
2545
|
+
var resolveCancelRefundResponseSchema = z7.union([
|
|
2546
|
+
z7.object({
|
|
2547
|
+
orderId: z7.string().min(1),
|
|
2548
|
+
transactionId: z7.string().min(1),
|
|
2549
|
+
refundTransactionId: z7.string().min(1),
|
|
2550
|
+
refundedAmount: z7.number().int().positive(),
|
|
2551
|
+
refundStatus: z7.literal("succeeded"),
|
|
2552
|
+
transactionStatus: z7.enum(["paid", "refunded"])
|
|
1455
2553
|
}).strict(),
|
|
1456
|
-
|
|
1457
|
-
orderId:
|
|
1458
|
-
transactionId:
|
|
1459
|
-
refundTransactionId:
|
|
1460
|
-
refundedAmount:
|
|
1461
|
-
refundStatus:
|
|
1462
|
-
transactionStatus:
|
|
2554
|
+
z7.object({
|
|
2555
|
+
orderId: z7.string().min(1),
|
|
2556
|
+
transactionId: z7.string().min(1),
|
|
2557
|
+
refundTransactionId: z7.string().min(1),
|
|
2558
|
+
refundedAmount: z7.literal(0),
|
|
2559
|
+
refundStatus: z7.literal("failed"),
|
|
2560
|
+
transactionStatus: z7.literal("paid")
|
|
1463
2561
|
}).strict()
|
|
1464
2562
|
]);
|
|
1465
2563
|
|
|
1466
2564
|
// src/commands/order.ts
|
|
1467
|
-
import { z as
|
|
1468
|
-
var idSchema =
|
|
1469
|
-
var
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
phone: z4.string().optional()
|
|
1473
|
-
}).strict();
|
|
1474
|
-
var orderStatusSchema2 = z4.enum(["confirmed"]);
|
|
1475
|
-
var fulfillmentStatusSchema = z4.enum(["shipped", "delivered", "failed"]);
|
|
1476
|
-
var updateFulfillmentSchema = z4.object({
|
|
2565
|
+
import { z as z8 } from "zod";
|
|
2566
|
+
var idSchema = z8.union([z8.string().min(1), z8.number()]).transform(String);
|
|
2567
|
+
var orderStatusSchema = z8.enum(["confirmed"]);
|
|
2568
|
+
var fulfillmentStatusSchema = z8.enum(["shipped", "delivered", "failed"]);
|
|
2569
|
+
var updateFulfillmentSchema = z8.object({
|
|
1477
2570
|
fulfillmentId: idSchema,
|
|
1478
2571
|
status: fulfillmentStatusSchema.optional(),
|
|
1479
|
-
carrier:
|
|
1480
|
-
trackingNumber:
|
|
2572
|
+
carrier: z8.string().min(1).optional(),
|
|
2573
|
+
trackingNumber: z8.string().min(1).optional()
|
|
1481
2574
|
}).refine(
|
|
1482
2575
|
(value) => value.status !== void 0 || value.carrier !== void 0 || value.trackingNumber !== void 0,
|
|
1483
2576
|
{
|
|
1484
2577
|
message: "status, carrier, or trackingNumber is required"
|
|
1485
2578
|
}
|
|
1486
2579
|
);
|
|
1487
|
-
var fulfillmentItemsSchema =
|
|
1488
|
-
|
|
2580
|
+
var fulfillmentItemsSchema = z8.array(
|
|
2581
|
+
z8.object({
|
|
1489
2582
|
orderItem: idSchema,
|
|
1490
|
-
quantity:
|
|
2583
|
+
quantity: z8.number().int().positive("quantity must be a positive integer")
|
|
1491
2584
|
}).strict()
|
|
1492
2585
|
).min(1, "At least one fulfillment item is required").max(100, "Maximum 100 items per fulfillment");
|
|
1493
2586
|
function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
1494
2587
|
const order = program2.command("order").description("Order management");
|
|
1495
|
-
order.command("create").description("Create a new order").option("--payment-id <id>", "Payment ID").requiredOption("--order-number <num>", "Order number").requiredOption("--email <email>", "Customer email").option("--customer <id>", "Customer ID").option("--name <name>", "Customer name").option("--phone <phone>", "Customer phone").requiredOption("--shipping-address <json>", "Shipping address (JSON)").requiredOption("--products <json>", "Order products array (JSON)").requiredOption("--total-amount <n>", "Total amount", parseFloat).option("--shipping-amount <n>", "Shipping amount", parseFloat).option("--discount-code <code>", "Discount code").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
1496
|
-
try {
|
|
1497
|
-
const data = parseWithSchema(
|
|
1498
|
-
{
|
|
1499
|
-
pgPaymentId: opts.paymentId,
|
|
1500
|
-
orderNumber: opts.orderNumber,
|
|
1501
|
-
customerSnapshot: {
|
|
1502
|
-
email: opts.email,
|
|
1503
|
-
name: opts.name,
|
|
1504
|
-
phone: opts.phone
|
|
1505
|
-
},
|
|
1506
|
-
customer: opts.customer,
|
|
1507
|
-
shippingAddress: parseJson(
|
|
1508
|
-
opts.shippingAddress,
|
|
1509
|
-
"shipping-address"
|
|
1510
|
-
),
|
|
1511
|
-
orderItems: parseJsonArray(opts.products, "products"),
|
|
1512
|
-
totalAmount: opts.totalAmount,
|
|
1513
|
-
shippingAmount: opts.shippingAmount,
|
|
1514
|
-
discountCode: opts.discountCode
|
|
1515
|
-
},
|
|
1516
|
-
"order",
|
|
1517
|
-
createOrderSchema
|
|
1518
|
-
);
|
|
1519
|
-
if (opts.dryRun) {
|
|
1520
|
-
printResult(
|
|
1521
|
-
{ dryRun: true, valid: true, action: "order create", data },
|
|
1522
|
-
getFormat2()
|
|
1523
|
-
);
|
|
1524
|
-
return;
|
|
1525
|
-
}
|
|
1526
|
-
const client = getClient2();
|
|
1527
|
-
const result = await client.commerce.orders.create(data);
|
|
1528
|
-
printResult(result, getFormat2());
|
|
1529
|
-
} catch (e) {
|
|
1530
|
-
exitWithError(e);
|
|
1531
|
-
}
|
|
1532
|
-
});
|
|
1533
|
-
order.command("get <orderNumber>").description("Get an order by order number").action(async (orderNumber) => {
|
|
1534
|
-
try {
|
|
1535
|
-
const client = getClient2();
|
|
1536
|
-
const {
|
|
1537
|
-
docs: [order2]
|
|
1538
|
-
} = await client.collections.from("orders").find({
|
|
1539
|
-
where: { orderNumber: { equals: orderNumber } },
|
|
1540
|
-
limit: 1,
|
|
1541
|
-
depth: 1
|
|
1542
|
-
});
|
|
1543
|
-
if (!order2) throw new Error("Order not found");
|
|
1544
|
-
printResult(order2, getFormat2());
|
|
1545
|
-
} catch (e) {
|
|
1546
|
-
exitWithError(e);
|
|
1547
|
-
}
|
|
1548
|
-
});
|
|
1549
2588
|
order.command("update <orderNumber>").description("Confirm a delivered order purchase").requiredOption("--status <status>", "New status (confirmed only)").option("--dry-run", "Validate inputs without executing").action(async (orderNumber, opts) => {
|
|
1550
2589
|
try {
|
|
1551
|
-
const status = parseWithSchema(opts.status, "status",
|
|
2590
|
+
const status = parseWithSchema(opts.status, "status", orderStatusSchema);
|
|
1552
2591
|
const data = { orderNumber, status };
|
|
1553
2592
|
if (opts.dryRun) {
|
|
1554
2593
|
printResult(
|
|
@@ -1592,36 +2631,6 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
|
1592
2631
|
exitWithError(e);
|
|
1593
2632
|
}
|
|
1594
2633
|
});
|
|
1595
|
-
order.command("checkout").description("Convert a cart to an order").requiredOption("--cart-id <id>", "Cart ID").option("--payment-id <id>", "Payment ID (optional for free orders)").requiredOption("--order-number <num>", "Order number").requiredOption("--customer <json>", "Customer snapshot (JSON)").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
1596
|
-
try {
|
|
1597
|
-
const customerSnapshot = parseWithSchema(
|
|
1598
|
-
parseJson(opts.customer, "customer"),
|
|
1599
|
-
"customer",
|
|
1600
|
-
customerSnapshotSchema
|
|
1601
|
-
);
|
|
1602
|
-
const data = {
|
|
1603
|
-
cartId: opts.cartId,
|
|
1604
|
-
pgPaymentId: opts.paymentId,
|
|
1605
|
-
orderNumber: opts.orderNumber,
|
|
1606
|
-
customerSnapshot
|
|
1607
|
-
};
|
|
1608
|
-
if (opts.dryRun) {
|
|
1609
|
-
printResult(
|
|
1610
|
-
{ dryRun: true, valid: true, action: "order checkout", data },
|
|
1611
|
-
getFormat2()
|
|
1612
|
-
);
|
|
1613
|
-
return;
|
|
1614
|
-
}
|
|
1615
|
-
const client = getClient2();
|
|
1616
|
-
const result = await client.commerce.orders.checkout({
|
|
1617
|
-
...data,
|
|
1618
|
-
customerSnapshot
|
|
1619
|
-
});
|
|
1620
|
-
printResult(result, getFormat2());
|
|
1621
|
-
} catch (e) {
|
|
1622
|
-
exitWithError(e);
|
|
1623
|
-
}
|
|
1624
|
-
});
|
|
1625
2634
|
order.command("prepare <orderNumber>").description("Move paid order fulfillment work to preparation").option("--dry-run", "Validate inputs without executing").action(async (orderNumber, opts) => {
|
|
1626
2635
|
try {
|
|
1627
2636
|
const data = { orderNumber };
|
|
@@ -1705,8 +2714,8 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
|
1705
2714
|
}
|
|
1706
2715
|
|
|
1707
2716
|
// src/commands/return.ts
|
|
1708
|
-
import { z as
|
|
1709
|
-
var returnStatusSchema =
|
|
2717
|
+
import { z as z9 } from "zod";
|
|
2718
|
+
var returnStatusSchema = z9.enum([
|
|
1710
2719
|
"processing",
|
|
1711
2720
|
"approved",
|
|
1712
2721
|
"rejected",
|
|
@@ -1835,146 +2844,227 @@ function registerReturnCommands(program2, getClient2, getFormat2) {
|
|
|
1835
2844
|
});
|
|
1836
2845
|
}
|
|
1837
2846
|
|
|
2847
|
+
// src/lib/sensitive-json-input.ts
|
|
2848
|
+
import { createReadStream } from "fs";
|
|
2849
|
+
import { stdin as processStdin } from "process";
|
|
2850
|
+
var SENSITIVE_JSON_MAX_BYTES = 1024 * 1024;
|
|
2851
|
+
function invalidInput(message) {
|
|
2852
|
+
return {
|
|
2853
|
+
type: "validation",
|
|
2854
|
+
code: "invalid_argument",
|
|
2855
|
+
field: "data",
|
|
2856
|
+
message,
|
|
2857
|
+
detail: { message, field: "data" }
|
|
2858
|
+
};
|
|
2859
|
+
}
|
|
2860
|
+
function isInvalidInput(error) {
|
|
2861
|
+
if (!error || typeof error !== "object") return false;
|
|
2862
|
+
const value = error;
|
|
2863
|
+
return value.type === "validation" && value.code === "invalid_argument";
|
|
2864
|
+
}
|
|
2865
|
+
async function readBoundedUtf8(source) {
|
|
2866
|
+
const chunks = [];
|
|
2867
|
+
let totalBytes = 0;
|
|
2868
|
+
for await (const chunk of source) {
|
|
2869
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
2870
|
+
totalBytes += buffer.byteLength;
|
|
2871
|
+
if (totalBytes > SENSITIVE_JSON_MAX_BYTES) {
|
|
2872
|
+
throw invalidInput(
|
|
2873
|
+
`Sensitive commerce data must be ${SENSITIVE_JSON_MAX_BYTES} bytes or fewer.`
|
|
2874
|
+
);
|
|
2875
|
+
}
|
|
2876
|
+
chunks.push(buffer);
|
|
2877
|
+
}
|
|
2878
|
+
return Buffer.concat(chunks, totalBytes).toString("utf8");
|
|
2879
|
+
}
|
|
2880
|
+
async function readSensitiveJsonObject(opts, sources = {}) {
|
|
2881
|
+
const sourceCount = [opts.dataStdin, opts.dataFile].filter(Boolean).length;
|
|
2882
|
+
if (sourceCount !== 1) {
|
|
2883
|
+
throw invalidInput(
|
|
2884
|
+
"Exactly one of --data-stdin or --data-file is required for sensitive commerce data."
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
let raw;
|
|
2888
|
+
const input = sources.stdin ?? processStdin;
|
|
2889
|
+
try {
|
|
2890
|
+
if (opts.dataStdin) {
|
|
2891
|
+
if (input.isTTY === true) {
|
|
2892
|
+
throw invalidInput(
|
|
2893
|
+
"Sensitive commerce data cannot be read from an interactive terminal. Pipe JSON to --data-stdin or use --data-file."
|
|
2894
|
+
);
|
|
2895
|
+
}
|
|
2896
|
+
raw = await readBoundedUtf8(input);
|
|
2897
|
+
} else {
|
|
2898
|
+
const file = (sources.openFile ?? createReadStream)(opts.dataFile);
|
|
2899
|
+
try {
|
|
2900
|
+
raw = await readBoundedUtf8(file);
|
|
2901
|
+
} finally {
|
|
2902
|
+
file.destroy?.();
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
} catch (error) {
|
|
2906
|
+
if (isInvalidInput(error)) throw error;
|
|
2907
|
+
throw invalidInput("Sensitive commerce data could not be read.");
|
|
2908
|
+
}
|
|
2909
|
+
let parsed;
|
|
2910
|
+
try {
|
|
2911
|
+
parsed = JSON.parse(raw);
|
|
2912
|
+
} catch {
|
|
2913
|
+
throw invalidInput("Sensitive commerce data must be valid JSON.");
|
|
2914
|
+
}
|
|
2915
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2916
|
+
throw invalidInput("Sensitive commerce data must be a JSON object.");
|
|
2917
|
+
}
|
|
2918
|
+
return parsed;
|
|
2919
|
+
}
|
|
2920
|
+
function sensitiveDryRunResult(action) {
|
|
2921
|
+
return { dryRun: true, valid: true, action };
|
|
2922
|
+
}
|
|
2923
|
+
|
|
1838
2924
|
// src/commands/cart.ts
|
|
1839
2925
|
function registerCartCommands(program2, getClient2, getFormat2) {
|
|
1840
2926
|
const cart = program2.command("cart").description("Cart management");
|
|
1841
|
-
cart.command("create").description("Create a cart and print its cartToken
|
|
2927
|
+
cart.command("create").description("Create a cart and print its cartToken capability").option("--data-stdin", "Read market and attributes JSON from stdin").option("--data-file <path>", "Read market and attributes JSON from file").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
1842
2928
|
try {
|
|
2929
|
+
const input = opts.dataStdin || opts.dataFile ? await readSensitiveJsonObject(opts) : {};
|
|
2930
|
+
const data = parseWithSchema(
|
|
2931
|
+
input,
|
|
2932
|
+
"cart create",
|
|
2933
|
+
createCartParamsSchema
|
|
2934
|
+
);
|
|
1843
2935
|
if (opts.dryRun) {
|
|
1844
|
-
printResult(
|
|
1845
|
-
{ dryRun: true, valid: true, action: "cart create", data: {} },
|
|
1846
|
-
getFormat2()
|
|
1847
|
-
);
|
|
2936
|
+
printResult(sensitiveDryRunResult("cart create"), getFormat2());
|
|
1848
2937
|
return;
|
|
1849
2938
|
}
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
} catch (e) {
|
|
1854
|
-
exitWithError(e);
|
|
2939
|
+
printResult(await getClient2().commerce.carts.create(data), getFormat2());
|
|
2940
|
+
} catch (error) {
|
|
2941
|
+
exitWithError(error);
|
|
1855
2942
|
}
|
|
1856
2943
|
});
|
|
1857
|
-
cart.command("
|
|
1858
|
-
"--quantity <n>",
|
|
1859
|
-
"Quantity",
|
|
1860
|
-
(v) => parseInt(v, 10)
|
|
1861
|
-
).option("--dry-run", "Validate inputs without executing").action(async (cartToken, opts) => {
|
|
2944
|
+
cart.command("retrieve").description("Retrieve a cart by its capability token").option("--data-stdin", "Read the Cart capability JSON from stdin").option("--data-file <path>", "Read the Cart capability JSON from file").action(async (opts) => {
|
|
1862
2945
|
try {
|
|
1863
|
-
const data =
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
2946
|
+
const data = parseWithSchema(
|
|
2947
|
+
await readSensitiveJsonObject(opts),
|
|
2948
|
+
"cart retrieve",
|
|
2949
|
+
retrieveCartParamsSchema
|
|
2950
|
+
);
|
|
2951
|
+
printResult(
|
|
2952
|
+
await getClient2().commerce.carts.retrieve(data),
|
|
2953
|
+
getFormat2()
|
|
2954
|
+
);
|
|
2955
|
+
} catch (error) {
|
|
2956
|
+
exitWithError(error);
|
|
2957
|
+
}
|
|
2958
|
+
});
|
|
2959
|
+
cart.command("add").description("Add an item to a cart").option("--data-stdin", "Read capability and item JSON from stdin").option("--data-file <path>", "Read capability and item JSON from file").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
2960
|
+
try {
|
|
2961
|
+
const data = parseWithSchema(
|
|
2962
|
+
await readSensitiveJsonObject(opts),
|
|
2963
|
+
"cart add",
|
|
2964
|
+
addItemParamsSchema
|
|
2965
|
+
);
|
|
1870
2966
|
if (opts.dryRun) {
|
|
1871
|
-
printResult(
|
|
1872
|
-
{ dryRun: true, valid: true, action: "cart add", data },
|
|
1873
|
-
getFormat2()
|
|
1874
|
-
);
|
|
2967
|
+
printResult(sensitiveDryRunResult("cart add"), getFormat2());
|
|
1875
2968
|
return;
|
|
1876
2969
|
}
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
} catch (e) {
|
|
1881
|
-
exitWithError(e);
|
|
2970
|
+
printResult(await getClient2().commerce.carts.addItem(data), getFormat2());
|
|
2971
|
+
} catch (error) {
|
|
2972
|
+
exitWithError(error);
|
|
1882
2973
|
}
|
|
1883
2974
|
});
|
|
1884
|
-
cart.command("update
|
|
1885
|
-
"--quantity <n>",
|
|
1886
|
-
"New quantity",
|
|
1887
|
-
(v) => parseInt(v, 10)
|
|
1888
|
-
).option("--dry-run", "Validate inputs without executing").action(async (cartItemId, opts) => {
|
|
2975
|
+
cart.command("update").description("Update cart item quantity").option("--data-stdin", "Read capability and item JSON from stdin").option("--data-file <path>", "Read capability and item JSON from file").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
1889
2976
|
try {
|
|
1890
|
-
const data =
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
2977
|
+
const data = parseWithSchema(
|
|
2978
|
+
await readSensitiveJsonObject(opts),
|
|
2979
|
+
"cart update",
|
|
2980
|
+
updateItemParamsSchema
|
|
2981
|
+
);
|
|
1895
2982
|
if (opts.dryRun) {
|
|
1896
|
-
printResult(
|
|
1897
|
-
{ dryRun: true, valid: true, action: "cart update", data },
|
|
1898
|
-
getFormat2()
|
|
1899
|
-
);
|
|
2983
|
+
printResult(sensitiveDryRunResult("cart update"), getFormat2());
|
|
1900
2984
|
return;
|
|
1901
2985
|
}
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
2986
|
+
printResult(
|
|
2987
|
+
await getClient2().commerce.carts.updateItem(data),
|
|
2988
|
+
getFormat2()
|
|
2989
|
+
);
|
|
2990
|
+
} catch (error) {
|
|
2991
|
+
exitWithError(error);
|
|
1907
2992
|
}
|
|
1908
2993
|
});
|
|
1909
|
-
cart.command("remove
|
|
2994
|
+
cart.command("remove").description("Remove an item from a cart").option("--data-stdin", "Read capability and item JSON from stdin").option("--data-file <path>", "Read capability and item JSON from file").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
1910
2995
|
try {
|
|
1911
|
-
const data =
|
|
2996
|
+
const data = parseWithSchema(
|
|
2997
|
+
await readSensitiveJsonObject(opts),
|
|
2998
|
+
"cart remove",
|
|
2999
|
+
removeItemParamsSchema
|
|
3000
|
+
);
|
|
1912
3001
|
if (opts.dryRun) {
|
|
1913
|
-
printResult(
|
|
1914
|
-
{ dryRun: true, valid: true, action: "cart remove", data },
|
|
1915
|
-
getFormat2()
|
|
1916
|
-
);
|
|
3002
|
+
printResult(sensitiveDryRunResult("cart remove"), getFormat2());
|
|
1917
3003
|
return;
|
|
1918
3004
|
}
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
3005
|
+
printResult(
|
|
3006
|
+
await getClient2().commerce.carts.removeItem(data),
|
|
3007
|
+
getFormat2()
|
|
3008
|
+
);
|
|
3009
|
+
} catch (error) {
|
|
3010
|
+
exitWithError(error);
|
|
1924
3011
|
}
|
|
1925
3012
|
});
|
|
1926
|
-
cart.command("clear
|
|
3013
|
+
cart.command("clear").description("Remove all items from a cart").option("--data-stdin", "Read the Cart capability JSON from stdin").option("--data-file <path>", "Read the Cart capability JSON from file").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
1927
3014
|
try {
|
|
3015
|
+
const data = parseWithSchema(
|
|
3016
|
+
await readSensitiveJsonObject(opts),
|
|
3017
|
+
"cart clear",
|
|
3018
|
+
clearCartParamsSchema
|
|
3019
|
+
);
|
|
1928
3020
|
if (opts.dryRun) {
|
|
1929
|
-
printResult(
|
|
1930
|
-
{ dryRun: true, valid: true, action: "cart clear", data: { cartToken } },
|
|
1931
|
-
getFormat2()
|
|
1932
|
-
);
|
|
3021
|
+
printResult(sensitiveDryRunResult("cart clear"), getFormat2());
|
|
1933
3022
|
return;
|
|
1934
3023
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
} catch (e) {
|
|
1939
|
-
exitWithError(e);
|
|
3024
|
+
printResult(await getClient2().commerce.carts.clear(data), getFormat2());
|
|
3025
|
+
} catch (error) {
|
|
3026
|
+
exitWithError(error);
|
|
1940
3027
|
}
|
|
1941
3028
|
});
|
|
1942
|
-
cart.command("
|
|
3029
|
+
cart.command("discounts").description("Replace all cart discount codes; pass [] to clear").option("--data-stdin", "Read capability and discount JSON from stdin").option("--data-file <path>", "Read capability and discount JSON from file").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
1943
3030
|
try {
|
|
1944
|
-
const data =
|
|
3031
|
+
const data = parseWithSchema(
|
|
3032
|
+
await readSensitiveJsonObject(opts),
|
|
3033
|
+
"cart discounts",
|
|
3034
|
+
updateDiscountCodesParamsSchema
|
|
3035
|
+
);
|
|
1945
3036
|
if (opts.dryRun) {
|
|
1946
|
-
printResult(
|
|
1947
|
-
{ dryRun: true, valid: true, action: "cart apply-discount", data },
|
|
1948
|
-
getFormat2()
|
|
1949
|
-
);
|
|
3037
|
+
printResult(sensitiveDryRunResult("cart discounts"), getFormat2());
|
|
1950
3038
|
return;
|
|
1951
3039
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
3040
|
+
printResult(
|
|
3041
|
+
await getClient2().commerce.carts.updateDiscountCodes(data),
|
|
3042
|
+
getFormat2()
|
|
3043
|
+
);
|
|
3044
|
+
} catch (error) {
|
|
3045
|
+
exitWithError(error);
|
|
1957
3046
|
}
|
|
1958
3047
|
});
|
|
1959
|
-
cart.command("
|
|
3048
|
+
cart.command("attributes").description("Replace all public cart attributes; pass [] to clear").option("--data-stdin", "Read capability and attributes JSON from stdin").option(
|
|
3049
|
+
"--data-file <path>",
|
|
3050
|
+
"Read capability and attributes JSON from file"
|
|
3051
|
+
).option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
1960
3052
|
try {
|
|
3053
|
+
const data = parseWithSchema(
|
|
3054
|
+
await readSensitiveJsonObject(opts),
|
|
3055
|
+
"cart attributes",
|
|
3056
|
+
updateCartAttributesParamsSchema
|
|
3057
|
+
);
|
|
1961
3058
|
if (opts.dryRun) {
|
|
1962
|
-
printResult(
|
|
1963
|
-
{
|
|
1964
|
-
dryRun: true,
|
|
1965
|
-
valid: true,
|
|
1966
|
-
action: "cart remove-discount",
|
|
1967
|
-
data: { cartToken }
|
|
1968
|
-
},
|
|
1969
|
-
getFormat2()
|
|
1970
|
-
);
|
|
3059
|
+
printResult(sensitiveDryRunResult("cart attributes"), getFormat2());
|
|
1971
3060
|
return;
|
|
1972
3061
|
}
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
3062
|
+
printResult(
|
|
3063
|
+
await getClient2().commerce.carts.updateAttributes(data),
|
|
3064
|
+
getFormat2()
|
|
3065
|
+
);
|
|
3066
|
+
} catch (error) {
|
|
3067
|
+
exitWithError(error);
|
|
1978
3068
|
}
|
|
1979
3069
|
});
|
|
1980
3070
|
}
|
|
@@ -1998,124 +3088,196 @@ function registerStockCommands(program2, getClient2, getFormat2) {
|
|
|
1998
3088
|
}
|
|
1999
3089
|
|
|
2000
3090
|
// src/commands/transaction.ts
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
});
|
|
2005
|
-
var confirmPaymentAmountSchema = z6.object({
|
|
2006
|
-
amount: z6.string().regex(/^(0|[1-9]\d*)$/, "amount must be a non-negative integer").transform(Number)
|
|
2007
|
-
});
|
|
2008
|
-
var idempotencyKeyOptionSchema = z6.object({
|
|
2009
|
-
idempotencyKey: idempotencyKeySchema
|
|
2010
|
-
});
|
|
2011
|
-
function parseTransactionAmount(value) {
|
|
2012
|
-
if (value === void 0) return void 0;
|
|
2013
|
-
return parseWithSchema({ amount: value }, "amount", transactionAmountSchema).amount;
|
|
2014
|
-
}
|
|
2015
|
-
function parseConfirmPaymentAmount(value) {
|
|
2016
|
-
return parseWithSchema({ amount: value }, "amount", confirmPaymentAmountSchema).amount;
|
|
2017
|
-
}
|
|
2018
|
-
function parseIdempotencyKey(value) {
|
|
2019
|
-
if (value === void 0) return void 0;
|
|
2020
|
-
return parseWithSchema(
|
|
2021
|
-
{ idempotencyKey: value },
|
|
2022
|
-
"idempotencyKey",
|
|
2023
|
-
idempotencyKeyOptionSchema
|
|
2024
|
-
).idempotencyKey;
|
|
2025
|
-
}
|
|
2026
|
-
function registerTransactionCommands(program2, getClient2, getFormat2) {
|
|
2027
|
-
const tx = program2.command("transaction").description("Transaction management");
|
|
2028
|
-
tx.command("update").description("Update transaction status").requiredOption("--payment-id <id>", "Payment ID").requiredOption(
|
|
2029
|
-
"--status <status>",
|
|
2030
|
-
"New status (pending, paid, failed, canceled, refunded)"
|
|
2031
|
-
).option("--payment-method <method>", "Payment method").option("--receipt-url <url>", "Receipt URL").option("--payment-key <key>", "Provider payment key").option("--amount <n>", "Provider-confirmed amount").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
3091
|
+
function registerCommerceSessionCommands(program2, getClient2, getFormat2) {
|
|
3092
|
+
const checkout = program2.command("checkout").description("Checkout management");
|
|
3093
|
+
checkout.command("create").description("Create a Checkout from a server-authoritative Cart").option("--data-stdin", "Read capability and customer JSON from stdin").option("--data-file <path>", "Read capability and customer JSON from file").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
2032
3094
|
try {
|
|
2033
3095
|
const data = parseWithSchema(
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
3096
|
+
await readSensitiveJsonObject(opts),
|
|
3097
|
+
"checkout",
|
|
3098
|
+
CreateServerCheckoutParamsSchema
|
|
3099
|
+
);
|
|
3100
|
+
if (opts.dryRun) {
|
|
3101
|
+
printResult(sensitiveDryRunResult("checkout create"), getFormat2());
|
|
3102
|
+
return;
|
|
3103
|
+
}
|
|
3104
|
+
printResult(
|
|
3105
|
+
await getClient2().commerce.checkouts.create(data),
|
|
3106
|
+
getFormat2()
|
|
3107
|
+
);
|
|
3108
|
+
} catch (error) {
|
|
3109
|
+
exitWithError(error);
|
|
3110
|
+
}
|
|
3111
|
+
});
|
|
3112
|
+
checkout.command("retrieve <checkoutId>").description("Retrieve a Checkout by ID with server credentials").action(async (checkoutId) => {
|
|
3113
|
+
try {
|
|
3114
|
+
printResult(
|
|
3115
|
+
await getClient2().commerce.checkouts.retrieve({ checkoutId }),
|
|
3116
|
+
getFormat2()
|
|
3117
|
+
);
|
|
3118
|
+
} catch (error) {
|
|
3119
|
+
exitWithError(error);
|
|
3120
|
+
}
|
|
3121
|
+
});
|
|
3122
|
+
checkout.command("query").description("Query lightweight Checkouts with server credentials").option("--params <json>", "Checkout query parameters (JSON)", "{}").action(async (opts) => {
|
|
3123
|
+
try {
|
|
3124
|
+
const data = parseWithSchema(
|
|
3125
|
+
parseJson(opts.params, "params"),
|
|
3126
|
+
"checkout query",
|
|
3127
|
+
CanonicalCheckoutQuerySchema
|
|
3128
|
+
);
|
|
3129
|
+
printResult(
|
|
3130
|
+
await getClient2().commerce.checkouts.query(data),
|
|
3131
|
+
getFormat2()
|
|
3132
|
+
);
|
|
3133
|
+
} catch (error) {
|
|
3134
|
+
exitWithError(error);
|
|
3135
|
+
}
|
|
3136
|
+
});
|
|
3137
|
+
const sessions = program2.command("payment-session").description("PaymentSession management");
|
|
3138
|
+
sessions.command("create").description("Create a canonical provider-configured PaymentSession").option("--data-stdin", "Read canonical create parameters from stdin").option("--data-file <path>", "Read canonical create parameters from file").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
3139
|
+
try {
|
|
3140
|
+
const data = parseWithSchema(
|
|
3141
|
+
await readSensitiveJsonObject(opts),
|
|
3142
|
+
"payment-session",
|
|
3143
|
+
CreatePaymentSessionParamsSchema
|
|
2044
3144
|
);
|
|
2045
3145
|
if (opts.dryRun) {
|
|
2046
3146
|
printResult(
|
|
2047
|
-
|
|
3147
|
+
sensitiveDryRunResult("payment-session create"),
|
|
2048
3148
|
getFormat2()
|
|
2049
3149
|
);
|
|
2050
3150
|
return;
|
|
2051
3151
|
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
3152
|
+
printResult(
|
|
3153
|
+
await getClient2().commerce.paymentSessions.create(data),
|
|
3154
|
+
getFormat2()
|
|
3155
|
+
);
|
|
3156
|
+
} catch (error) {
|
|
3157
|
+
exitWithError(error);
|
|
3158
|
+
}
|
|
3159
|
+
});
|
|
3160
|
+
sessions.command("retrieve <paymentSessionId>").description("Retrieve a PaymentSession").action(async (paymentSessionId) => {
|
|
3161
|
+
try {
|
|
3162
|
+
printResult(
|
|
3163
|
+
await getClient2().commerce.paymentSessions.retrieve({
|
|
3164
|
+
paymentSessionId
|
|
3165
|
+
}),
|
|
3166
|
+
getFormat2()
|
|
3167
|
+
);
|
|
3168
|
+
} catch (error) {
|
|
3169
|
+
exitWithError(error);
|
|
2057
3170
|
}
|
|
2058
3171
|
});
|
|
2059
|
-
|
|
2060
|
-
"--
|
|
2061
|
-
"
|
|
2062
|
-
).
|
|
2063
|
-
"--amount <n>",
|
|
2064
|
-
"Provider-confirmed amount in minor units"
|
|
2065
|
-
).option("--order-number <num>", "Order number").option("--pg-order-id <id>", "Provider order id").option("--currency <code>", "Currency code").option("--payment-method <method>", "Payment method").option("--receipt-url <url>", "Receipt URL").option("--approved-at <ts>", "Provider approval timestamp").option("--provider-status <status>", "Provider status").option("--provider-event-id <id>", "Provider event id (idempotency)").option("--idempotency-key <key>", "Idempotency key header override").option(
|
|
2066
|
-
"--confirmation-source <src>",
|
|
2067
|
-
"provider_webhook | provider_lookup | provider_api_confirm | manual_server"
|
|
2068
|
-
).option("--payment-key <key>", "Provider payment key").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
3172
|
+
sessions.command("cancel").description("Cancel a PaymentSession and release its payment slot").option("--data-stdin", "Read session ID and idempotency key from stdin").option(
|
|
3173
|
+
"--data-file <path>",
|
|
3174
|
+
"Read session ID and idempotency key from file"
|
|
3175
|
+
).option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
2069
3176
|
try {
|
|
2070
3177
|
const data = parseWithSchema(
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
amount: parseConfirmPaymentAmount(opts.amount),
|
|
2075
|
-
...opts.orderNumber ? { orderNumber: opts.orderNumber } : {},
|
|
2076
|
-
...opts.pgOrderId ? { pgOrderId: opts.pgOrderId } : {},
|
|
2077
|
-
...opts.currency ? { currency: opts.currency } : {},
|
|
2078
|
-
...opts.paymentMethod ? { paymentMethod: opts.paymentMethod } : {},
|
|
2079
|
-
...opts.receiptUrl ? { receiptUrl: opts.receiptUrl } : {},
|
|
2080
|
-
...opts.approvedAt ? { approvedAt: opts.approvedAt } : {},
|
|
2081
|
-
...opts.providerStatus ? { providerStatus: opts.providerStatus } : {},
|
|
2082
|
-
...opts.providerEventId ? { providerEventId: opts.providerEventId } : {},
|
|
2083
|
-
...opts.confirmationSource ? { confirmationSource: opts.confirmationSource } : {},
|
|
2084
|
-
...opts.paymentKey ? { paymentKey: opts.paymentKey } : {}
|
|
2085
|
-
},
|
|
2086
|
-
"confirm-payment",
|
|
2087
|
-
confirmPaymentSchema
|
|
3178
|
+
await readSensitiveJsonObject(opts),
|
|
3179
|
+
"payment-session cancel",
|
|
3180
|
+
CancelServerPaymentSessionParamsSchema
|
|
2088
3181
|
);
|
|
2089
|
-
const sdkParams = {
|
|
2090
|
-
...data,
|
|
2091
|
-
...opts.idempotencyKey !== void 0 ? { idempotencyKey: parseIdempotencyKey(opts.idempotencyKey) } : {}
|
|
2092
|
-
};
|
|
2093
3182
|
if (opts.dryRun) {
|
|
2094
3183
|
printResult(
|
|
2095
|
-
|
|
2096
|
-
dryRun: true,
|
|
2097
|
-
valid: true,
|
|
2098
|
-
action: "transaction confirm-payment",
|
|
2099
|
-
data: sdkParams
|
|
2100
|
-
},
|
|
3184
|
+
sensitiveDryRunResult("payment-session cancel"),
|
|
2101
3185
|
getFormat2()
|
|
2102
3186
|
);
|
|
2103
3187
|
return;
|
|
2104
3188
|
}
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
3189
|
+
printResult(
|
|
3190
|
+
await getClient2().commerce.paymentSessions.cancel(data),
|
|
3191
|
+
getFormat2()
|
|
2108
3192
|
);
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
3193
|
+
} catch (error) {
|
|
3194
|
+
exitWithError(error);
|
|
3195
|
+
}
|
|
3196
|
+
});
|
|
3197
|
+
sessions.command("confirm-toss").description("Confirm a Toss authorization with the typed server action").option("--data-stdin", "Read Toss confirmation params from stdin").option("--data-file <path>", "Read Toss confirmation params from file").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
3198
|
+
try {
|
|
3199
|
+
const data = parseWithSchema(
|
|
3200
|
+
await readSensitiveJsonObject(opts),
|
|
3201
|
+
"payment-session confirm-toss",
|
|
3202
|
+
ConfirmTossPaymentSessionParamsSchema
|
|
3203
|
+
);
|
|
3204
|
+
if (opts.dryRun) {
|
|
3205
|
+
printResult(
|
|
3206
|
+
sensitiveDryRunResult("payment-session confirm-toss"),
|
|
3207
|
+
getFormat2()
|
|
3208
|
+
);
|
|
3209
|
+
return;
|
|
3210
|
+
}
|
|
3211
|
+
printResult(
|
|
3212
|
+
await getClient2().commerce.paymentSessions.confirm(data),
|
|
3213
|
+
getFormat2()
|
|
3214
|
+
);
|
|
3215
|
+
} catch (error) {
|
|
3216
|
+
exitWithError(error);
|
|
2112
3217
|
}
|
|
2113
3218
|
});
|
|
2114
3219
|
}
|
|
2115
3220
|
|
|
3221
|
+
// src/lib/product-detail-options.ts
|
|
3222
|
+
function invalidOption(message, field, value) {
|
|
3223
|
+
const error = new Error(message);
|
|
3224
|
+
Object.assign(error, {
|
|
3225
|
+
type: "validation",
|
|
3226
|
+
code: "invalid_argument",
|
|
3227
|
+
field,
|
|
3228
|
+
detail: { message, value, field }
|
|
3229
|
+
});
|
|
3230
|
+
return error;
|
|
3231
|
+
}
|
|
3232
|
+
function parseLocale(value) {
|
|
3233
|
+
if (value == null) return void 0;
|
|
3234
|
+
if (value === "ko" || value === "en" || value === "all") return value;
|
|
3235
|
+
throw invalidOption("--locale must be one of: ko, en, all", "locale", value);
|
|
3236
|
+
}
|
|
3237
|
+
function parseFallbackLocale(value) {
|
|
3238
|
+
if (value == null) return void 0;
|
|
3239
|
+
if (value === "ko" || value === "en") return value;
|
|
3240
|
+
if (value === "none") return false;
|
|
3241
|
+
throw invalidOption(
|
|
3242
|
+
"--fallback-locale must be one of: ko, en, none",
|
|
3243
|
+
"fallbackLocale",
|
|
3244
|
+
value
|
|
3245
|
+
);
|
|
3246
|
+
}
|
|
3247
|
+
function productDetailParamsFromOptions(options) {
|
|
3248
|
+
const hasId = typeof options.id === "string" && options.id.length > 0;
|
|
3249
|
+
const hasSlug = typeof options.slug === "string" && options.slug.length > 0;
|
|
3250
|
+
if (hasId === hasSlug) {
|
|
3251
|
+
throw invalidOption(
|
|
3252
|
+
"Exactly one of --id or --slug is required.",
|
|
3253
|
+
"product",
|
|
3254
|
+
{ id: options.id, slug: options.slug }
|
|
3255
|
+
);
|
|
3256
|
+
}
|
|
3257
|
+
const locale = parseLocale(options.locale);
|
|
3258
|
+
const fallbackLocale = parseFallbackLocale(options.fallbackLocale);
|
|
3259
|
+
const identifier = hasId ? { id: options.id } : { slug: options.slug };
|
|
3260
|
+
return {
|
|
3261
|
+
...identifier,
|
|
3262
|
+
...options.market !== void 0 ? { market: options.market } : {},
|
|
3263
|
+
...locale !== void 0 ? { locale } : {},
|
|
3264
|
+
...fallbackLocale !== void 0 ? { fallbackLocale } : {}
|
|
3265
|
+
};
|
|
3266
|
+
}
|
|
3267
|
+
|
|
2116
3268
|
// src/commands/product.ts
|
|
2117
3269
|
function registerProductCommands(program2, getClient2, getFormat2) {
|
|
2118
3270
|
const product = program2.command("product").description("Product management");
|
|
3271
|
+
product.command("detail").description("Get shaped product detail by slug or ID").option("--slug <slug>", "Product slug").option("--id <id>", "Product ID").option("--market <market>", "Market slug").option("--locale <locale>", "Locale: ko, en, or all").option("--fallback-locale <locale>", "Fallback locale: ko, en, or none").action(async (opts) => {
|
|
3272
|
+
try {
|
|
3273
|
+
const params = productDetailParamsFromOptions(opts);
|
|
3274
|
+
const client = getClient2();
|
|
3275
|
+
const result = await client.commerce.product.detail(params);
|
|
3276
|
+
printResult(result, getFormat2());
|
|
3277
|
+
} catch (e) {
|
|
3278
|
+
exitWithError(e);
|
|
3279
|
+
}
|
|
3280
|
+
});
|
|
2119
3281
|
product.command("upsert").description("Create or update a product graph (options, values, variants)").requiredOption("--input <json>", "Product upsert input (JSON)").option("--dry-run", "Validate inputs without executing").action(async (opts) => {
|
|
2120
3282
|
try {
|
|
2121
3283
|
const data = parseWithSchema(
|
|
@@ -2169,12 +3331,14 @@ function registerShippingCommands(program2, getClient2, getFormat2) {
|
|
|
2169
3331
|
"--order-amount <n>",
|
|
2170
3332
|
"Order amount",
|
|
2171
3333
|
(v) => parseInt(v, 10)
|
|
2172
|
-
).option("--shipping-policy-id <id>", "Shipping policy ID").option("--postal-code <code>", "Destination postal code").action(async (opts) => {
|
|
3334
|
+
).option("--shipping-policy-id <id>", "Shipping policy ID").option("--country-code <code>", "Destination country code").option("--region-code <code>", "Destination region code").option("--postal-code <code>", "Destination postal code").action(async (opts) => {
|
|
2173
3335
|
try {
|
|
2174
3336
|
const client = getClient2();
|
|
2175
3337
|
const result = await client.commerce.shipping.calculate({
|
|
2176
3338
|
orderAmount: opts.orderAmount,
|
|
2177
3339
|
...opts.shippingPolicyId ? { shippingPolicyId: opts.shippingPolicyId } : {},
|
|
3340
|
+
...opts.countryCode ? { countryCode: opts.countryCode } : {},
|
|
3341
|
+
...opts.regionCode ? { regionCode: opts.regionCode } : {},
|
|
2178
3342
|
...opts.postalCode ? { postalCode: opts.postalCode } : {}
|
|
2179
3343
|
});
|
|
2180
3344
|
printResult(result, getFormat2());
|
|
@@ -2185,7 +3349,7 @@ function registerShippingCommands(program2, getClient2, getFormat2) {
|
|
|
2185
3349
|
}
|
|
2186
3350
|
|
|
2187
3351
|
// src/commands/auth.ts
|
|
2188
|
-
import { randomBytes } from "crypto";
|
|
3352
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
2189
3353
|
import { createServer } from "http";
|
|
2190
3354
|
import { execFile, exec } from "child_process";
|
|
2191
3355
|
import { platform } from "os";
|
|
@@ -2360,7 +3524,7 @@ Logged in successfully!`));
|
|
|
2360
3524
|
}
|
|
2361
3525
|
function registerAuthCommands(program2) {
|
|
2362
3526
|
program2.command("login").description("Login via browser and store credentials").action(async () => {
|
|
2363
|
-
const state =
|
|
3527
|
+
const state = randomBytes2(32).toString("hex");
|
|
2364
3528
|
try {
|
|
2365
3529
|
const { port } = await startAuthServer({
|
|
2366
3530
|
state,
|
|
@@ -2449,7 +3613,7 @@ ${loginUrl}`));
|
|
|
2449
3613
|
);
|
|
2450
3614
|
process.exit(3);
|
|
2451
3615
|
}
|
|
2452
|
-
const state =
|
|
3616
|
+
const state = randomBytes2(32).toString("hex");
|
|
2453
3617
|
const isLocal = !!opts.local;
|
|
2454
3618
|
try {
|
|
2455
3619
|
const { port } = await startAuthServer({
|
|
@@ -2548,9 +3712,15 @@ function registerFeatureCommands(program2, getClient2, getFormat2) {
|
|
|
2548
3712
|
}
|
|
2549
3713
|
|
|
2550
3714
|
// src/commands/agent.ts
|
|
3715
|
+
import { SERVER_COLLECTIONS as SERVER_COLLECTIONS4 } from "@01.software/sdk";
|
|
3716
|
+
|
|
3717
|
+
// src/lib/agent-plan-allowlist.ts
|
|
2551
3718
|
import { SERVER_COLLECTIONS as SERVER_COLLECTIONS3 } from "@01.software/sdk";
|
|
2552
3719
|
|
|
2553
3720
|
// src/lib/agent-output.ts
|
|
3721
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
3722
|
+
import fs from "fs";
|
|
3723
|
+
import path from "path";
|
|
2554
3724
|
var PLAN_AGENT_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
2555
3725
|
"PLAN_EXPIRED",
|
|
2556
3726
|
"PLAN_MISMATCH",
|
|
@@ -2567,9 +3737,95 @@ function agentPlanError(code, message) {
|
|
|
2567
3737
|
});
|
|
2568
3738
|
return error;
|
|
2569
3739
|
}
|
|
3740
|
+
var AGENT_OUTPUT_FILE_MODE = 384;
|
|
3741
|
+
var isWin32 = process.platform === "win32";
|
|
2570
3742
|
function stringifyAgentJson(data, options = {}) {
|
|
2571
3743
|
return options.pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
2572
3744
|
}
|
|
3745
|
+
function invalidOutputTarget(message, outputFile) {
|
|
3746
|
+
const error = new Error(message);
|
|
3747
|
+
Object.assign(error, {
|
|
3748
|
+
type: "validation",
|
|
3749
|
+
code: "invalid_argument",
|
|
3750
|
+
field: "outputFile",
|
|
3751
|
+
detail: { message, field: "outputFile", value: outputFile }
|
|
3752
|
+
});
|
|
3753
|
+
return error;
|
|
3754
|
+
}
|
|
3755
|
+
function assertSafeAgentOutputTarget(outputFile) {
|
|
3756
|
+
let stat;
|
|
3757
|
+
try {
|
|
3758
|
+
stat = fs.lstatSync(outputFile);
|
|
3759
|
+
} catch (error) {
|
|
3760
|
+
if (error.code === "ENOENT") return;
|
|
3761
|
+
throw error;
|
|
3762
|
+
}
|
|
3763
|
+
if (stat.isSymbolicLink()) {
|
|
3764
|
+
throw invalidOutputTarget(
|
|
3765
|
+
`Refusing to write Agent output through a symlink: ${outputFile}.`,
|
|
3766
|
+
outputFile
|
|
3767
|
+
);
|
|
3768
|
+
}
|
|
3769
|
+
if (!stat.isFile()) {
|
|
3770
|
+
throw invalidOutputTarget(
|
|
3771
|
+
`Refusing to write Agent output to a non-regular file: ${outputFile}.`,
|
|
3772
|
+
outputFile
|
|
3773
|
+
);
|
|
3774
|
+
}
|
|
3775
|
+
if (!isWin32 && stat.nlink > 1) {
|
|
3776
|
+
throw invalidOutputTarget(
|
|
3777
|
+
`Refusing to write Agent output to a file with multiple hard links: ${outputFile}.`,
|
|
3778
|
+
outputFile
|
|
3779
|
+
);
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
function writeAgentOutputFile(requestedPath, content) {
|
|
3783
|
+
const outputFile = path.resolve(requestedPath);
|
|
3784
|
+
assertSafeAgentOutputTarget(outputFile);
|
|
3785
|
+
const tempFile = path.join(
|
|
3786
|
+
path.dirname(outputFile),
|
|
3787
|
+
`.${path.basename(outputFile)}.${randomBytes3(12).toString("hex")}.tmp`
|
|
3788
|
+
);
|
|
3789
|
+
let tempFd;
|
|
3790
|
+
try {
|
|
3791
|
+
tempFd = fs.openSync(tempFile, "wx", AGENT_OUTPUT_FILE_MODE);
|
|
3792
|
+
if (!isWin32) {
|
|
3793
|
+
fs.fchmodSync(tempFd, AGENT_OUTPUT_FILE_MODE);
|
|
3794
|
+
}
|
|
3795
|
+
fs.writeFileSync(tempFd, content, { encoding: "utf8" });
|
|
3796
|
+
fs.closeSync(tempFd);
|
|
3797
|
+
tempFd = void 0;
|
|
3798
|
+
fs.renameSync(tempFile, outputFile);
|
|
3799
|
+
} catch (error) {
|
|
3800
|
+
if (tempFd !== void 0) {
|
|
3801
|
+
try {
|
|
3802
|
+
fs.closeSync(tempFd);
|
|
3803
|
+
} catch {
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
try {
|
|
3807
|
+
fs.unlinkSync(tempFile);
|
|
3808
|
+
} catch {
|
|
3809
|
+
}
|
|
3810
|
+
throw error;
|
|
3811
|
+
}
|
|
3812
|
+
return {
|
|
3813
|
+
outputFile,
|
|
3814
|
+
bytes: Buffer.byteLength(content, "utf8")
|
|
3815
|
+
};
|
|
3816
|
+
}
|
|
3817
|
+
function resolveAgentPrintOptions(command) {
|
|
3818
|
+
const options = command.optsWithGlobals();
|
|
3819
|
+
return {
|
|
3820
|
+
pretty: Boolean(options.pretty),
|
|
3821
|
+
outputFile: options.outputFile
|
|
3822
|
+
};
|
|
3823
|
+
}
|
|
3824
|
+
function validateAgentOutputTarget(options) {
|
|
3825
|
+
if (options.outputFile !== void 0) {
|
|
3826
|
+
assertSafeAgentOutputTarget(path.resolve(options.outputFile));
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
2573
3829
|
function asRecord(value) {
|
|
2574
3830
|
return value && typeof value === "object" ? value : null;
|
|
2575
3831
|
}
|
|
@@ -2595,6 +3851,20 @@ function isRawNotFound(error) {
|
|
|
2595
3851
|
const raw = asRecord(error);
|
|
2596
3852
|
return raw?.status === 404 || raw?.code === "not_found" || raw?.name === "GoneError";
|
|
2597
3853
|
}
|
|
3854
|
+
function isSdkUsageLimitError(error) {
|
|
3855
|
+
const raw = asRecord(error);
|
|
3856
|
+
return raw?.name === "UsageLimitError" || raw?.code === "USAGE_LIMIT_ERROR";
|
|
3857
|
+
}
|
|
3858
|
+
function agentErrorEnvelope(code, message, retryable, retryAfter) {
|
|
3859
|
+
return {
|
|
3860
|
+
error: {
|
|
3861
|
+
code,
|
|
3862
|
+
message,
|
|
3863
|
+
retryable,
|
|
3864
|
+
...typeof retryAfter === "number" ? { retryAfter } : {}
|
|
3865
|
+
}
|
|
3866
|
+
};
|
|
3867
|
+
}
|
|
2598
3868
|
function agentErrorExitCode(code) {
|
|
2599
3869
|
switch (code) {
|
|
2600
3870
|
case "INVALID_INPUT":
|
|
@@ -2618,22 +3888,30 @@ function classifyAgentError(error) {
|
|
|
2618
3888
|
const detailRecord = detail && typeof detail === "object" ? detail : null;
|
|
2619
3889
|
const agentCode = raw?.agentCode ?? detailRecord?.agentCode;
|
|
2620
3890
|
if (typeof agentCode === "string" && PLAN_AGENT_ERROR_CODES.has(agentCode)) {
|
|
2621
|
-
return
|
|
3891
|
+
return agentErrorEnvelope(agentCode, message, false);
|
|
2622
3892
|
}
|
|
2623
3893
|
const adminError = classifyError(error);
|
|
2624
3894
|
if (isRawNotFound(error) || adminError.code === "not_found") {
|
|
2625
|
-
return
|
|
3895
|
+
return agentErrorEnvelope("NOT_FOUND", message, false);
|
|
2626
3896
|
}
|
|
2627
3897
|
if (adminError.type === "permission") {
|
|
2628
|
-
return
|
|
3898
|
+
return agentErrorEnvelope("AUTH_FAILED", message, false);
|
|
2629
3899
|
}
|
|
2630
3900
|
if (adminError.type === "validation" && adminError.code !== "unknown") {
|
|
2631
|
-
return
|
|
3901
|
+
return agentErrorEnvelope("INVALID_INPUT", message, false);
|
|
2632
3902
|
}
|
|
2633
|
-
|
|
3903
|
+
const retryable = !isSdkUsageLimitError(error) && (adminError.type === "network" || adminError.type === "degraded");
|
|
3904
|
+
const retryAfter = retryable && adminError.type === "degraded" && adminError.code === "rate_limited" ? adminError.retryAfter : void 0;
|
|
3905
|
+
return agentErrorEnvelope("INTERNAL", message, retryable, retryAfter);
|
|
2634
3906
|
}
|
|
2635
3907
|
function printAgentSuccess(data, options = {}) {
|
|
2636
|
-
|
|
3908
|
+
const output = stringifyAgentJson(data, options);
|
|
3909
|
+
if (options.outputFile !== void 0) {
|
|
3910
|
+
const receipt = writeAgentOutputFile(options.outputFile, output);
|
|
3911
|
+
console.log(JSON.stringify(receipt));
|
|
3912
|
+
return;
|
|
3913
|
+
}
|
|
3914
|
+
console.log(output);
|
|
2637
3915
|
}
|
|
2638
3916
|
function printAgentError(error, options = {}) {
|
|
2639
3917
|
const envelope = classifyAgentError(error);
|
|
@@ -2646,25 +3924,77 @@ function exitWithAgentError(error, options = {}) {
|
|
|
2646
3924
|
}
|
|
2647
3925
|
|
|
2648
3926
|
// src/lib/agent-plan-allowlist.ts
|
|
2649
|
-
var
|
|
2650
|
-
|
|
2651
|
-
"article-categories",
|
|
2652
|
-
"article-tags",
|
|
2653
|
-
|
|
2654
|
-
"link-categories",
|
|
2655
|
-
"link-tags"
|
|
2656
|
-
]
|
|
2657
|
-
|
|
3927
|
+
var AGENT_PLAN_CAPABILITIES = {
|
|
3928
|
+
articles: ["create", "update", "delete"],
|
|
3929
|
+
"article-categories": ["create", "update", "delete"],
|
|
3930
|
+
"article-tags": ["create", "update", "delete"],
|
|
3931
|
+
links: ["create", "update", "delete"],
|
|
3932
|
+
"link-categories": ["create", "update", "delete"],
|
|
3933
|
+
"link-tags": ["create", "update", "delete"],
|
|
3934
|
+
documents: ["create", "update"],
|
|
3935
|
+
"document-categories": ["create", "update"],
|
|
3936
|
+
"document-types": ["create", "update"],
|
|
3937
|
+
canvases: ["create", "update", "delete"],
|
|
3938
|
+
"canvas-categories": ["create", "update", "delete"],
|
|
3939
|
+
"canvas-tags": ["create", "update", "delete"]
|
|
3940
|
+
};
|
|
3941
|
+
var SERVER_COLLECTION_SET = new Set(SERVER_COLLECTIONS3);
|
|
3942
|
+
var AGENT_PLAN_OPERATIONS = /* @__PURE__ */ new Set([
|
|
3943
|
+
"create",
|
|
3944
|
+
"update",
|
|
3945
|
+
"delete"
|
|
3946
|
+
]);
|
|
3947
|
+
function assertAgentPlanCapabilityMatrix(matrix) {
|
|
3948
|
+
for (const [collection, operations] of Object.entries(matrix)) {
|
|
3949
|
+
if (!SERVER_COLLECTION_SET.has(collection)) {
|
|
3950
|
+
throw new Error(
|
|
3951
|
+
`Agent plan capability collection "${collection}" is not a ServerCollection.`
|
|
3952
|
+
);
|
|
3953
|
+
}
|
|
3954
|
+
if (operations.length === 0) {
|
|
3955
|
+
throw new Error(
|
|
3956
|
+
`Agent plan capability collection "${collection}" has no operations.`
|
|
3957
|
+
);
|
|
3958
|
+
}
|
|
3959
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3960
|
+
for (const operation of operations) {
|
|
3961
|
+
if (!AGENT_PLAN_OPERATIONS.has(operation)) {
|
|
3962
|
+
throw new Error(
|
|
3963
|
+
`Agent plan capability operation "${operation}" is invalid for "${collection}".`
|
|
3964
|
+
);
|
|
3965
|
+
}
|
|
3966
|
+
if (seen.has(operation)) {
|
|
3967
|
+
throw new Error(
|
|
3968
|
+
`Agent plan capability operation "${operation}" is duplicated for "${collection}".`
|
|
3969
|
+
);
|
|
3970
|
+
}
|
|
3971
|
+
seen.add(operation);
|
|
3972
|
+
}
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
assertAgentPlanCapabilityMatrix(AGENT_PLAN_CAPABILITIES);
|
|
2658
3976
|
function isAgentPlanCollection(collection) {
|
|
2659
|
-
return
|
|
3977
|
+
return Object.prototype.hasOwnProperty.call(
|
|
3978
|
+
AGENT_PLAN_CAPABILITIES,
|
|
3979
|
+
collection
|
|
3980
|
+
);
|
|
3981
|
+
}
|
|
3982
|
+
function getAgentPlanOperations(collection) {
|
|
3983
|
+
return isAgentPlanCollection(collection) ? AGENT_PLAN_CAPABILITIES[collection] : [];
|
|
2660
3984
|
}
|
|
2661
|
-
function
|
|
2662
|
-
if (isAgentPlanCollection(collection))
|
|
3985
|
+
function isAgentPlanCapability(collection, operation) {
|
|
3986
|
+
if (!isAgentPlanCollection(collection)) return false;
|
|
3987
|
+
return AGENT_PLAN_CAPABILITIES[collection].includes(
|
|
3988
|
+
operation
|
|
3989
|
+
);
|
|
3990
|
+
}
|
|
3991
|
+
function assertAgentPlanCapability(collection, operation) {
|
|
3992
|
+
if (isAgentPlanCapability(collection, operation)) {
|
|
2663
3993
|
return collection;
|
|
2664
3994
|
}
|
|
2665
3995
|
throw agentPlanError(
|
|
2666
3996
|
"UNSUPPORTED_OPERATION",
|
|
2667
|
-
`
|
|
3997
|
+
`Operation "${operation}" is not supported for collection "${collection}" in agent plan mutations.`
|
|
2668
3998
|
);
|
|
2669
3999
|
}
|
|
2670
4000
|
|
|
@@ -2767,6 +4097,12 @@ function parseStoredAgentPlan(raw, planId) {
|
|
|
2767
4097
|
if (operation !== "create" && operation !== "update" && operation !== "delete") {
|
|
2768
4098
|
throw agentPlanError("PLAN_MISMATCH", "Stored plan has invalid operation.");
|
|
2769
4099
|
}
|
|
4100
|
+
if (!isAgentPlanCapability(collection, operation)) {
|
|
4101
|
+
throw agentPlanError(
|
|
4102
|
+
"PLAN_MISMATCH",
|
|
4103
|
+
"Stored plan has unsupported collection operation."
|
|
4104
|
+
);
|
|
4105
|
+
}
|
|
2770
4106
|
const payload = record.payload == null ? void 0 : typeof record.payload === "object" && !Array.isArray(record.payload) ? record.payload : (() => {
|
|
2771
4107
|
throw agentPlanError("PLAN_MISMATCH", "Stored plan payload is invalid.");
|
|
2772
4108
|
})();
|
|
@@ -2791,6 +4127,12 @@ function parseStoredAgentPlan(raw, planId) {
|
|
|
2791
4127
|
};
|
|
2792
4128
|
}
|
|
2793
4129
|
function assertStoredPlanHashMatches(plan) {
|
|
4130
|
+
if (!isAgentPlanCapability(plan.collection, plan.operation)) {
|
|
4131
|
+
throw agentPlanError(
|
|
4132
|
+
"PLAN_MISMATCH",
|
|
4133
|
+
"Stored plan has unsupported collection operation."
|
|
4134
|
+
);
|
|
4135
|
+
}
|
|
2794
4136
|
const expected = hashAgentPlanEnvelope({
|
|
2795
4137
|
operation: plan.operation,
|
|
2796
4138
|
collection: plan.collection,
|
|
@@ -3011,10 +4353,10 @@ function isSecretFieldName(key) {
|
|
|
3011
4353
|
const snake = key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
|
|
3012
4354
|
return SECRET_KEY.test(snake);
|
|
3013
4355
|
}
|
|
3014
|
-
function assertNoSecretFields(value,
|
|
4356
|
+
function assertNoSecretFields(value, path2 = "") {
|
|
3015
4357
|
if (Array.isArray(value)) {
|
|
3016
4358
|
value.forEach((item, index) => {
|
|
3017
|
-
assertNoSecretFields(item, `${
|
|
4359
|
+
assertNoSecretFields(item, `${path2}[${index}]`);
|
|
3018
4360
|
});
|
|
3019
4361
|
return;
|
|
3020
4362
|
}
|
|
@@ -3022,7 +4364,7 @@ function assertNoSecretFields(value, path = "") {
|
|
|
3022
4364
|
return;
|
|
3023
4365
|
}
|
|
3024
4366
|
for (const [key, child] of Object.entries(value)) {
|
|
3025
|
-
const fieldPath =
|
|
4367
|
+
const fieldPath = path2 ? `${path2}.${key}` : key;
|
|
3026
4368
|
if (isSecretFieldName(key)) {
|
|
3027
4369
|
throw agentPlanError(
|
|
3028
4370
|
"INVALID_INPUT",
|
|
@@ -3064,7 +4406,7 @@ function buildConfirmCommand(planToken, planHash) {
|
|
|
3064
4406
|
}
|
|
3065
4407
|
|
|
3066
4408
|
// src/commands/agent-plan.ts
|
|
3067
|
-
function
|
|
4409
|
+
function invalidInput2(message, field) {
|
|
3068
4410
|
const error = new Error(message);
|
|
3069
4411
|
Object.assign(error, {
|
|
3070
4412
|
type: "validation",
|
|
@@ -3078,7 +4420,7 @@ function handleCommanderError(error) {
|
|
|
3078
4420
|
if (error.code === "commander.helpDisplayed") {
|
|
3079
4421
|
process.exit(error.exitCode);
|
|
3080
4422
|
}
|
|
3081
|
-
exitWithAgentError(
|
|
4423
|
+
exitWithAgentError(invalidInput2(error.message, "command"));
|
|
3082
4424
|
}
|
|
3083
4425
|
function configureAgentParser(command) {
|
|
3084
4426
|
command.configureOutput({
|
|
@@ -3096,9 +4438,12 @@ async function captureBaseUpdatedAt(client, collection, documentId) {
|
|
|
3096
4438
|
return readDocumentUpdatedAt(doc);
|
|
3097
4439
|
}
|
|
3098
4440
|
async function runPlanAction(input) {
|
|
3099
|
-
const collection =
|
|
4441
|
+
const collection = assertAgentPlanCapability(
|
|
4442
|
+
input.collection,
|
|
4443
|
+
input.operation
|
|
4444
|
+
);
|
|
3100
4445
|
if (input.operation !== "create" && !input.documentId) {
|
|
3101
|
-
throw
|
|
4446
|
+
throw invalidInput2("Missing required argument: id", "id");
|
|
3102
4447
|
}
|
|
3103
4448
|
let payload;
|
|
3104
4449
|
if (input.operation === "create" || input.operation === "update") {
|
|
@@ -3160,7 +4505,7 @@ async function runPlanAction(input) {
|
|
|
3160
4505
|
documentId: stored.documentId,
|
|
3161
4506
|
confirmCommand: buildConfirmCommand(planToken, stored.planHash)
|
|
3162
4507
|
},
|
|
3163
|
-
|
|
4508
|
+
input.outputOptions
|
|
3164
4509
|
);
|
|
3165
4510
|
}
|
|
3166
4511
|
function registerAgentPlanCommands(agent, getClient2) {
|
|
@@ -3168,63 +4513,83 @@ function registerAgentPlanCommands(agent, getClient2) {
|
|
|
3168
4513
|
agent.command("plan").description("Plan a mutation without executing")
|
|
3169
4514
|
);
|
|
3170
4515
|
configureAgentParser(
|
|
3171
|
-
plan.command("create <collection>").description("Plan a document create").option("--data-stdin", "Read mutation JSON from stdin").option("--data-file <path>", "Read mutation JSON from file").option("--pretty", "Print 2-space indented JSON").
|
|
3172
|
-
|
|
4516
|
+
plan.command("create <collection>").description("Plan a document create").option("--data-stdin", "Read mutation JSON from stdin").option("--data-file <path>", "Read mutation JSON from file").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4517
|
+
"--output-file <path>",
|
|
4518
|
+
"Write success JSON to a secure file and print a receipt"
|
|
4519
|
+
).action(
|
|
4520
|
+
async (collection, opts, command) => {
|
|
4521
|
+
const outputOptions = resolveAgentPrintOptions(command);
|
|
3173
4522
|
try {
|
|
4523
|
+
validateAgentOutputTarget(outputOptions);
|
|
3174
4524
|
await runPlanAction({
|
|
3175
4525
|
operation: "create",
|
|
3176
4526
|
collection,
|
|
3177
4527
|
dataStdin: opts.dataStdin,
|
|
3178
4528
|
dataFile: opts.dataFile,
|
|
3179
|
-
|
|
4529
|
+
outputOptions,
|
|
3180
4530
|
getClient: getClient2
|
|
3181
4531
|
});
|
|
3182
4532
|
} catch (error) {
|
|
3183
|
-
exitWithAgentError(error,
|
|
4533
|
+
exitWithAgentError(error, outputOptions);
|
|
3184
4534
|
}
|
|
3185
4535
|
}
|
|
3186
4536
|
)
|
|
3187
4537
|
);
|
|
3188
4538
|
configureAgentParser(
|
|
3189
|
-
plan.command("update <collection> <id>").description("Plan a document update").option("--data-stdin", "Read mutation JSON from stdin").option("--data-file <path>", "Read mutation JSON from file").option("--pretty", "Print 2-space indented JSON").
|
|
3190
|
-
|
|
4539
|
+
plan.command("update <collection> <id>").description("Plan a document update").option("--data-stdin", "Read mutation JSON from stdin").option("--data-file <path>", "Read mutation JSON from file").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4540
|
+
"--output-file <path>",
|
|
4541
|
+
"Write success JSON to a secure file and print a receipt"
|
|
4542
|
+
).action(
|
|
4543
|
+
async (collection, id, opts, command) => {
|
|
4544
|
+
const outputOptions = resolveAgentPrintOptions(command);
|
|
3191
4545
|
try {
|
|
4546
|
+
validateAgentOutputTarget(outputOptions);
|
|
3192
4547
|
await runPlanAction({
|
|
3193
4548
|
operation: "update",
|
|
3194
4549
|
collection,
|
|
3195
4550
|
documentId: id,
|
|
3196
4551
|
dataStdin: opts.dataStdin,
|
|
3197
4552
|
dataFile: opts.dataFile,
|
|
3198
|
-
|
|
4553
|
+
outputOptions,
|
|
3199
4554
|
getClient: getClient2
|
|
3200
4555
|
});
|
|
3201
4556
|
} catch (error) {
|
|
3202
|
-
exitWithAgentError(error,
|
|
4557
|
+
exitWithAgentError(error, outputOptions);
|
|
3203
4558
|
}
|
|
3204
4559
|
}
|
|
3205
4560
|
)
|
|
3206
4561
|
);
|
|
3207
4562
|
configureAgentParser(
|
|
3208
|
-
plan.command("delete <collection> <id>").description("Plan a document delete").option("--pretty", "Print 2-space indented JSON").
|
|
3209
|
-
|
|
4563
|
+
plan.command("delete <collection> <id>").description("Plan a document delete").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4564
|
+
"--output-file <path>",
|
|
4565
|
+
"Write success JSON to a secure file and print a receipt"
|
|
4566
|
+
).action(
|
|
4567
|
+
async (collection, id, opts, command) => {
|
|
4568
|
+
const outputOptions = resolveAgentPrintOptions(command);
|
|
3210
4569
|
try {
|
|
4570
|
+
validateAgentOutputTarget(outputOptions);
|
|
3211
4571
|
await runPlanAction({
|
|
3212
4572
|
operation: "delete",
|
|
3213
4573
|
collection,
|
|
3214
4574
|
documentId: id,
|
|
3215
|
-
|
|
4575
|
+
outputOptions,
|
|
3216
4576
|
getClient: getClient2
|
|
3217
4577
|
});
|
|
3218
4578
|
} catch (error) {
|
|
3219
|
-
exitWithAgentError(error,
|
|
4579
|
+
exitWithAgentError(error, outputOptions);
|
|
3220
4580
|
}
|
|
3221
4581
|
}
|
|
3222
4582
|
)
|
|
3223
4583
|
);
|
|
3224
4584
|
configureAgentParser(
|
|
3225
|
-
agent.command("confirm <planToken>").description("Execute a previously planned mutation").requiredOption("--hash <planHash>", "Plan hash from plan output").option("--pretty", "Print 2-space indented JSON").
|
|
3226
|
-
|
|
4585
|
+
agent.command("confirm <planToken>").description("Execute a previously planned mutation").requiredOption("--hash <planHash>", "Plan hash from plan output").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4586
|
+
"--output-file <path>",
|
|
4587
|
+
"Write success JSON to a secure file and print a receipt"
|
|
4588
|
+
).action(
|
|
4589
|
+
async (planTokenRaw, opts, command) => {
|
|
4590
|
+
const outputOptions = resolveAgentPrintOptions(command);
|
|
3227
4591
|
try {
|
|
4592
|
+
validateAgentOutputTarget(outputOptions);
|
|
3228
4593
|
const token = decodePlanToken(planTokenRaw);
|
|
3229
4594
|
if (token.planHash !== opts.hash) {
|
|
3230
4595
|
throw agentPlanError(
|
|
@@ -3270,10 +4635,10 @@ function registerAgentPlanCommands(agent, getClient2) {
|
|
|
3270
4635
|
id: doc && typeof doc === "object" && "id" in doc ? String(doc.id) : plan2.documentId,
|
|
3271
4636
|
doc
|
|
3272
4637
|
},
|
|
3273
|
-
|
|
4638
|
+
outputOptions
|
|
3274
4639
|
);
|
|
3275
4640
|
} catch (error) {
|
|
3276
|
-
exitWithAgentError(error,
|
|
4641
|
+
exitWithAgentError(error, outputOptions);
|
|
3277
4642
|
}
|
|
3278
4643
|
}
|
|
3279
4644
|
)
|
|
@@ -3289,7 +4654,7 @@ function buildStableAgentFields() {
|
|
|
3289
4654
|
updatedAt: { type: "string", queryable: true }
|
|
3290
4655
|
};
|
|
3291
4656
|
}
|
|
3292
|
-
function
|
|
4657
|
+
function invalidInput3(message, field, value) {
|
|
3293
4658
|
const error = new Error(message);
|
|
3294
4659
|
Object.assign(error, {
|
|
3295
4660
|
type: "validation",
|
|
@@ -3302,13 +4667,13 @@ function invalidInput2(message, field, value) {
|
|
|
3302
4667
|
function parsePositiveInteger(value, field) {
|
|
3303
4668
|
if (value == null) return void 0;
|
|
3304
4669
|
if (/^[1-9]\d*$/.test(value)) return Number(value);
|
|
3305
|
-
throw
|
|
4670
|
+
throw invalidInput3(`--${field} must be a positive integer`, field, value);
|
|
3306
4671
|
}
|
|
3307
4672
|
function handleCommanderError2(error) {
|
|
3308
4673
|
if (error.code === "commander.helpDisplayed") {
|
|
3309
4674
|
process.exit(error.exitCode);
|
|
3310
4675
|
}
|
|
3311
|
-
exitWithAgentError(
|
|
4676
|
+
exitWithAgentError(invalidInput3(error.message, "command"));
|
|
3312
4677
|
}
|
|
3313
4678
|
function configureAgentParser2(command) {
|
|
3314
4679
|
command.configureOutput({
|
|
@@ -3329,23 +4694,27 @@ function parseWhere(value) {
|
|
|
3329
4694
|
return parsed;
|
|
3330
4695
|
}
|
|
3331
4696
|
} catch {
|
|
3332
|
-
throw
|
|
4697
|
+
throw invalidInput3("--where must be a JSON object", "where", value);
|
|
3333
4698
|
}
|
|
3334
|
-
throw
|
|
4699
|
+
throw invalidInput3("--where must be a JSON object", "where", value);
|
|
3335
4700
|
}
|
|
3336
4701
|
var AGENT_READ_OPERATIONS = [
|
|
3337
4702
|
"query",
|
|
3338
4703
|
"get"
|
|
3339
4704
|
];
|
|
3340
|
-
var
|
|
3341
|
-
"
|
|
3342
|
-
"plan:update",
|
|
3343
|
-
"plan:delete"
|
|
4705
|
+
var AGENT_PRODUCT_OPERATIONS = [
|
|
4706
|
+
"detail"
|
|
3344
4707
|
];
|
|
3345
4708
|
function buildAgentManifest() {
|
|
3346
4709
|
const collections = {};
|
|
3347
|
-
for (const collection of
|
|
3348
|
-
const operations =
|
|
4710
|
+
for (const collection of SERVER_COLLECTIONS4) {
|
|
4711
|
+
const operations = [
|
|
4712
|
+
...AGENT_READ_OPERATIONS,
|
|
4713
|
+
...collection === "products" ? AGENT_PRODUCT_OPERATIONS : [],
|
|
4714
|
+
...getAgentPlanOperations(collection).map(
|
|
4715
|
+
(operation) => `plan:${operation}`
|
|
4716
|
+
)
|
|
4717
|
+
];
|
|
3349
4718
|
collections[collection] = {
|
|
3350
4719
|
operations,
|
|
3351
4720
|
fields: buildStableAgentFields()
|
|
@@ -3353,6 +4722,10 @@ function buildAgentManifest() {
|
|
|
3353
4722
|
}
|
|
3354
4723
|
return {
|
|
3355
4724
|
version: AGENT_PROTOCOL_VERSION,
|
|
4725
|
+
discovery: {
|
|
4726
|
+
context: { counts: true },
|
|
4727
|
+
schema: { mode: "effective" }
|
|
4728
|
+
},
|
|
3356
4729
|
collections
|
|
3357
4730
|
};
|
|
3358
4731
|
}
|
|
@@ -3361,27 +4734,75 @@ function validateAgentCollection(collection) {
|
|
|
3361
4734
|
return validateCollection(collection);
|
|
3362
4735
|
} catch (error) {
|
|
3363
4736
|
const message = error instanceof Error ? error.message : `Unknown collection "${collection}".`;
|
|
3364
|
-
throw
|
|
4737
|
+
throw invalidInput3(message, "collection", collection);
|
|
3365
4738
|
}
|
|
3366
4739
|
}
|
|
3367
4740
|
function registerAgentCommands(program2, getClient2) {
|
|
3368
4741
|
const agent = configureAgentParser2(
|
|
3369
|
-
program2.command("agent").description("Machine-stable CLI namespace for coding agents").
|
|
4742
|
+
program2.command("agent").description("Machine-stable CLI namespace for coding agents").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4743
|
+
"--output-file <path>",
|
|
4744
|
+
"Write success JSON to a secure file and print a receipt"
|
|
4745
|
+
).addHelpText(
|
|
3370
4746
|
"after",
|
|
3371
4747
|
"\nContract: docs/agent-cli-contract.md\nJSON only on stdout; no TTY effects."
|
|
3372
4748
|
)
|
|
3373
4749
|
);
|
|
3374
4750
|
configureAgentParser2(
|
|
3375
|
-
agent.command("manifest").description("Print the Agent CLI protocol manifest").option("--pretty", "Print 2-space indented JSON").
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
4751
|
+
agent.command("manifest").description("Print the Agent CLI protocol manifest").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4752
|
+
"--output-file <path>",
|
|
4753
|
+
"Write success JSON to a secure file and print a receipt"
|
|
4754
|
+
).action((_opts, command) => {
|
|
4755
|
+
const outputOptions = resolveAgentPrintOptions(command);
|
|
4756
|
+
try {
|
|
4757
|
+
validateAgentOutputTarget(outputOptions);
|
|
4758
|
+
printAgentSuccess(buildAgentManifest(), outputOptions);
|
|
4759
|
+
} catch (error) {
|
|
4760
|
+
exitWithAgentError(error, outputOptions);
|
|
4761
|
+
}
|
|
4762
|
+
})
|
|
4763
|
+
);
|
|
4764
|
+
configureAgentParser2(
|
|
4765
|
+
agent.command("context").description("Get the active tenant context").option("--counts", "Include collection document counts").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4766
|
+
"--output-file <path>",
|
|
4767
|
+
"Write success JSON to a secure file and print a receipt"
|
|
4768
|
+
).action(async (opts, command) => {
|
|
4769
|
+
const outputOptions = resolveAgentPrintOptions(command);
|
|
4770
|
+
try {
|
|
4771
|
+
validateAgentOutputTarget(outputOptions);
|
|
4772
|
+
const client = getClient2();
|
|
4773
|
+
const result = opts.counts ? await client.tenant.context({ includeCounts: true }) : await client.tenant.context();
|
|
4774
|
+
printAgentSuccess(result, outputOptions);
|
|
4775
|
+
} catch (error) {
|
|
4776
|
+
exitWithAgentError(error, outputOptions);
|
|
4777
|
+
}
|
|
4778
|
+
})
|
|
4779
|
+
);
|
|
4780
|
+
configureAgentParser2(
|
|
4781
|
+
agent.command("schema <collection>").description("Get the effective field schema for a collection").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4782
|
+
"--output-file <path>",
|
|
4783
|
+
"Write success JSON to a secure file and print a receipt"
|
|
4784
|
+
).action(async (collection, _opts, command) => {
|
|
4785
|
+
const outputOptions = resolveAgentPrintOptions(command);
|
|
4786
|
+
try {
|
|
4787
|
+
validateAgentOutputTarget(outputOptions);
|
|
4788
|
+
const col = validateAgentCollection(collection);
|
|
4789
|
+
const client = getClient2();
|
|
4790
|
+
const result = await client.tenant.collectionSchema(col);
|
|
4791
|
+
printAgentSuccess(result, outputOptions);
|
|
4792
|
+
} catch (error) {
|
|
4793
|
+
exitWithAgentError(error, outputOptions);
|
|
4794
|
+
}
|
|
3379
4795
|
})
|
|
3380
4796
|
);
|
|
3381
4797
|
configureAgentParser2(
|
|
3382
|
-
agent.command("query <collection>").description("Query documents from a collection").option("--where <json>", "Filter conditions as a JSON object").option("--limit <n>", "Max results").option("--page <n>", "Page number").option("--sort <field>", "Sort field; prefix with - for descending").option("--select <fields>", "Comma-separated fields to select").option("--pretty", "Print 2-space indented JSON").
|
|
3383
|
-
|
|
4798
|
+
agent.command("query <collection>").description("Query documents from a collection").option("--where <json>", "Filter conditions as a JSON object").option("--limit <n>", "Max results").option("--page <n>", "Page number").option("--sort <field>", "Sort field; prefix with - for descending").option("--select <fields>", "Comma-separated fields to select").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4799
|
+
"--output-file <path>",
|
|
4800
|
+
"Write success JSON to a secure file and print a receipt"
|
|
4801
|
+
).action(
|
|
4802
|
+
async (collection, opts, command) => {
|
|
4803
|
+
const outputOptions = resolveAgentPrintOptions(command);
|
|
3384
4804
|
try {
|
|
4805
|
+
validateAgentOutputTarget(outputOptions);
|
|
3385
4806
|
const col = validateAgentCollection(collection);
|
|
3386
4807
|
const options = {};
|
|
3387
4808
|
const where = parseWhere(opts.where);
|
|
@@ -3394,28 +4815,55 @@ function registerAgentCommands(program2, getClient2) {
|
|
|
3394
4815
|
if (opts.select) options.select = parseSelect(opts.select);
|
|
3395
4816
|
const client = getClient2();
|
|
3396
4817
|
const result = await client.collections.from(col).find(options);
|
|
3397
|
-
printAgentSuccess(result,
|
|
4818
|
+
printAgentSuccess(result, outputOptions);
|
|
3398
4819
|
} catch (error) {
|
|
3399
|
-
exitWithAgentError(error,
|
|
4820
|
+
exitWithAgentError(error, outputOptions);
|
|
3400
4821
|
}
|
|
3401
4822
|
}
|
|
3402
4823
|
)
|
|
3403
4824
|
);
|
|
3404
4825
|
configureAgentParser2(
|
|
3405
|
-
agent.command("get <collection> [id]").description("Get a document by ID").option("--select <fields>", "Comma-separated fields to select").option("--pretty", "Print 2-space indented JSON").
|
|
3406
|
-
|
|
4826
|
+
agent.command("get <collection> [id]").description("Get a document by ID").option("--select <fields>", "Comma-separated fields to select").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4827
|
+
"--output-file <path>",
|
|
4828
|
+
"Write success JSON to a secure file and print a receipt"
|
|
4829
|
+
).action(
|
|
4830
|
+
async (collection, id, opts, command) => {
|
|
4831
|
+
const outputOptions = resolveAgentPrintOptions(command);
|
|
3407
4832
|
try {
|
|
4833
|
+
validateAgentOutputTarget(outputOptions);
|
|
3408
4834
|
const col = validateAgentCollection(collection);
|
|
3409
4835
|
if (!id) {
|
|
3410
|
-
throw
|
|
4836
|
+
throw invalidInput3("Missing required argument: id", "id");
|
|
3411
4837
|
}
|
|
3412
4838
|
const options = {};
|
|
3413
4839
|
if (opts.select) options.select = parseSelect(opts.select);
|
|
3414
4840
|
const client = getClient2();
|
|
3415
4841
|
const result = await client.collections.from(col).findById(id, options);
|
|
3416
|
-
printAgentSuccess(result,
|
|
4842
|
+
printAgentSuccess(result, outputOptions);
|
|
4843
|
+
} catch (error) {
|
|
4844
|
+
exitWithAgentError(error, outputOptions);
|
|
4845
|
+
}
|
|
4846
|
+
}
|
|
4847
|
+
)
|
|
4848
|
+
);
|
|
4849
|
+
const product = configureAgentParser2(
|
|
4850
|
+
agent.command("product").description("Shaped product reads")
|
|
4851
|
+
);
|
|
4852
|
+
configureAgentParser2(
|
|
4853
|
+
product.command("detail").description("Get shaped product detail by slug or ID").option("--slug <slug>", "Product slug").option("--id <id>", "Product ID").option("--market <market>", "Market slug").option("--locale <locale>", "Locale: ko, en, or all").option("--fallback-locale <locale>", "Fallback locale: ko, en, or none").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4854
|
+
"--output-file <path>",
|
|
4855
|
+
"Write success JSON to a secure file and print a receipt"
|
|
4856
|
+
).action(
|
|
4857
|
+
async (opts, command) => {
|
|
4858
|
+
const outputOptions = resolveAgentPrintOptions(command);
|
|
4859
|
+
try {
|
|
4860
|
+
validateAgentOutputTarget(outputOptions);
|
|
4861
|
+
const params = productDetailParamsFromOptions(opts);
|
|
4862
|
+
const client = getClient2();
|
|
4863
|
+
const result = await client.commerce.product.detail(params);
|
|
4864
|
+
printAgentSuccess(result, outputOptions);
|
|
3417
4865
|
} catch (error) {
|
|
3418
|
-
exitWithAgentError(error,
|
|
4866
|
+
exitWithAgentError(error, outputOptions);
|
|
3419
4867
|
}
|
|
3420
4868
|
}
|
|
3421
4869
|
)
|
|
@@ -3445,7 +4893,7 @@ registerOrderCommands(program, getClient, getFormat);
|
|
|
3445
4893
|
registerReturnCommands(program, getClient, getFormat);
|
|
3446
4894
|
registerCartCommands(program, getClient, getFormat);
|
|
3447
4895
|
registerStockCommands(program, getClient, getFormat);
|
|
3448
|
-
|
|
4896
|
+
registerCommerceSessionCommands(program, getClient, getFormat);
|
|
3449
4897
|
registerProductCommands(program, getClient, getFormat);
|
|
3450
4898
|
registerDiscountCommands(program, getClient, getFormat);
|
|
3451
4899
|
registerShippingCommands(program, getClient, getFormat);
|