@01.software/cli 0.17.3 → 0.18.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 +1371 -235
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import {
|
|
4
|
+
import { realpathSync } from "fs";
|
|
5
|
+
import { createRequire as createRequire2 } from "module";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
5
7
|
import { Command } from "commander";
|
|
6
8
|
|
|
7
9
|
// src/lib/client.ts
|
|
@@ -11,6 +13,373 @@ import {
|
|
|
11
13
|
TenantIntrospectionApi
|
|
12
14
|
} from "@01.software/sdk/server";
|
|
13
15
|
|
|
16
|
+
// ../../internal/http-contracts/src/index.ts
|
|
17
|
+
var operationBrand = /* @__PURE__ */ Symbol("sdk-http-operation");
|
|
18
|
+
var operation = (collection, method, path2, errorFamily) => Object.freeze({
|
|
19
|
+
[operationBrand]: true,
|
|
20
|
+
collection,
|
|
21
|
+
method,
|
|
22
|
+
path: path2,
|
|
23
|
+
...errorFamily && { errorFamily }
|
|
24
|
+
});
|
|
25
|
+
var strictCommerceOperation = (collection, method, path2) => operation(collection, method, path2, "commerce");
|
|
26
|
+
var selectiveCommerceOperation = (collection, method, path2, typedCommerceErrorReasons) => Object.freeze({
|
|
27
|
+
...operation(collection, method, path2),
|
|
28
|
+
typedCommerceErrorReasons: Object.freeze([...typedCommerceErrorReasons])
|
|
29
|
+
});
|
|
30
|
+
var COMMERCE_ENDPOINT_OPERATIONS = {
|
|
31
|
+
products: {
|
|
32
|
+
detail: operation("products", "get", "/detail"),
|
|
33
|
+
detailCatalog: operation("products", "get", "/detail/catalog"),
|
|
34
|
+
listingGroups: operation("products", "get", "/listing-groups"),
|
|
35
|
+
listingGroupsCatalog: operation(
|
|
36
|
+
"products",
|
|
37
|
+
"get",
|
|
38
|
+
"/listing-groups/catalog"
|
|
39
|
+
),
|
|
40
|
+
listingGroupsQuery: operation("products", "post", "/listing-groups/query"),
|
|
41
|
+
listingGroupsQueryGet: operation(
|
|
42
|
+
"products",
|
|
43
|
+
"get",
|
|
44
|
+
"/listing-groups/query"
|
|
45
|
+
),
|
|
46
|
+
listingGroupsQueryCatalog: operation(
|
|
47
|
+
"products",
|
|
48
|
+
"get",
|
|
49
|
+
"/listing-groups/query/catalog"
|
|
50
|
+
),
|
|
51
|
+
stockCheck: operation("products", "post", "/stock-check"),
|
|
52
|
+
stockSnapshot: operation("products", "get", "/stock"),
|
|
53
|
+
upsert: operation("products", "post", "/upsert")
|
|
54
|
+
},
|
|
55
|
+
orders: {
|
|
56
|
+
create: operation("orders", "post", "/create"),
|
|
57
|
+
update: operation("orders", "post", "/update"),
|
|
58
|
+
confirmPayment: operation("orders", "post", "/confirm-payment"),
|
|
59
|
+
byPayment: operation("orders", "get", "/by-payment"),
|
|
60
|
+
cancel: operation("orders", "post", "/cancel"),
|
|
61
|
+
resolveCancelRefund: selectiveCommerceOperation(
|
|
62
|
+
"orders",
|
|
63
|
+
"post",
|
|
64
|
+
"/resolve-cancel-refund",
|
|
65
|
+
["managed_refund_attestation_forbidden"]
|
|
66
|
+
),
|
|
67
|
+
checkout: strictCommerceOperation("orders", "post", "/checkout"),
|
|
68
|
+
createFulfillment: operation("orders", "post", "/create-fulfillment"),
|
|
69
|
+
updateFulfillment: operation("orders", "post", "/update-fulfillment")
|
|
70
|
+
},
|
|
71
|
+
checkouts: {
|
|
72
|
+
detail: strictCommerceOperation("checkouts", "post", "/detail"),
|
|
73
|
+
query: strictCommerceOperation("checkouts", "post", "/query")
|
|
74
|
+
},
|
|
75
|
+
transactions: {
|
|
76
|
+
update: operation("transactions", "post", "/update")
|
|
77
|
+
},
|
|
78
|
+
returns: {
|
|
79
|
+
create: operation("returns", "post", "/create"),
|
|
80
|
+
update: operation("returns", "post", "/update"),
|
|
81
|
+
returnRefund: operation("returns", "post", "/return-refund")
|
|
82
|
+
},
|
|
83
|
+
fulfillmentOrders: {
|
|
84
|
+
prepare: operation(
|
|
85
|
+
"fulfillment-orders",
|
|
86
|
+
"post",
|
|
87
|
+
"/prepare-fulfillment-order"
|
|
88
|
+
)
|
|
89
|
+
},
|
|
90
|
+
fulfillments: {
|
|
91
|
+
bulkImport: operation("fulfillments", "post", "/bulk-import")
|
|
92
|
+
},
|
|
93
|
+
carts: {
|
|
94
|
+
create: strictCommerceOperation("carts", "post", "/create"),
|
|
95
|
+
retrieve: strictCommerceOperation("carts", "post", "/retrieve"),
|
|
96
|
+
mine: strictCommerceOperation("carts", "post", "/mine"),
|
|
97
|
+
merge: strictCommerceOperation("carts", "post", "/merge"),
|
|
98
|
+
addItem: strictCommerceOperation("carts", "post", "/add-item"),
|
|
99
|
+
updateItem: strictCommerceOperation("carts", "post", "/update-item"),
|
|
100
|
+
removeItem: strictCommerceOperation("carts", "post", "/remove-item"),
|
|
101
|
+
updateDiscountCodes: strictCommerceOperation(
|
|
102
|
+
"carts",
|
|
103
|
+
"post",
|
|
104
|
+
"/update-discount-codes"
|
|
105
|
+
),
|
|
106
|
+
updateAttributes: strictCommerceOperation(
|
|
107
|
+
"carts",
|
|
108
|
+
"post",
|
|
109
|
+
"/update-attributes"
|
|
110
|
+
),
|
|
111
|
+
clear: strictCommerceOperation("carts", "post", "/clear")
|
|
112
|
+
},
|
|
113
|
+
paymentSessions: {
|
|
114
|
+
create: strictCommerceOperation("payment-sessions", "post", "/create"),
|
|
115
|
+
retrieve: strictCommerceOperation("payment-sessions", "post", "/retrieve"),
|
|
116
|
+
cancel: strictCommerceOperation("payment-sessions", "post", "/cancel"),
|
|
117
|
+
server: {
|
|
118
|
+
create: strictCommerceOperation(
|
|
119
|
+
"payment-sessions",
|
|
120
|
+
"post",
|
|
121
|
+
"/server/create"
|
|
122
|
+
),
|
|
123
|
+
retrieve: strictCommerceOperation(
|
|
124
|
+
"payment-sessions",
|
|
125
|
+
"post",
|
|
126
|
+
"/server/retrieve"
|
|
127
|
+
),
|
|
128
|
+
cancel: strictCommerceOperation(
|
|
129
|
+
"payment-sessions",
|
|
130
|
+
"post",
|
|
131
|
+
"/server/cancel"
|
|
132
|
+
),
|
|
133
|
+
confirm: strictCommerceOperation(
|
|
134
|
+
"payment-sessions",
|
|
135
|
+
"post",
|
|
136
|
+
"/server/confirm"
|
|
137
|
+
),
|
|
138
|
+
findPortOne: strictCommerceOperation(
|
|
139
|
+
"payment-sessions",
|
|
140
|
+
"post",
|
|
141
|
+
"/server/portone/find"
|
|
142
|
+
),
|
|
143
|
+
reconcilePortOne: strictCommerceOperation(
|
|
144
|
+
"payment-sessions",
|
|
145
|
+
"post",
|
|
146
|
+
"/server/portone/reconcile"
|
|
147
|
+
)
|
|
148
|
+
},
|
|
149
|
+
custom: {
|
|
150
|
+
create: operation("orders", "post", "/custom-payment-sessions"),
|
|
151
|
+
retrieve: operation(
|
|
152
|
+
"orders",
|
|
153
|
+
"post",
|
|
154
|
+
"/custom-payment-sessions/retrieve"
|
|
155
|
+
),
|
|
156
|
+
confirm: operation("orders", "post", "/custom-payment-sessions/confirm")
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
shippingPolicies: {
|
|
160
|
+
calculate: operation("shipping-policies", "post", "/calculate")
|
|
161
|
+
},
|
|
162
|
+
discounts: {
|
|
163
|
+
validate: operation("discounts", "post", "/validate")
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
var portOneStandardActionCapabilityOperations = /* @__PURE__ */ new Set([
|
|
167
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.create,
|
|
168
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.retrieve,
|
|
169
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.create,
|
|
170
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.server.retrieve
|
|
171
|
+
]);
|
|
172
|
+
var MEMBERSHIP_ENDPOINT_OPERATIONS = {
|
|
173
|
+
subscribe: operation(null, "post", "/memberships/subscribe"),
|
|
174
|
+
cancel: operation(null, "post", "/memberships/:id/cancel"),
|
|
175
|
+
me: operation(null, "get", "/memberships/me")
|
|
176
|
+
};
|
|
177
|
+
var EMBEDDED_ADMIN_ENDPOINT_OPERATIONS = {
|
|
178
|
+
show: operation("tenants", "get", "/embedded-admin-app"),
|
|
179
|
+
configure: operation("tenants", "patch", "/embedded-admin-app"),
|
|
180
|
+
disable: operation("tenants", "delete", "/embedded-admin-app")
|
|
181
|
+
};
|
|
182
|
+
var EVENTS_ENDPOINT_OPERATIONS = {
|
|
183
|
+
events: {
|
|
184
|
+
convertSchedule: operation("events", "post", "/:id/schedule")
|
|
185
|
+
},
|
|
186
|
+
occurrences: {
|
|
187
|
+
range: operation("event-occurrences", "get", "/range"),
|
|
188
|
+
admissionAvailability: operation(
|
|
189
|
+
"event-occurrences",
|
|
190
|
+
"get",
|
|
191
|
+
"/admission-availability"
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
var COMMUNITY_ENDPOINT_OPERATIONS = {
|
|
196
|
+
posts: {
|
|
197
|
+
detail: operation("posts", "get", "/detail")
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
function resolveOperationTemplate(descriptor) {
|
|
201
|
+
return descriptor.collection ? `/api/${descriptor.collection}${descriptor.path}` : `/api${descriptor.path}`;
|
|
202
|
+
}
|
|
203
|
+
function resolveOperationPath(descriptor, options) {
|
|
204
|
+
const path2 = resolveOperationTemplate(descriptor).replace(
|
|
205
|
+
/:([A-Za-z][A-Za-z0-9_]*)/g,
|
|
206
|
+
(_, key) => {
|
|
207
|
+
const value = options?.pathParams?.[key];
|
|
208
|
+
if (value === void 0) {
|
|
209
|
+
throw new TypeError(`Missing path parameter: ${key}`);
|
|
210
|
+
}
|
|
211
|
+
return encodeURIComponent(value);
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
const unresolved = path2.match(/:([A-Za-z][A-Za-z0-9_]*)/);
|
|
215
|
+
if (unresolved) {
|
|
216
|
+
throw new TypeError(`Missing path parameter: ${unresolved[1]}`);
|
|
217
|
+
}
|
|
218
|
+
const query = options?.query?.toString().replace(/^\?/, "");
|
|
219
|
+
return query ? `${path2}?${query}` : path2;
|
|
220
|
+
}
|
|
221
|
+
function resolveOperationMethod(descriptor) {
|
|
222
|
+
return descriptor.method.toUpperCase();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// src/lib/embedded-admin-management.ts
|
|
226
|
+
import {
|
|
227
|
+
normalizeEmbeddedAdminBindingConfiguration
|
|
228
|
+
} from "@01.software/sdk/embedded-admin";
|
|
229
|
+
var REQUEST_TIMEOUT_MS = 3e4;
|
|
230
|
+
var EmbeddedAdminManagementError = class extends Error {
|
|
231
|
+
constructor(message, status, options = {}) {
|
|
232
|
+
super(message);
|
|
233
|
+
this.name = "EmbeddedAdminManagementError";
|
|
234
|
+
this.status = status;
|
|
235
|
+
this.reason = options.reason;
|
|
236
|
+
this.requestId = options.requestId;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
function resolveApiUrl(explicit) {
|
|
240
|
+
const buildDefault = true ? "https://api.01.software" : "https://api.01.software";
|
|
241
|
+
return (explicit ?? process.env.SOFTWARE_API_URL ?? process.env.NEXT_PUBLIC_SOFTWARE_API_URL ?? buildDefault).replace(/\/$/, "");
|
|
242
|
+
}
|
|
243
|
+
function inferConsoleOrigin(apiUrl) {
|
|
244
|
+
const url = new URL(apiUrl);
|
|
245
|
+
if (url.hostname === "api.01.software") {
|
|
246
|
+
return {
|
|
247
|
+
allowLoopbackConsoleHttp: false,
|
|
248
|
+
consoleOrigin: "https://console.01.software"
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
if (url.hostname === "api.stg.01.software") {
|
|
252
|
+
return {
|
|
253
|
+
allowLoopbackConsoleHttp: false,
|
|
254
|
+
consoleOrigin: "https://console.stg.01.software"
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
const loopback = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]";
|
|
258
|
+
return {
|
|
259
|
+
allowLoopbackConsoleHttp: loopback && url.protocol === "http:",
|
|
260
|
+
...loopback ? { consoleOrigin: url.origin } : {}
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function parseBindingState(value) {
|
|
264
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
265
|
+
throw new Error("Embedded admin binding response is invalid.");
|
|
266
|
+
}
|
|
267
|
+
const input = value;
|
|
268
|
+
if (typeof input.tenantId !== "string" || input.tenantId.length === 0 || typeof input.tenantName !== "string" || input.status !== "unconfigured" && input.status !== "disabled" && input.status !== "enabled" && input.status !== "invalid") {
|
|
269
|
+
throw new Error("Embedded admin binding response is invalid.");
|
|
270
|
+
}
|
|
271
|
+
if (input.status === "unconfigured" || input.status === "invalid") {
|
|
272
|
+
if (input.binding !== null) {
|
|
273
|
+
throw new Error("Embedded admin binding response is invalid.");
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
binding: null,
|
|
277
|
+
status: input.status,
|
|
278
|
+
tenantId: input.tenantId,
|
|
279
|
+
tenantName: input.tenantName
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
const binding = normalizeEmbeddedAdminBindingConfiguration(input.binding);
|
|
283
|
+
if (binding.enabled !== (input.status === "enabled")) {
|
|
284
|
+
throw new Error("Embedded admin binding response is invalid.");
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
binding,
|
|
288
|
+
status: input.status,
|
|
289
|
+
tenantId: input.tenantId,
|
|
290
|
+
tenantName: input.tenantName
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
var EmbeddedAdminManagementClient = class {
|
|
294
|
+
constructor(options) {
|
|
295
|
+
this.apiUrl = resolveApiUrl(options.apiUrl);
|
|
296
|
+
this.fetchImplementation = options.fetch ?? globalThis.fetch;
|
|
297
|
+
this.publishableKey = options.publishableKey;
|
|
298
|
+
this.secretKey = options.secretKey;
|
|
299
|
+
}
|
|
300
|
+
validateConfiguration(input) {
|
|
301
|
+
this.validateManagementAccess();
|
|
302
|
+
const console2 = inferConsoleOrigin(this.apiUrl);
|
|
303
|
+
return normalizeEmbeddedAdminBindingConfiguration(
|
|
304
|
+
{ ...input, enabled: true, path: input.path ?? "/" },
|
|
305
|
+
console2
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
show() {
|
|
309
|
+
this.validateManagementAccess();
|
|
310
|
+
return this.request(EMBEDDED_ADMIN_ENDPOINT_OPERATIONS.show);
|
|
311
|
+
}
|
|
312
|
+
configure(input) {
|
|
313
|
+
const binding = this.validateConfiguration(input);
|
|
314
|
+
return this.request(EMBEDDED_ADMIN_ENDPOINT_OPERATIONS.configure, {
|
|
315
|
+
label: binding.label,
|
|
316
|
+
origin: binding.origin,
|
|
317
|
+
path: binding.path
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
disable() {
|
|
321
|
+
this.validateManagementAccess();
|
|
322
|
+
return this.request(EMBEDDED_ADMIN_ENDPOINT_OPERATIONS.disable);
|
|
323
|
+
}
|
|
324
|
+
validateManagementAccess() {
|
|
325
|
+
if (!this.secretKey.startsWith("pat01_")) {
|
|
326
|
+
const error = new Error(
|
|
327
|
+
"Embedded admin binding management requires a user PAT (pat01_...)."
|
|
328
|
+
);
|
|
329
|
+
error.name = "ConfigError";
|
|
330
|
+
throw error;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
async request(operation2, body) {
|
|
334
|
+
const controller = new AbortController();
|
|
335
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
336
|
+
let response;
|
|
337
|
+
try {
|
|
338
|
+
response = await this.fetchImplementation(
|
|
339
|
+
new URL(resolveOperationPath(operation2), `${this.apiUrl}/`),
|
|
340
|
+
{
|
|
341
|
+
method: resolveOperationMethod(operation2),
|
|
342
|
+
headers: {
|
|
343
|
+
Accept: "application/json",
|
|
344
|
+
Authorization: `Bearer ${this.secretKey}`,
|
|
345
|
+
"Content-Type": "application/json",
|
|
346
|
+
"X-Publishable-Key": this.publishableKey
|
|
347
|
+
},
|
|
348
|
+
...body === void 0 ? {} : { body: JSON.stringify(body) },
|
|
349
|
+
signal: controller.signal
|
|
350
|
+
}
|
|
351
|
+
);
|
|
352
|
+
} catch (cause) {
|
|
353
|
+
const error = new Error(
|
|
354
|
+
"Embedded admin binding request failed."
|
|
355
|
+
);
|
|
356
|
+
error.cause = cause;
|
|
357
|
+
error.name = "NetworkError";
|
|
358
|
+
throw error;
|
|
359
|
+
} finally {
|
|
360
|
+
clearTimeout(timer);
|
|
361
|
+
}
|
|
362
|
+
let payload;
|
|
363
|
+
try {
|
|
364
|
+
payload = await response.json();
|
|
365
|
+
} catch {
|
|
366
|
+
payload = null;
|
|
367
|
+
}
|
|
368
|
+
if (!response.ok) {
|
|
369
|
+
const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
370
|
+
throw new EmbeddedAdminManagementError(
|
|
371
|
+
typeof record.error === "string" ? record.error : `Embedded admin binding request failed (${response.status}).`,
|
|
372
|
+
response.status,
|
|
373
|
+
{
|
|
374
|
+
...typeof record.reason === "string" ? { reason: record.reason } : {},
|
|
375
|
+
...response.headers.get("x-request-id") ? { requestId: response.headers.get("x-request-id") } : {}
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
return parseBindingState(payload);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
|
|
14
383
|
// src/lib/credentials.ts
|
|
15
384
|
import {
|
|
16
385
|
chmodSync,
|
|
@@ -573,7 +942,10 @@ function adminErrorExitCode(err) {
|
|
|
573
942
|
}
|
|
574
943
|
|
|
575
944
|
// src/lib/i18n.ts
|
|
576
|
-
|
|
945
|
+
function withDoctorActionTranslations(translations) {
|
|
946
|
+
return translations;
|
|
947
|
+
}
|
|
948
|
+
var CLI_I18N_KO = withDoctorActionTranslations({
|
|
577
949
|
// CLI-surface microcopy
|
|
578
950
|
AuthenticationRequired: "\uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4",
|
|
579
951
|
RunLoginToAuthenticate: "`01 login` \uBA85\uB839\uC73C\uB85C \uBE0C\uB77C\uC6B0\uC800 \uC778\uC99D\uC744 \uC9C4\uD589\uD558\uAC70\uB098,",
|
|
@@ -587,6 +959,26 @@ var CLI_I18N_KO = {
|
|
|
587
959
|
Empty: "(\uC5C6\uC74C)",
|
|
588
960
|
Total: "\uCD1D {{n}}\uAC1C",
|
|
589
961
|
PageOf: "{{page}} / {{total}} \uD398\uC774\uC9C0",
|
|
962
|
+
// Redacted app-integration doctor remediation keys. These are stable
|
|
963
|
+
// machine references; the human CLI renders this locale-specific copy.
|
|
964
|
+
DoctorProjectPackageJsonReady: "package.json\uC744 \uC77D\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
965
|
+
DoctorProjectPackageJsonBlocked: "package.json\uC774 \uC788\uB294 \uC571 \uB514\uB809\uD130\uB9AC\uC5D0\uC11C \uC2E4\uD589\uD558\uC138\uC694.",
|
|
966
|
+
DoctorNodeEngineReady: "\uD604\uC7AC Node.js\uAC00 \uC120\uC5B8\uB41C engine\uC744 \uCDA9\uC871\uD569\uB2C8\uB2E4.",
|
|
967
|
+
DoctorNodeEngineAttention: "package.json\uC758 Node.js engine\uACFC \uD604\uC7AC \uBC84\uC804\uC744 \uD655\uC778\uD558\uC138\uC694.",
|
|
968
|
+
DoctorNodeEngineNotDeclared: "package.json\uC5D0 \uC9C0\uC6D0\uD558\uB294 Node.js engine \uBC94\uC704\uB97C \uC120\uC5B8\uD558\uC138\uC694.",
|
|
969
|
+
DoctorSdkDeclarationReady: "@01.software/sdk\uAC00 package.json\uC5D0 \uC120\uC5B8\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
970
|
+
DoctorSdkDeclarationBlocked: "package.json\uC5D0 @01.software/sdk\uB97C \uCD94\uAC00\uD558\uC138\uC694.",
|
|
971
|
+
DoctorSdkInstallationReady: "@01.software/sdk\uC758 server export\uB97C \uD655\uC778\uD588\uC2B5\uB2C8\uB2E4.",
|
|
972
|
+
DoctorSdkInstallationAttention: "\uC571\uC744 \uC2E4\uD589\uD558\uAE30 \uC804\uC5D0 \uC120\uC5B8\uB41C \uC758\uC874\uC131\uC744 \uC124\uCE58\uD558\uC138\uC694.",
|
|
973
|
+
DoctorEnvCredentialsReady: "\uC571 \uC790\uACA9\uC99D\uBA85 \uD615\uC2DD\uACFC API \uB300\uC0C1\uC774 \uC62C\uBC14\uB985\uB2C8\uB2E4.",
|
|
974
|
+
DoctorEnvCredentialsBlocked: "\uD558\uB098\uC758 pk01_/sk01_ \uC571 \uC30D\uC744 \uC0AC\uC6A9\uD558\uACE0 \uACF5\uAC1C \uD658\uACBD \uBCC0\uC218\uB098 PAT\uC5D0 secret\uC744 \uB123\uC9C0 \uB9C8\uC138\uC694.",
|
|
975
|
+
DoctorEnvFileInvalid: "\uC77C\uBC18 \uD30C\uC77C\uC778 \uC571 \uD658\uACBD \uD30C\uC77C\uC744 \uC9C0\uC815\uD558\uACE0 symlink\xB7\uD2B9\uC218 \uD30C\uC77C\uC744 \uC81C\uAC70\uD558\uC138\uC694.",
|
|
976
|
+
DoctorOriginInputInvalid: "\uC808\uB300 http(s) origin URL\uC744 \uC9C0\uC815\uD558\uC138\uC694.",
|
|
977
|
+
DoctorTenantContextReady: "\uC571 \uC790\uACA9\uC99D\uBA85\uC73C\uB85C \uD14C\uB10C\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8\uC5D0 \uC5F0\uACB0\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
978
|
+
DoctorTenantContextBlocked: "\uC571 \uC790\uACA9\uC99D\uBA85, \uD14C\uB10C\uD2B8 \uC811\uADFC \uAD8C\uD55C \uBC0F API \uC5F0\uACB0\uC744 \uD655\uC778\uD558\uC138\uC694.",
|
|
979
|
+
DoctorOriginCorsReady: "API CORS \uC815\uCC45\uC5D0\uC11C origin\uC774 \uD5C8\uC6A9\uB429\uB2C8\uB2E4.",
|
|
980
|
+
DoctorOriginCorsBlocked: "\uC774 origin\uC744 \uD14C\uB10C\uD2B8 CORS \uC815\uCC45\uC5D0 \uCD94\uAC00\uD558\uC138\uC694.",
|
|
981
|
+
DoctorOriginCorsAttention: "API URL \uBC0F CORS \uC815\uCC45\uC744 \uD655\uC778\uD558\uC138\uC694.",
|
|
590
982
|
// AdminError code translations (mirrors apps/console admin.ts).
|
|
591
983
|
tenant_mismatch: "\uAD8C\uD55C\uC774 \uC5C6\uB294 \uD14C\uB10C\uD2B8",
|
|
592
984
|
account_suspended: "\uACC4\uC815\uC774 \uC815\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
|
|
@@ -605,7 +997,7 @@ var CLI_I18N_KO = {
|
|
|
605
997
|
not_found: "\uB9AC\uC18C\uC2A4\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
|
|
606
998
|
invalid_argument: "\uC778\uC790\uAC00 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
|
|
607
999
|
unknown: "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"
|
|
608
|
-
};
|
|
1000
|
+
});
|
|
609
1001
|
var CLI_I18N_EN = {
|
|
610
1002
|
AuthenticationRequired: "Authentication required",
|
|
611
1003
|
RunLoginToAuthenticate: "Run `01 login` to authenticate via browser, or",
|
|
@@ -619,6 +1011,24 @@ var CLI_I18N_EN = {
|
|
|
619
1011
|
Empty: "(empty)",
|
|
620
1012
|
Total: "{{n}} total",
|
|
621
1013
|
PageOf: "page {{page}}/{{total}}",
|
|
1014
|
+
DoctorProjectPackageJsonReady: "package.json is readable.",
|
|
1015
|
+
DoctorProjectPackageJsonBlocked: "Run this command in an app directory with package.json.",
|
|
1016
|
+
DoctorNodeEngineReady: "Current Node.js satisfies the declared engine.",
|
|
1017
|
+
DoctorNodeEngineAttention: "Check the package.json Node.js engine and current version.",
|
|
1018
|
+
DoctorNodeEngineNotDeclared: "Declare a supported Node.js engine range in package.json.",
|
|
1019
|
+
DoctorSdkDeclarationReady: "@01.software/sdk is declared in package.json.",
|
|
1020
|
+
DoctorSdkDeclarationBlocked: "Add @01.software/sdk to package.json.",
|
|
1021
|
+
DoctorSdkInstallationReady: "@01.software/sdk server export is installed and resolvable.",
|
|
1022
|
+
DoctorSdkInstallationAttention: "Install declared dependencies before running the app.",
|
|
1023
|
+
DoctorEnvCredentialsReady: "App credentials and the API target are structurally valid.",
|
|
1024
|
+
DoctorEnvCredentialsBlocked: "Use one pk01_/sk01_ app pair; never put a secret in a public env variable or use a PAT.",
|
|
1025
|
+
DoctorEnvFileInvalid: "Use a regular app env file and remove symlinks or special files.",
|
|
1026
|
+
DoctorOriginInputInvalid: "Use an absolute http(s) origin URL.",
|
|
1027
|
+
DoctorTenantContextReady: "Tenant context is reachable with the app credential pair.",
|
|
1028
|
+
DoctorTenantContextBlocked: "Check app credentials, tenant access, and API reachability.",
|
|
1029
|
+
DoctorOriginCorsReady: "Origin is allowed by the API CORS policy.",
|
|
1030
|
+
DoctorOriginCorsBlocked: "Add this origin to the tenant CORS policy.",
|
|
1031
|
+
DoctorOriginCorsAttention: "Check the API URL and CORS policy.",
|
|
622
1032
|
tenant_mismatch: "Tenant access denied",
|
|
623
1033
|
account_suspended: "Your account has been suspended",
|
|
624
1034
|
feature_disabled: "This feature is disabled",
|
|
@@ -749,7 +1159,7 @@ function printError(error, options = {}) {
|
|
|
749
1159
|
const rawMessage = rawErr && typeof rawErr.message === "string" ? rawErr.message : "";
|
|
750
1160
|
const stringErr = typeof error === "string" ? error : "";
|
|
751
1161
|
const detailMessage = rawErr && rawErr.detail && typeof rawErr.detail === "object" && typeof rawErr.detail.message === "string" ? String(rawErr.detail.message) : "";
|
|
752
|
-
const headline = rawMessage || stringErr || detailMessage || localized || adminError.code;
|
|
1162
|
+
const headline = (options.headlineKey ? t(options.headlineKey) : null) || rawMessage || stringErr || detailMessage || localized || adminError.code;
|
|
753
1163
|
console.error(pc.red(`Error: ${headline}`));
|
|
754
1164
|
if (rawErr && typeof rawErr.code === "string" && rawErr.code !== adminError.code) {
|
|
755
1165
|
console.error(pc.dim(`Code: ${rawErr.code}`));
|
|
@@ -830,6 +1240,7 @@ function resolveClientOrThrow(apiKeyFlag) {
|
|
|
830
1240
|
),
|
|
831
1241
|
commerce: new ServerCommerceClient(serverOptions),
|
|
832
1242
|
tenant: new TenantIntrospectionApi(serverOptions),
|
|
1243
|
+
embeddedAdmin: new EmbeddedAdminManagementClient(serverOptions),
|
|
833
1244
|
publishableKey,
|
|
834
1245
|
secretKey
|
|
835
1246
|
};
|
|
@@ -929,15 +1340,15 @@ function readFileAsBlob(filePath) {
|
|
|
929
1340
|
const buffer = readFileSync2(filePath);
|
|
930
1341
|
return { blob: new Blob([buffer]), filename: basename(filePath) };
|
|
931
1342
|
}
|
|
932
|
-
function registerCrudCommands(
|
|
933
|
-
|
|
1343
|
+
function registerCrudCommands(program, getClient, getFormat) {
|
|
1344
|
+
program.command("query <collection>").description("Query documents from a collection").option("--where <json>", "Filter conditions (JSON)").option("--limit <n>", "Max results", (v) => parseInt(v, 10)).option("--page <n>", "Page number", (v) => parseInt(v, 10)).option("--sort <field>", "Sort field (prefix with - for descending)").option(
|
|
934
1345
|
"--depth <n>",
|
|
935
1346
|
"Relationship depth (0 = no population)",
|
|
936
1347
|
(v) => parseInt(v, 10)
|
|
937
1348
|
).option("--select <fields>", "Comma-separated fields to select").action(async (collection, opts) => {
|
|
938
1349
|
try {
|
|
939
1350
|
const col = validateCollection(collection);
|
|
940
|
-
const client =
|
|
1351
|
+
const client = getClient();
|
|
941
1352
|
const options = {};
|
|
942
1353
|
if (opts.where) options.where = parseJson(opts.where, "where");
|
|
943
1354
|
if (opts.limit) options.limit = opts.limit;
|
|
@@ -946,29 +1357,29 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
946
1357
|
if (opts.depth != null) options.depth = opts.depth;
|
|
947
1358
|
if (opts.select) options.select = parseSelect(opts.select);
|
|
948
1359
|
const result = await client.collections.from(col).find(options);
|
|
949
|
-
printResult(result,
|
|
1360
|
+
printResult(result, getFormat());
|
|
950
1361
|
} catch (e) {
|
|
951
1362
|
exitWithError(e);
|
|
952
1363
|
}
|
|
953
1364
|
});
|
|
954
|
-
|
|
1365
|
+
program.command("get <collection> <id>").description("Get a document by ID").option(
|
|
955
1366
|
"--depth <n>",
|
|
956
1367
|
"Relationship depth (0 = no population)",
|
|
957
1368
|
(v) => parseInt(v, 10)
|
|
958
1369
|
).option("--select <fields>", "Comma-separated fields to select").action(async (collection, id, opts) => {
|
|
959
1370
|
try {
|
|
960
1371
|
const col = validateCollection(collection);
|
|
961
|
-
const client =
|
|
1372
|
+
const client = getClient();
|
|
962
1373
|
const options = {};
|
|
963
1374
|
if (opts.depth != null) options.depth = opts.depth;
|
|
964
1375
|
if (opts.select) options.select = parseSelect(opts.select);
|
|
965
1376
|
const result = await client.collections.from(col).findById(id, options);
|
|
966
|
-
printResult(result,
|
|
1377
|
+
printResult(result, getFormat());
|
|
967
1378
|
} catch (e) {
|
|
968
1379
|
exitWithError(e);
|
|
969
1380
|
}
|
|
970
1381
|
});
|
|
971
|
-
|
|
1382
|
+
program.command("create <collection>").description("Create a new document").requiredOption("--data <json>", "Document data (JSON)").option("--file <path>", "File to upload (for upload collections)").option("--dry-run", "Validate inputs without executing").action(async (collection, opts) => {
|
|
972
1383
|
try {
|
|
973
1384
|
const col = validateCollection(collection);
|
|
974
1385
|
const data = parseJson(opts.data, "data");
|
|
@@ -981,23 +1392,23 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
981
1392
|
collection: col,
|
|
982
1393
|
data
|
|
983
1394
|
},
|
|
984
|
-
|
|
1395
|
+
getFormat()
|
|
985
1396
|
);
|
|
986
1397
|
return;
|
|
987
1398
|
}
|
|
988
|
-
const client =
|
|
1399
|
+
const client = getClient();
|
|
989
1400
|
let fileOpts;
|
|
990
1401
|
if (opts.file) {
|
|
991
1402
|
const { blob, filename } = readFileAsBlob(opts.file);
|
|
992
1403
|
fileOpts = { file: blob, filename };
|
|
993
1404
|
}
|
|
994
1405
|
const result = await client.collections.from(col).create(data, fileOpts);
|
|
995
|
-
printResult(result,
|
|
1406
|
+
printResult(result, getFormat());
|
|
996
1407
|
} catch (e) {
|
|
997
1408
|
exitWithError(e);
|
|
998
1409
|
}
|
|
999
1410
|
});
|
|
1000
|
-
|
|
1411
|
+
program.command("update <collection> <id>").description("Update a document by ID").requiredOption("--data <json>", "Document data (JSON)").option("--file <path>", "File to upload (for upload collections)").option("--dry-run", "Validate inputs without executing").action(async (collection, id, opts) => {
|
|
1001
1412
|
try {
|
|
1002
1413
|
const col = validateCollection(collection);
|
|
1003
1414
|
const data = parseJson(opts.data, "data");
|
|
@@ -1011,23 +1422,23 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
1011
1422
|
id,
|
|
1012
1423
|
data
|
|
1013
1424
|
},
|
|
1014
|
-
|
|
1425
|
+
getFormat()
|
|
1015
1426
|
);
|
|
1016
1427
|
return;
|
|
1017
1428
|
}
|
|
1018
|
-
const client =
|
|
1429
|
+
const client = getClient();
|
|
1019
1430
|
let fileOpts;
|
|
1020
1431
|
if (opts.file) {
|
|
1021
1432
|
const { blob, filename } = readFileAsBlob(opts.file);
|
|
1022
1433
|
fileOpts = { file: blob, filename };
|
|
1023
1434
|
}
|
|
1024
1435
|
const result = await client.collections.from(col).update(id, data, fileOpts);
|
|
1025
|
-
printResult(result,
|
|
1436
|
+
printResult(result, getFormat());
|
|
1026
1437
|
} catch (e) {
|
|
1027
1438
|
exitWithError(e);
|
|
1028
1439
|
}
|
|
1029
1440
|
});
|
|
1030
|
-
|
|
1441
|
+
program.command("delete <collection> <id>").description("Delete a document by ID").option("--dry-run", "Validate inputs without executing").action(async (collection, id, opts) => {
|
|
1031
1442
|
try {
|
|
1032
1443
|
const col = validateCollection(collection);
|
|
1033
1444
|
if (opts.dryRun) {
|
|
@@ -1039,18 +1450,18 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
1039
1450
|
collection: col,
|
|
1040
1451
|
id
|
|
1041
1452
|
},
|
|
1042
|
-
|
|
1453
|
+
getFormat()
|
|
1043
1454
|
);
|
|
1044
1455
|
return;
|
|
1045
1456
|
}
|
|
1046
|
-
const client =
|
|
1457
|
+
const client = getClient();
|
|
1047
1458
|
const result = await client.collections.from(col).remove(id);
|
|
1048
|
-
printResult(result,
|
|
1459
|
+
printResult(result, getFormat());
|
|
1049
1460
|
} catch (e) {
|
|
1050
1461
|
exitWithError(e);
|
|
1051
1462
|
}
|
|
1052
1463
|
});
|
|
1053
|
-
|
|
1464
|
+
program.command("update-many <collection>").description("Update multiple documents matching a filter").requiredOption("--where <json>", "Filter conditions (JSON)").requiredOption("--data <json>", "Update data (JSON)").option("--dry-run", "Validate inputs without executing").action(async (collection, opts) => {
|
|
1054
1465
|
try {
|
|
1055
1466
|
const col = validateCollection(collection);
|
|
1056
1467
|
const where = parseJson(opts.where, "where");
|
|
@@ -1065,18 +1476,18 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
1065
1476
|
where,
|
|
1066
1477
|
data
|
|
1067
1478
|
},
|
|
1068
|
-
|
|
1479
|
+
getFormat()
|
|
1069
1480
|
);
|
|
1070
1481
|
return;
|
|
1071
1482
|
}
|
|
1072
|
-
const client =
|
|
1483
|
+
const client = getClient();
|
|
1073
1484
|
const result = await client.collections.from(col).updateMany(where, data);
|
|
1074
|
-
printResult(result,
|
|
1485
|
+
printResult(result, getFormat());
|
|
1075
1486
|
} catch (e) {
|
|
1076
1487
|
exitWithError(e);
|
|
1077
1488
|
}
|
|
1078
1489
|
});
|
|
1079
|
-
|
|
1490
|
+
program.command("delete-many <collection>").description("Delete multiple documents matching a filter").requiredOption("--where <json>", "Filter conditions (JSON)").option("--dry-run", "Validate inputs without executing").action(async (collection, opts) => {
|
|
1080
1491
|
try {
|
|
1081
1492
|
const col = validateCollection(collection);
|
|
1082
1493
|
const where = parseJson(opts.where, "where");
|
|
@@ -1089,13 +1500,13 @@ function registerCrudCommands(program2, getClient2, getFormat2) {
|
|
|
1089
1500
|
collection: col,
|
|
1090
1501
|
where
|
|
1091
1502
|
},
|
|
1092
|
-
|
|
1503
|
+
getFormat()
|
|
1093
1504
|
);
|
|
1094
1505
|
return;
|
|
1095
1506
|
}
|
|
1096
|
-
const client =
|
|
1507
|
+
const client = getClient();
|
|
1097
1508
|
const result = await client.collections.from(col).removeMany(where);
|
|
1098
|
-
printResult(result,
|
|
1509
|
+
printResult(result, getFormat());
|
|
1099
1510
|
} catch (e) {
|
|
1100
1511
|
exitWithError(e);
|
|
1101
1512
|
}
|
|
@@ -1923,13 +2334,25 @@ var PORTONE_HOSTED_PAYMENT_METHODS = [
|
|
|
1923
2334
|
var portOneHostedPaymentMethodSchema = z5.enum(
|
|
1924
2335
|
PORTONE_HOSTED_PAYMENT_METHODS
|
|
1925
2336
|
);
|
|
2337
|
+
var PORTONE_STANDARD_PAYMENT_METHODS = ["CARD"];
|
|
2338
|
+
var portOneStandardPaymentMethodSchema = z5.enum(
|
|
2339
|
+
PORTONE_STANDARD_PAYMENT_METHODS
|
|
2340
|
+
);
|
|
2341
|
+
var PORTONE_STANDARD_CURRENCY = "CURRENCY_KRW";
|
|
2342
|
+
var portOneStandardProviderOptionsSchema = z5.object({
|
|
2343
|
+
profile: z5.literal("standard_v2"),
|
|
2344
|
+
paymentMethod: portOneStandardPaymentMethodSchema
|
|
2345
|
+
}).strict();
|
|
1926
2346
|
var createPortOnePaymentSessionBodySchema = z5.object({
|
|
1927
2347
|
...createPaymentSessionBaseBodyShape,
|
|
1928
2348
|
provider: z5.literal("portone"),
|
|
1929
|
-
providerOptions: z5.
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
2349
|
+
providerOptions: z5.discriminatedUnion("profile", [
|
|
2350
|
+
z5.object({
|
|
2351
|
+
profile: z5.literal("hosted_v2"),
|
|
2352
|
+
paymentMethod: portOneHostedPaymentMethodSchema
|
|
2353
|
+
}).strict(),
|
|
2354
|
+
portOneStandardProviderOptionsSchema
|
|
2355
|
+
])
|
|
1933
2356
|
}).strict();
|
|
1934
2357
|
var createPaymentSessionBodySchema = z5.discriminatedUnion("provider", [
|
|
1935
2358
|
createTossPaymentSessionBodySchema,
|
|
@@ -1979,6 +2402,17 @@ var confirmTossPaymentSessionBodySchema = z5.object({
|
|
|
1979
2402
|
var confirmTossPaymentSessionParamsSchema = confirmTossPaymentSessionBodySchema.extend({
|
|
1980
2403
|
idempotencyKey: commerceIdempotencyKeySchema
|
|
1981
2404
|
});
|
|
2405
|
+
var portOneProviderIdentitySchema = z5.string().min(1).max(512).refine((value) => /\S/u.test(value), "Provider identity must not be blank");
|
|
2406
|
+
var portOnePaymentSelectorSchema = z5.object({
|
|
2407
|
+
provider: z5.literal("portone"),
|
|
2408
|
+
providerAccountKey: portOneProviderIdentitySchema,
|
|
2409
|
+
environment: z5.enum(["test", "live"]),
|
|
2410
|
+
providerPaymentId: portOneProviderIdentitySchema
|
|
2411
|
+
}).strict();
|
|
2412
|
+
var reconcilePortOnePaymentBodySchema = portOnePaymentSelectorSchema;
|
|
2413
|
+
var reconcilePortOnePaymentParamsSchema = reconcilePortOnePaymentBodySchema.extend({
|
|
2414
|
+
idempotencyKey: commerceIdempotencyKeySchema
|
|
2415
|
+
});
|
|
1982
2416
|
var PAYMENT_PROVIDER_STATUSES = [
|
|
1983
2417
|
"requires_payment_method",
|
|
1984
2418
|
"requires_action",
|
|
@@ -2047,6 +2481,15 @@ var confirmCustomPaymentSessionResponseSchema = z5.object({
|
|
|
2047
2481
|
status: z5.literal("paid"),
|
|
2048
2482
|
alreadyConfirmed: z5.boolean().optional()
|
|
2049
2483
|
}).strict();
|
|
2484
|
+
var PORTONE_RECONCILIATION_DISPOSITIONS = [
|
|
2485
|
+
"applied",
|
|
2486
|
+
"observed",
|
|
2487
|
+
"recovered_after_ambiguous_result",
|
|
2488
|
+
"requires_attention"
|
|
2489
|
+
];
|
|
2490
|
+
var portOneReconciliationDispositionSchema = z5.enum(
|
|
2491
|
+
PORTONE_RECONCILIATION_DISPOSITIONS
|
|
2492
|
+
);
|
|
2050
2493
|
var tossPaymentNextActionSchema = z5.object({
|
|
2051
2494
|
type: z5.literal("toss_widget"),
|
|
2052
2495
|
clientKey: z5.string().min(1).max(255),
|
|
@@ -2065,9 +2508,41 @@ var portOnePaymentNextActionSchema = z5.object({
|
|
|
2065
2508
|
return url.username === "" && url.password === "";
|
|
2066
2509
|
}, "checkoutUrl must not contain embedded credentials")
|
|
2067
2510
|
}).strict();
|
|
2068
|
-
var
|
|
2511
|
+
var PORTONE_STANDARD_ACTION_RETRY_POLICY = "same_action_only";
|
|
2512
|
+
var portOneSdkPaymentRequestSchema = z5.object({
|
|
2513
|
+
type: z5.literal("portone_sdk"),
|
|
2514
|
+
version: z5.literal("v2"),
|
|
2515
|
+
storeId: z5.string().min(1).max(255),
|
|
2516
|
+
channelKey: z5.string().min(1).max(255),
|
|
2517
|
+
paymentId: z5.string().regex(/^[A-Za-z0-9]{6,40}$/),
|
|
2518
|
+
orderName: z5.string().min(1).max(200),
|
|
2519
|
+
totalAmount: z5.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
2520
|
+
currency: z5.literal(PORTONE_STANDARD_CURRENCY),
|
|
2521
|
+
payMethod: portOneStandardPaymentMethodSchema,
|
|
2522
|
+
redirectUrl: z5.string().url().max(2048).refine((value) => {
|
|
2523
|
+
const url = new URL(value);
|
|
2524
|
+
const loopback = url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1");
|
|
2525
|
+
return (url.protocol === "https:" || loopback) && !url.username && !url.password;
|
|
2526
|
+
}, "redirectUrl must be HTTPS (or development loopback) without embedded credentials")
|
|
2527
|
+
}).strict();
|
|
2528
|
+
var portOneSdkPaymentCapabilityNextActionSchema = portOneSdkPaymentRequestSchema.extend({
|
|
2529
|
+
cancelable: z5.literal(false),
|
|
2530
|
+
retryPolicy: z5.literal(PORTONE_STANDARD_ACTION_RETRY_POLICY)
|
|
2531
|
+
}).strict();
|
|
2532
|
+
var portOneSdkPaymentNextActionSchema = z5.union([
|
|
2533
|
+
portOneSdkPaymentCapabilityNextActionSchema,
|
|
2534
|
+
portOneSdkPaymentRequestSchema
|
|
2535
|
+
]).transform(
|
|
2536
|
+
(action) => "cancelable" in action ? action : {
|
|
2537
|
+
...action,
|
|
2538
|
+
cancelable: false,
|
|
2539
|
+
retryPolicy: PORTONE_STANDARD_ACTION_RETRY_POLICY
|
|
2540
|
+
}
|
|
2541
|
+
);
|
|
2542
|
+
var paymentNextActionSchema = z5.union([
|
|
2069
2543
|
tossPaymentNextActionSchema,
|
|
2070
|
-
portOnePaymentNextActionSchema
|
|
2544
|
+
portOnePaymentNextActionSchema,
|
|
2545
|
+
portOneSdkPaymentNextActionSchema
|
|
2071
2546
|
]);
|
|
2072
2547
|
var PAYMENT_SESSION_ROLES = [
|
|
2073
2548
|
"active",
|
|
@@ -2277,9 +2752,56 @@ function providerSessionSchemas(provider, action) {
|
|
|
2277
2752
|
}
|
|
2278
2753
|
var publicPaymentSessionVariants = [
|
|
2279
2754
|
...providerSessionSchemas("toss", tossPaymentNextActionSchema),
|
|
2280
|
-
...providerSessionSchemas(
|
|
2755
|
+
...providerSessionSchemas(
|
|
2756
|
+
"portone",
|
|
2757
|
+
z5.union([
|
|
2758
|
+
portOnePaymentNextActionSchema,
|
|
2759
|
+
portOneSdkPaymentNextActionSchema
|
|
2760
|
+
])
|
|
2761
|
+
)
|
|
2281
2762
|
];
|
|
2282
2763
|
var publicPaymentSessionSchema = z5.union(publicPaymentSessionVariants);
|
|
2764
|
+
var portOneReconciliationSummarySchema = z5.union([
|
|
2765
|
+
noReconciliationSchema,
|
|
2766
|
+
z5.object({
|
|
2767
|
+
status: z5.literal("required"),
|
|
2768
|
+
reasons: z5.array(paymentReconciliationReasonSchema).min(1).readonly()
|
|
2769
|
+
}).strict()
|
|
2770
|
+
]);
|
|
2771
|
+
var portOnePaymentCurrentStateSchema = z5.object({
|
|
2772
|
+
paymentSession: z5.object({
|
|
2773
|
+
id: commerceResourceIdSchema,
|
|
2774
|
+
provider: z5.literal("portone"),
|
|
2775
|
+
providerStatus: paymentProviderStatusSchema,
|
|
2776
|
+
finalizationStatus: z5.enum(["not_ready", "pending", "committed"]),
|
|
2777
|
+
sessionRole: paymentSessionRoleSchema,
|
|
2778
|
+
reconciliation: portOneReconciliationSummarySchema
|
|
2779
|
+
}).strict(),
|
|
2780
|
+
checkout: z5.object({ id: commerceResourceIdSchema }).strict(),
|
|
2781
|
+
order: orderReferenceSchema.nullable(),
|
|
2782
|
+
money: moneySchema
|
|
2783
|
+
}).strict();
|
|
2784
|
+
var findPortOnePaymentResultSchema = z5.discriminatedUnion("found", [
|
|
2785
|
+
z5.object({ found: z5.literal(false) }).strict(),
|
|
2786
|
+
z5.object({
|
|
2787
|
+
found: z5.literal(true),
|
|
2788
|
+
current: portOnePaymentCurrentStateSchema
|
|
2789
|
+
}).strict()
|
|
2790
|
+
]);
|
|
2791
|
+
var reconcilePortOnePaymentResultSchema = z5.discriminatedUnion(
|
|
2792
|
+
"found",
|
|
2793
|
+
[
|
|
2794
|
+
z5.object({
|
|
2795
|
+
found: z5.literal(false),
|
|
2796
|
+
disposition: z5.literal("requires_attention")
|
|
2797
|
+
}).strict(),
|
|
2798
|
+
z5.object({
|
|
2799
|
+
found: z5.literal(true),
|
|
2800
|
+
disposition: portOneReconciliationDispositionSchema,
|
|
2801
|
+
current: portOnePaymentCurrentStateSchema
|
|
2802
|
+
}).strict()
|
|
2803
|
+
]
|
|
2804
|
+
);
|
|
2283
2805
|
var CreatePaymentSessionParamsSchema = createPaymentSessionParamsSchema;
|
|
2284
2806
|
var CancelServerPaymentSessionParamsSchema = cancelServerPaymentSessionParamsSchema;
|
|
2285
2807
|
var ConfirmTossPaymentSessionParamsSchema = confirmTossPaymentSessionParamsSchema;
|
|
@@ -2332,9 +2854,10 @@ var checkoutAmountsSchema = z6.object({
|
|
|
2332
2854
|
});
|
|
2333
2855
|
}
|
|
2334
2856
|
});
|
|
2857
|
+
var CHECKOUT_PAYMENT_SESSION_PROVIDERS = ["toss", "portone"];
|
|
2335
2858
|
var checkoutPaymentSessionRefSchema = z6.object({
|
|
2336
2859
|
id: z6.string().min(1),
|
|
2337
|
-
provider: z6.
|
|
2860
|
+
provider: z6.enum(CHECKOUT_PAYMENT_SESSION_PROVIDERS),
|
|
2338
2861
|
providerStatus: paymentProviderStatusSchema
|
|
2339
2862
|
}).strict();
|
|
2340
2863
|
var openCheckoutPaymentStateSchema = z6.object({
|
|
@@ -2528,40 +3051,62 @@ var returnCancellationReasonCodeSchema = z7.enum(
|
|
|
2528
3051
|
RETURN_CANCELLATION_REASON_CODES
|
|
2529
3052
|
);
|
|
2530
3053
|
var restockActionSchema = z7.enum(["return_to_stock", "discard"]);
|
|
3054
|
+
var returnRefundMoneySchema = z7.number().int("amount must be an integer minor-unit value").safe("amount must be a safe integer").nonnegative("amount must be non-negative");
|
|
3055
|
+
var positiveReturnRefundMoneySchema = z7.number().int("amount must be an integer minor-unit value").safe("amount must be a safe integer").positive("amount must be positive");
|
|
3056
|
+
function trimmedReturnRefundScalarString(maxScalars, emptyMessage, maximumMessage) {
|
|
3057
|
+
return z7.string().trim().min(1, emptyMessage).refine((value) => Array.from(value).length <= maxScalars, maximumMessage);
|
|
3058
|
+
}
|
|
2531
3059
|
var returnWithRefundItemSchema = z7.object({
|
|
2532
|
-
orderItem: z7.union([z7.string().min(1), z7.number()]).transform(String),
|
|
2533
|
-
quantity: z7.number().int().positive("quantity must be a positive integer"),
|
|
3060
|
+
orderItem: z7.union([z7.string().trim().min(1), z7.number().int().safe().positive()]).transform(String),
|
|
3061
|
+
quantity: z7.number().int("quantity must be an integer").safe("quantity must be a safe integer").positive("quantity must be a positive integer"),
|
|
2534
3062
|
restockAction: restockActionSchema.default("return_to_stock"),
|
|
2535
|
-
restockingFee:
|
|
3063
|
+
restockingFee: returnRefundMoneySchema.optional().describe("Restocking fee charged for this line (ADR 0005 \xA7Gap 1)")
|
|
2536
3064
|
}).strict();
|
|
2537
3065
|
var returnWithRefundSchema = z7.object({
|
|
2538
|
-
orderNumber: z7.string().min(1, "orderNumber is required").describe("Order number (required)"),
|
|
3066
|
+
orderNumber: z7.string().trim().min(1, "orderNumber is required").describe("Order number (required)"),
|
|
2539
3067
|
reason: returnReasonSchema.optional().describe("Return reason (optional)"),
|
|
2540
|
-
reasonDetail:
|
|
3068
|
+
reasonDetail: trimmedReturnRefundScalarString(
|
|
3069
|
+
2e3,
|
|
3070
|
+
"reasonDetail must not be empty",
|
|
3071
|
+
"reasonDetail must be 2000 Unicode code points or fewer"
|
|
3072
|
+
).optional().describe("Detailed reason text (optional)"),
|
|
2541
3073
|
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)"),
|
|
2542
|
-
refundAmount:
|
|
2543
|
-
|
|
3074
|
+
refundAmount: positiveReturnRefundMoneySchema.describe(
|
|
3075
|
+
"Refund amount (required, min 1)"
|
|
3076
|
+
),
|
|
3077
|
+
returnShippingFee: returnRefundMoneySchema.optional().describe(
|
|
2544
3078
|
"Return shipping fee charged to the customer (ADR 0005 \xA7Gap 1)"
|
|
2545
3079
|
),
|
|
2546
|
-
initialShippingRefundAmount:
|
|
2547
|
-
initialShippingRefundOverrideNote:
|
|
3080
|
+
initialShippingRefundAmount: returnRefundMoneySchema.optional().describe("Initial order shipping amount refunded to the customer"),
|
|
3081
|
+
initialShippingRefundOverrideNote: trimmedReturnRefundScalarString(
|
|
3082
|
+
2e3,
|
|
3083
|
+
"initialShippingRefundOverrideNote must not be empty",
|
|
3084
|
+
"initialShippingRefundOverrideNote must be 2000 Unicode code points or fewer"
|
|
3085
|
+
).optional().describe(
|
|
2548
3086
|
"Operator audit note required when overriding policy suggestion"
|
|
2549
3087
|
),
|
|
2550
|
-
pgPaymentId: z7.string().min(1, "pgPaymentId is required").describe("PG payment ID for refund (required)"),
|
|
2551
|
-
paymentKey: z7.string().min(1).optional().describe("Provider payment key for verified refund"),
|
|
2552
|
-
refundReceiptUrl:
|
|
3088
|
+
pgPaymentId: z7.string().trim().min(1, "pgPaymentId is required").describe("PG payment ID for refund (required)"),
|
|
3089
|
+
paymentKey: z7.string().trim().min(1).optional().describe("Provider payment key for verified refund"),
|
|
3090
|
+
refundReceiptUrl: trimmedReturnRefundScalarString(
|
|
3091
|
+
2048,
|
|
3092
|
+
"refundReceiptUrl must not be empty",
|
|
3093
|
+
"refundReceiptUrl must be 2048 Unicode code points or fewer"
|
|
3094
|
+
).optional().describe("Refund receipt URL (optional)")
|
|
2553
3095
|
}).strict();
|
|
2554
3096
|
var createReturnSchema = z7.object({
|
|
2555
3097
|
orderNumber: z7.string().min(1, "orderNumber is required").describe("Order number (required)"),
|
|
2556
3098
|
reason: returnReasonSchema.optional().describe("Return reason (optional)"),
|
|
2557
|
-
reasonDetail: z7.string().optional().describe("Detailed reason text (optional)"),
|
|
3099
|
+
reasonDetail: z7.string().max(2e3, "reasonDetail must be 2000 characters or fewer").optional().describe("Detailed reason text (optional)"),
|
|
2558
3100
|
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)"),
|
|
2559
|
-
refundAmount:
|
|
3101
|
+
refundAmount: returnRefundMoneySchema.describe(
|
|
2560
3102
|
"Line refund amount before initial shipping refund (required, min 0)"
|
|
2561
3103
|
),
|
|
2562
|
-
returnShippingFee:
|
|
2563
|
-
initialShippingRefundAmount:
|
|
2564
|
-
initialShippingRefundOverrideNote: z7.string().min(1).
|
|
3104
|
+
returnShippingFee: returnRefundMoneySchema.optional().describe("Return shipping fee charged to the customer"),
|
|
3105
|
+
initialShippingRefundAmount: returnRefundMoneySchema.optional().describe("Initial order shipping amount refunded to the customer"),
|
|
3106
|
+
initialShippingRefundOverrideNote: z7.string().min(1).max(
|
|
3107
|
+
2e3,
|
|
3108
|
+
"initialShippingRefundOverrideNote must be 2000 characters or fewer"
|
|
3109
|
+
).optional().describe(
|
|
2565
3110
|
"Operator audit note required when overriding policy suggestion"
|
|
2566
3111
|
)
|
|
2567
3112
|
}).strict();
|
|
@@ -2737,8 +3282,8 @@ var fulfillmentItemsSchema = z8.array(
|
|
|
2737
3282
|
quantity: z8.number().int().positive("quantity must be a positive integer")
|
|
2738
3283
|
}).strict()
|
|
2739
3284
|
).min(1, "At least one fulfillment item is required").max(100, "Maximum 100 items per fulfillment");
|
|
2740
|
-
function registerOrderCommands(
|
|
2741
|
-
const order =
|
|
3285
|
+
function registerOrderCommands(program, getClient, getFormat) {
|
|
3286
|
+
const order = program.command("order").description("Order management");
|
|
2742
3287
|
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) => {
|
|
2743
3288
|
try {
|
|
2744
3289
|
const status = parseWithSchema(opts.status, "status", orderStatusSchema);
|
|
@@ -2746,13 +3291,13 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
|
2746
3291
|
if (opts.dryRun) {
|
|
2747
3292
|
printResult(
|
|
2748
3293
|
{ dryRun: true, valid: true, action: "order update", data },
|
|
2749
|
-
|
|
3294
|
+
getFormat()
|
|
2750
3295
|
);
|
|
2751
3296
|
return;
|
|
2752
3297
|
}
|
|
2753
|
-
const client =
|
|
3298
|
+
const client = getClient();
|
|
2754
3299
|
const result = await client.commerce.orders.update(data);
|
|
2755
|
-
printResult(result,
|
|
3300
|
+
printResult(result, getFormat());
|
|
2756
3301
|
} catch (e) {
|
|
2757
3302
|
exitWithError(e);
|
|
2758
3303
|
}
|
|
@@ -2774,13 +3319,13 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
|
2774
3319
|
if (opts.dryRun) {
|
|
2775
3320
|
printResult(
|
|
2776
3321
|
{ dryRun: true, valid: true, action: "order cancel", data },
|
|
2777
|
-
|
|
3322
|
+
getFormat()
|
|
2778
3323
|
);
|
|
2779
3324
|
return;
|
|
2780
3325
|
}
|
|
2781
|
-
const client =
|
|
3326
|
+
const client = getClient();
|
|
2782
3327
|
const result = await client.commerce.orders.cancelOrder(data);
|
|
2783
|
-
printResult(result,
|
|
3328
|
+
printResult(result, getFormat());
|
|
2784
3329
|
} catch (e) {
|
|
2785
3330
|
exitWithError(e);
|
|
2786
3331
|
}
|
|
@@ -2791,13 +3336,13 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
|
2791
3336
|
if (opts.dryRun) {
|
|
2792
3337
|
printResult(
|
|
2793
3338
|
{ dryRun: true, valid: true, action: "order prepare", data },
|
|
2794
|
-
|
|
3339
|
+
getFormat()
|
|
2795
3340
|
);
|
|
2796
3341
|
return;
|
|
2797
3342
|
}
|
|
2798
|
-
const client =
|
|
3343
|
+
const client = getClient();
|
|
2799
3344
|
const result = await client.commerce.orders.prepareFulfillmentOrder(data);
|
|
2800
|
-
printResult(result,
|
|
3345
|
+
printResult(result, getFormat());
|
|
2801
3346
|
} catch (e) {
|
|
2802
3347
|
exitWithError(e);
|
|
2803
3348
|
}
|
|
@@ -2818,18 +3363,18 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
|
2818
3363
|
if (opts.dryRun) {
|
|
2819
3364
|
printResult(
|
|
2820
3365
|
{ dryRun: true, valid: true, action: "order fulfill", data },
|
|
2821
|
-
|
|
3366
|
+
getFormat()
|
|
2822
3367
|
);
|
|
2823
3368
|
return;
|
|
2824
3369
|
}
|
|
2825
|
-
const client =
|
|
3370
|
+
const client = getClient();
|
|
2826
3371
|
const result = await client.commerce.orders.createFulfillment({
|
|
2827
3372
|
...data,
|
|
2828
3373
|
...items ? {
|
|
2829
3374
|
items
|
|
2830
3375
|
} : {}
|
|
2831
3376
|
});
|
|
2832
|
-
printResult(result,
|
|
3377
|
+
printResult(result, getFormat());
|
|
2833
3378
|
} catch (e) {
|
|
2834
3379
|
exitWithError(e);
|
|
2835
3380
|
}
|
|
@@ -2854,13 +3399,13 @@ function registerOrderCommands(program2, getClient2, getFormat2) {
|
|
|
2854
3399
|
action: "order update-fulfillment",
|
|
2855
3400
|
data
|
|
2856
3401
|
},
|
|
2857
|
-
|
|
3402
|
+
getFormat()
|
|
2858
3403
|
);
|
|
2859
3404
|
return;
|
|
2860
3405
|
}
|
|
2861
|
-
const client =
|
|
3406
|
+
const client = getClient();
|
|
2862
3407
|
const result = await client.commerce.orders.updateFulfillment(data);
|
|
2863
|
-
printResult(result,
|
|
3408
|
+
printResult(result, getFormat());
|
|
2864
3409
|
} catch (e) {
|
|
2865
3410
|
exitWithError(e);
|
|
2866
3411
|
}
|
|
@@ -2875,8 +3420,8 @@ var returnStatusSchema = z9.enum([
|
|
|
2875
3420
|
"rejected",
|
|
2876
3421
|
"completed"
|
|
2877
3422
|
]);
|
|
2878
|
-
function registerReturnCommands(
|
|
2879
|
-
const ret =
|
|
3423
|
+
function registerReturnCommands(program, getClient, getFormat) {
|
|
3424
|
+
const ret = program.command("return").description("Return management");
|
|
2880
3425
|
ret.command("create <orderNumber>").description("Create a return request").requiredOption("--products <json>", "Return products array (JSON)").requiredOption("--refund-amount <n>", "Refund amount", parseFloat).option(
|
|
2881
3426
|
"--return-shipping-fee <n>",
|
|
2882
3427
|
"Return shipping fee charged to the customer",
|
|
@@ -2910,16 +3455,16 @@ function registerReturnCommands(program2, getClient2, getFormat2) {
|
|
|
2910
3455
|
if (opts.dryRun) {
|
|
2911
3456
|
printResult(
|
|
2912
3457
|
{ dryRun: true, valid: true, action: "return create", data },
|
|
2913
|
-
|
|
3458
|
+
getFormat()
|
|
2914
3459
|
);
|
|
2915
3460
|
return;
|
|
2916
3461
|
}
|
|
2917
|
-
const client =
|
|
3462
|
+
const client = getClient();
|
|
2918
3463
|
const result = await client.commerce.orders.createReturn({
|
|
2919
3464
|
...data,
|
|
2920
3465
|
returnItems: data.returnItems
|
|
2921
3466
|
});
|
|
2922
|
-
printResult(result,
|
|
3467
|
+
printResult(result, getFormat());
|
|
2923
3468
|
} catch (e) {
|
|
2924
3469
|
exitWithError(e);
|
|
2925
3470
|
}
|
|
@@ -2938,13 +3483,13 @@ function registerReturnCommands(program2, getClient2, getFormat2) {
|
|
|
2938
3483
|
if (opts.dryRun) {
|
|
2939
3484
|
printResult(
|
|
2940
3485
|
{ dryRun: true, valid: true, action: "return update", data },
|
|
2941
|
-
|
|
3486
|
+
getFormat()
|
|
2942
3487
|
);
|
|
2943
3488
|
return;
|
|
2944
3489
|
}
|
|
2945
|
-
const client =
|
|
3490
|
+
const client = getClient();
|
|
2946
3491
|
const result = await client.commerce.orders.updateReturn(data);
|
|
2947
|
-
printResult(result,
|
|
3492
|
+
printResult(result, getFormat());
|
|
2948
3493
|
} catch (e) {
|
|
2949
3494
|
exitWithError(e);
|
|
2950
3495
|
}
|
|
@@ -2982,16 +3527,16 @@ function registerReturnCommands(program2, getClient2, getFormat2) {
|
|
|
2982
3527
|
if (opts.dryRun) {
|
|
2983
3528
|
printResult(
|
|
2984
3529
|
{ dryRun: true, valid: true, action: "return refund", data },
|
|
2985
|
-
|
|
3530
|
+
getFormat()
|
|
2986
3531
|
);
|
|
2987
3532
|
return;
|
|
2988
3533
|
}
|
|
2989
|
-
const client =
|
|
3534
|
+
const client = getClient();
|
|
2990
3535
|
const result = await client.commerce.orders.returnWithRefund({
|
|
2991
3536
|
...data,
|
|
2992
3537
|
returnItems: data.returnItems
|
|
2993
3538
|
});
|
|
2994
|
-
printResult(result,
|
|
3539
|
+
printResult(result, getFormat());
|
|
2995
3540
|
} catch (e) {
|
|
2996
3541
|
exitWithError(e);
|
|
2997
3542
|
}
|
|
@@ -3076,8 +3621,8 @@ function sensitiveDryRunResult(action) {
|
|
|
3076
3621
|
}
|
|
3077
3622
|
|
|
3078
3623
|
// src/commands/cart.ts
|
|
3079
|
-
function registerCartCommands(
|
|
3080
|
-
const cart =
|
|
3624
|
+
function registerCartCommands(program, getClient, getFormat) {
|
|
3625
|
+
const cart = program.command("cart").description("Cart management");
|
|
3081
3626
|
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) => {
|
|
3082
3627
|
try {
|
|
3083
3628
|
const input = opts.dataStdin || opts.dataFile ? await readSensitiveJsonObject(opts) : {};
|
|
@@ -3087,10 +3632,10 @@ function registerCartCommands(program2, getClient2, getFormat2) {
|
|
|
3087
3632
|
createCartParamsSchema
|
|
3088
3633
|
);
|
|
3089
3634
|
if (opts.dryRun) {
|
|
3090
|
-
printResult(sensitiveDryRunResult("cart create"),
|
|
3635
|
+
printResult(sensitiveDryRunResult("cart create"), getFormat());
|
|
3091
3636
|
return;
|
|
3092
3637
|
}
|
|
3093
|
-
printResult(await
|
|
3638
|
+
printResult(await getClient().commerce.carts.create(data), getFormat());
|
|
3094
3639
|
} catch (error) {
|
|
3095
3640
|
exitWithError(error);
|
|
3096
3641
|
}
|
|
@@ -3103,8 +3648,8 @@ function registerCartCommands(program2, getClient2, getFormat2) {
|
|
|
3103
3648
|
retrieveCartParamsSchema
|
|
3104
3649
|
);
|
|
3105
3650
|
printResult(
|
|
3106
|
-
await
|
|
3107
|
-
|
|
3651
|
+
await getClient().commerce.carts.retrieve(data),
|
|
3652
|
+
getFormat()
|
|
3108
3653
|
);
|
|
3109
3654
|
} catch (error) {
|
|
3110
3655
|
exitWithError(error);
|
|
@@ -3118,10 +3663,10 @@ function registerCartCommands(program2, getClient2, getFormat2) {
|
|
|
3118
3663
|
addItemParamsSchema
|
|
3119
3664
|
);
|
|
3120
3665
|
if (opts.dryRun) {
|
|
3121
|
-
printResult(sensitiveDryRunResult("cart add"),
|
|
3666
|
+
printResult(sensitiveDryRunResult("cart add"), getFormat());
|
|
3122
3667
|
return;
|
|
3123
3668
|
}
|
|
3124
|
-
printResult(await
|
|
3669
|
+
printResult(await getClient().commerce.carts.addItem(data), getFormat());
|
|
3125
3670
|
} catch (error) {
|
|
3126
3671
|
exitWithError(error);
|
|
3127
3672
|
}
|
|
@@ -3134,12 +3679,12 @@ function registerCartCommands(program2, getClient2, getFormat2) {
|
|
|
3134
3679
|
updateItemParamsSchema
|
|
3135
3680
|
);
|
|
3136
3681
|
if (opts.dryRun) {
|
|
3137
|
-
printResult(sensitiveDryRunResult("cart update"),
|
|
3682
|
+
printResult(sensitiveDryRunResult("cart update"), getFormat());
|
|
3138
3683
|
return;
|
|
3139
3684
|
}
|
|
3140
3685
|
printResult(
|
|
3141
|
-
await
|
|
3142
|
-
|
|
3686
|
+
await getClient().commerce.carts.updateItem(data),
|
|
3687
|
+
getFormat()
|
|
3143
3688
|
);
|
|
3144
3689
|
} catch (error) {
|
|
3145
3690
|
exitWithError(error);
|
|
@@ -3153,12 +3698,12 @@ function registerCartCommands(program2, getClient2, getFormat2) {
|
|
|
3153
3698
|
removeItemParamsSchema
|
|
3154
3699
|
);
|
|
3155
3700
|
if (opts.dryRun) {
|
|
3156
|
-
printResult(sensitiveDryRunResult("cart remove"),
|
|
3701
|
+
printResult(sensitiveDryRunResult("cart remove"), getFormat());
|
|
3157
3702
|
return;
|
|
3158
3703
|
}
|
|
3159
3704
|
printResult(
|
|
3160
|
-
await
|
|
3161
|
-
|
|
3705
|
+
await getClient().commerce.carts.removeItem(data),
|
|
3706
|
+
getFormat()
|
|
3162
3707
|
);
|
|
3163
3708
|
} catch (error) {
|
|
3164
3709
|
exitWithError(error);
|
|
@@ -3172,10 +3717,10 @@ function registerCartCommands(program2, getClient2, getFormat2) {
|
|
|
3172
3717
|
clearCartParamsSchema
|
|
3173
3718
|
);
|
|
3174
3719
|
if (opts.dryRun) {
|
|
3175
|
-
printResult(sensitiveDryRunResult("cart clear"),
|
|
3720
|
+
printResult(sensitiveDryRunResult("cart clear"), getFormat());
|
|
3176
3721
|
return;
|
|
3177
3722
|
}
|
|
3178
|
-
printResult(await
|
|
3723
|
+
printResult(await getClient().commerce.carts.clear(data), getFormat());
|
|
3179
3724
|
} catch (error) {
|
|
3180
3725
|
exitWithError(error);
|
|
3181
3726
|
}
|
|
@@ -3188,12 +3733,12 @@ function registerCartCommands(program2, getClient2, getFormat2) {
|
|
|
3188
3733
|
updateDiscountCodesParamsSchema
|
|
3189
3734
|
);
|
|
3190
3735
|
if (opts.dryRun) {
|
|
3191
|
-
printResult(sensitiveDryRunResult("cart discounts"),
|
|
3736
|
+
printResult(sensitiveDryRunResult("cart discounts"), getFormat());
|
|
3192
3737
|
return;
|
|
3193
3738
|
}
|
|
3194
3739
|
printResult(
|
|
3195
|
-
await
|
|
3196
|
-
|
|
3740
|
+
await getClient().commerce.carts.updateDiscountCodes(data),
|
|
3741
|
+
getFormat()
|
|
3197
3742
|
);
|
|
3198
3743
|
} catch (error) {
|
|
3199
3744
|
exitWithError(error);
|
|
@@ -3210,12 +3755,12 @@ function registerCartCommands(program2, getClient2, getFormat2) {
|
|
|
3210
3755
|
updateCartAttributesParamsSchema
|
|
3211
3756
|
);
|
|
3212
3757
|
if (opts.dryRun) {
|
|
3213
|
-
printResult(sensitiveDryRunResult("cart attributes"),
|
|
3758
|
+
printResult(sensitiveDryRunResult("cart attributes"), getFormat());
|
|
3214
3759
|
return;
|
|
3215
3760
|
}
|
|
3216
3761
|
printResult(
|
|
3217
|
-
await
|
|
3218
|
-
|
|
3762
|
+
await getClient().commerce.carts.updateAttributes(data),
|
|
3763
|
+
getFormat()
|
|
3219
3764
|
);
|
|
3220
3765
|
} catch (error) {
|
|
3221
3766
|
exitWithError(error);
|
|
@@ -3224,17 +3769,17 @@ function registerCartCommands(program2, getClient2, getFormat2) {
|
|
|
3224
3769
|
}
|
|
3225
3770
|
|
|
3226
3771
|
// src/commands/stock.ts
|
|
3227
|
-
function registerStockCommands(
|
|
3228
|
-
const stock =
|
|
3772
|
+
function registerStockCommands(program, getClient, getFormat) {
|
|
3773
|
+
const stock = program.command("stock").description("Stock management");
|
|
3229
3774
|
stock.command("check").description("Check stock availability").requiredOption(
|
|
3230
3775
|
"--items <json>",
|
|
3231
3776
|
"Items to check (JSON array of { optionId, quantity })"
|
|
3232
3777
|
).action(async (opts) => {
|
|
3233
3778
|
try {
|
|
3234
|
-
const client =
|
|
3779
|
+
const client = getClient();
|
|
3235
3780
|
const items = parseJsonArray(opts.items, "items");
|
|
3236
3781
|
const result = await client.commerce.product.stockCheck({ items });
|
|
3237
|
-
printResult(result,
|
|
3782
|
+
printResult(result, getFormat());
|
|
3238
3783
|
} catch (e) {
|
|
3239
3784
|
exitWithError(e);
|
|
3240
3785
|
}
|
|
@@ -3246,8 +3791,8 @@ function paymentProvider(value) {
|
|
|
3246
3791
|
if (value === "toss" || value === "portone") return value;
|
|
3247
3792
|
throw new Error("payment provider must be toss or portone");
|
|
3248
3793
|
}
|
|
3249
|
-
function registerCommerceSessionCommands(
|
|
3250
|
-
const checkout =
|
|
3794
|
+
function registerCommerceSessionCommands(program, getClient, getFormat) {
|
|
3795
|
+
const checkout = program.command("checkout").description("Checkout management");
|
|
3251
3796
|
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) => {
|
|
3252
3797
|
try {
|
|
3253
3798
|
const data = parseWithSchema(
|
|
@@ -3256,12 +3801,12 @@ function registerCommerceSessionCommands(program2, getClient2, getFormat2) {
|
|
|
3256
3801
|
CreateServerCheckoutParamsSchema
|
|
3257
3802
|
);
|
|
3258
3803
|
if (opts.dryRun) {
|
|
3259
|
-
printResult(sensitiveDryRunResult("checkout create"),
|
|
3804
|
+
printResult(sensitiveDryRunResult("checkout create"), getFormat());
|
|
3260
3805
|
return;
|
|
3261
3806
|
}
|
|
3262
3807
|
printResult(
|
|
3263
|
-
await
|
|
3264
|
-
|
|
3808
|
+
await getClient().commerce.checkouts.create(data),
|
|
3809
|
+
getFormat()
|
|
3265
3810
|
);
|
|
3266
3811
|
} catch (error) {
|
|
3267
3812
|
exitWithError(error);
|
|
@@ -3270,8 +3815,8 @@ function registerCommerceSessionCommands(program2, getClient2, getFormat2) {
|
|
|
3270
3815
|
checkout.command("retrieve <checkoutId>").description("Retrieve a Checkout by ID with server credentials").action(async (checkoutId) => {
|
|
3271
3816
|
try {
|
|
3272
3817
|
printResult(
|
|
3273
|
-
await
|
|
3274
|
-
|
|
3818
|
+
await getClient().commerce.checkouts.retrieve({ checkoutId }),
|
|
3819
|
+
getFormat()
|
|
3275
3820
|
);
|
|
3276
3821
|
} catch (error) {
|
|
3277
3822
|
exitWithError(error);
|
|
@@ -3285,14 +3830,14 @@ function registerCommerceSessionCommands(program2, getClient2, getFormat2) {
|
|
|
3285
3830
|
CanonicalCheckoutQuerySchema
|
|
3286
3831
|
);
|
|
3287
3832
|
printResult(
|
|
3288
|
-
await
|
|
3289
|
-
|
|
3833
|
+
await getClient().commerce.checkouts.query(data),
|
|
3834
|
+
getFormat()
|
|
3290
3835
|
);
|
|
3291
3836
|
} catch (error) {
|
|
3292
3837
|
exitWithError(error);
|
|
3293
3838
|
}
|
|
3294
3839
|
});
|
|
3295
|
-
const sessions =
|
|
3840
|
+
const sessions = program.command("payment-session").description("PaymentSession management");
|
|
3296
3841
|
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) => {
|
|
3297
3842
|
try {
|
|
3298
3843
|
const data = parseWithSchema(
|
|
@@ -3303,13 +3848,13 @@ function registerCommerceSessionCommands(program2, getClient2, getFormat2) {
|
|
|
3303
3848
|
if (opts.dryRun) {
|
|
3304
3849
|
printResult(
|
|
3305
3850
|
sensitiveDryRunResult("payment-session create"),
|
|
3306
|
-
|
|
3851
|
+
getFormat()
|
|
3307
3852
|
);
|
|
3308
3853
|
return;
|
|
3309
3854
|
}
|
|
3310
|
-
const paymentSessions =
|
|
3855
|
+
const paymentSessions = getClient().commerce.paymentSessions;
|
|
3311
3856
|
const result = data.provider === "portone" ? await paymentSessions.createPortOne(data) : await paymentSessions.create(data);
|
|
3312
|
-
printResult(result,
|
|
3857
|
+
printResult(result, getFormat());
|
|
3313
3858
|
} catch (error) {
|
|
3314
3859
|
exitWithError(error);
|
|
3315
3860
|
}
|
|
@@ -3321,10 +3866,10 @@ function registerCommerceSessionCommands(program2, getClient2, getFormat2) {
|
|
|
3321
3866
|
).action(async (paymentSessionId, opts) => {
|
|
3322
3867
|
try {
|
|
3323
3868
|
const provider = paymentProvider(opts.provider);
|
|
3324
|
-
const paymentSessions =
|
|
3869
|
+
const paymentSessions = getClient().commerce.paymentSessions;
|
|
3325
3870
|
printResult(
|
|
3326
3871
|
provider === "portone" ? await paymentSessions.retrievePortOne({ paymentSessionId }) : await paymentSessions.retrieve({ paymentSessionId }),
|
|
3327
|
-
|
|
3872
|
+
getFormat()
|
|
3328
3873
|
);
|
|
3329
3874
|
} catch (error) {
|
|
3330
3875
|
exitWithError(error);
|
|
@@ -3348,14 +3893,14 @@ function registerCommerceSessionCommands(program2, getClient2, getFormat2) {
|
|
|
3348
3893
|
if (opts.dryRun) {
|
|
3349
3894
|
printResult(
|
|
3350
3895
|
sensitiveDryRunResult("payment-session cancel"),
|
|
3351
|
-
|
|
3896
|
+
getFormat()
|
|
3352
3897
|
);
|
|
3353
3898
|
return;
|
|
3354
3899
|
}
|
|
3355
|
-
const paymentSessions =
|
|
3900
|
+
const paymentSessions = getClient().commerce.paymentSessions;
|
|
3356
3901
|
printResult(
|
|
3357
3902
|
provider === "portone" ? await paymentSessions.cancelPortOne(data) : await paymentSessions.cancel(data),
|
|
3358
|
-
|
|
3903
|
+
getFormat()
|
|
3359
3904
|
);
|
|
3360
3905
|
} catch (error) {
|
|
3361
3906
|
exitWithError(error);
|
|
@@ -3371,13 +3916,13 @@ function registerCommerceSessionCommands(program2, getClient2, getFormat2) {
|
|
|
3371
3916
|
if (opts.dryRun) {
|
|
3372
3917
|
printResult(
|
|
3373
3918
|
sensitiveDryRunResult("payment-session confirm-toss"),
|
|
3374
|
-
|
|
3919
|
+
getFormat()
|
|
3375
3920
|
);
|
|
3376
3921
|
return;
|
|
3377
3922
|
}
|
|
3378
3923
|
printResult(
|
|
3379
|
-
await
|
|
3380
|
-
|
|
3924
|
+
await getClient().commerce.paymentSessions.confirm(data),
|
|
3925
|
+
getFormat()
|
|
3381
3926
|
);
|
|
3382
3927
|
} catch (error) {
|
|
3383
3928
|
exitWithError(error);
|
|
@@ -3433,14 +3978,14 @@ function productDetailParamsFromOptions(options) {
|
|
|
3433
3978
|
}
|
|
3434
3979
|
|
|
3435
3980
|
// src/commands/product.ts
|
|
3436
|
-
function registerProductCommands(
|
|
3437
|
-
const product =
|
|
3981
|
+
function registerProductCommands(program, getClient, getFormat) {
|
|
3982
|
+
const product = program.command("product").description("Product management");
|
|
3438
3983
|
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) => {
|
|
3439
3984
|
try {
|
|
3440
3985
|
const params = productDetailParamsFromOptions(opts);
|
|
3441
|
-
const client =
|
|
3986
|
+
const client = getClient();
|
|
3442
3987
|
const result = await client.commerce.product.detail(params);
|
|
3443
|
-
printResult(result,
|
|
3988
|
+
printResult(result, getFormat());
|
|
3444
3989
|
} catch (e) {
|
|
3445
3990
|
exitWithError(e);
|
|
3446
3991
|
}
|
|
@@ -3455,15 +4000,15 @@ function registerProductCommands(program2, getClient2, getFormat2) {
|
|
|
3455
4000
|
if (opts.dryRun) {
|
|
3456
4001
|
printResult(
|
|
3457
4002
|
{ dryRun: true, valid: true, action: "product upsert", data },
|
|
3458
|
-
|
|
4003
|
+
getFormat()
|
|
3459
4004
|
);
|
|
3460
4005
|
return;
|
|
3461
4006
|
}
|
|
3462
|
-
const client =
|
|
4007
|
+
const client = getClient();
|
|
3463
4008
|
const result = await client.commerce.product.upsert(
|
|
3464
4009
|
data
|
|
3465
4010
|
);
|
|
3466
|
-
printResult(result,
|
|
4011
|
+
printResult(result, getFormat());
|
|
3467
4012
|
} catch (e) {
|
|
3468
4013
|
exitWithError(e);
|
|
3469
4014
|
}
|
|
@@ -3471,20 +4016,20 @@ function registerProductCommands(program2, getClient2, getFormat2) {
|
|
|
3471
4016
|
}
|
|
3472
4017
|
|
|
3473
4018
|
// src/commands/discount.ts
|
|
3474
|
-
function registerDiscountCommands(
|
|
3475
|
-
const discount =
|
|
4019
|
+
function registerDiscountCommands(program, getClient, getFormat) {
|
|
4020
|
+
const discount = program.command("discount").description("Discount management");
|
|
3476
4021
|
discount.command("validate").description("Validate a discount code against an order amount").requiredOption("--code <code>", "Discount code").requiredOption(
|
|
3477
4022
|
"--order-amount <n>",
|
|
3478
4023
|
"Order amount",
|
|
3479
4024
|
(v) => parseInt(v, 10)
|
|
3480
4025
|
).action(async (opts) => {
|
|
3481
4026
|
try {
|
|
3482
|
-
const client =
|
|
4027
|
+
const client = getClient();
|
|
3483
4028
|
const result = await client.commerce.discounts.validate({
|
|
3484
4029
|
code: opts.code,
|
|
3485
4030
|
orderAmount: opts.orderAmount
|
|
3486
4031
|
});
|
|
3487
|
-
printResult(result,
|
|
4032
|
+
printResult(result, getFormat());
|
|
3488
4033
|
} catch (e) {
|
|
3489
4034
|
exitWithError(e);
|
|
3490
4035
|
}
|
|
@@ -3492,15 +4037,15 @@ function registerDiscountCommands(program2, getClient2, getFormat2) {
|
|
|
3492
4037
|
}
|
|
3493
4038
|
|
|
3494
4039
|
// src/commands/shipping.ts
|
|
3495
|
-
function registerShippingCommands(
|
|
3496
|
-
const shipping =
|
|
4040
|
+
function registerShippingCommands(program, getClient, getFormat) {
|
|
4041
|
+
const shipping = program.command("shipping").description("Shipping calculation");
|
|
3497
4042
|
shipping.command("calculate").description("Calculate shipping for an order amount").requiredOption(
|
|
3498
4043
|
"--order-amount <n>",
|
|
3499
4044
|
"Order amount",
|
|
3500
4045
|
(v) => parseInt(v, 10)
|
|
3501
4046
|
).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) => {
|
|
3502
4047
|
try {
|
|
3503
|
-
const client =
|
|
4048
|
+
const client = getClient();
|
|
3504
4049
|
const result = await client.commerce.shipping.calculate({
|
|
3505
4050
|
orderAmount: opts.orderAmount,
|
|
3506
4051
|
...opts.shippingPolicyId ? { shippingPolicyId: opts.shippingPolicyId } : {},
|
|
@@ -3508,7 +4053,7 @@ function registerShippingCommands(program2, getClient2, getFormat2) {
|
|
|
3508
4053
|
...opts.regionCode ? { regionCode: opts.regionCode } : {},
|
|
3509
4054
|
...opts.postalCode ? { postalCode: opts.postalCode } : {}
|
|
3510
4055
|
});
|
|
3511
|
-
printResult(result,
|
|
4056
|
+
printResult(result, getFormat());
|
|
3512
4057
|
} catch (e) {
|
|
3513
4058
|
exitWithError(e);
|
|
3514
4059
|
}
|
|
@@ -3524,6 +4069,8 @@ import { URL as URL2 } from "url";
|
|
|
3524
4069
|
import pc2 from "picocolors";
|
|
3525
4070
|
var WEB_URL = process.env.SOFTWARE_WEB_URL || "https://01.software";
|
|
3526
4071
|
var TIMEOUT_MS = 3 * 60 * 1e3;
|
|
4072
|
+
var EXCHANGE_TIMEOUT_MS = 3e4;
|
|
4073
|
+
var MAX_EXCHANGE_RESPONSE_BYTES = 1024 * 1024;
|
|
3527
4074
|
function escapeHtml(s) {
|
|
3528
4075
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
3529
4076
|
}
|
|
@@ -3566,16 +4113,72 @@ var ERROR_HTML = (msg) => `<!DOCTYPE html>
|
|
|
3566
4113
|
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>CLI Login Error</title>
|
|
3567
4114
|
<style>${PAGE_STYLE}</style>
|
|
3568
4115
|
</head><body><div class="card"><div class="icon err">!</div><h1>Authentication failed</h1><p>${escapeHtml(msg)}</p></div></body></html>`;
|
|
3569
|
-
async function
|
|
4116
|
+
async function readBoundedResponseBody(response, signal) {
|
|
4117
|
+
const contentLength = response.headers.get("content-length");
|
|
4118
|
+
if (contentLength !== null && /^\d+$/.test(contentLength) && Number(contentLength) > MAX_EXCHANGE_RESPONSE_BYTES) {
|
|
4119
|
+
void response.body?.cancel().catch(() => void 0);
|
|
4120
|
+
throw new Error("response body exceeded 1 MiB");
|
|
4121
|
+
}
|
|
4122
|
+
const reader = response.body?.getReader();
|
|
4123
|
+
if (!reader) return "";
|
|
4124
|
+
const decoder = new TextDecoder();
|
|
4125
|
+
let body = "";
|
|
4126
|
+
let totalBytes = 0;
|
|
4127
|
+
let completed = false;
|
|
4128
|
+
let rejectAbort;
|
|
4129
|
+
const aborted = new Promise((_, reject) => {
|
|
4130
|
+
rejectAbort = reject;
|
|
4131
|
+
});
|
|
4132
|
+
const onAbort = () => rejectAbort(new Error("request timed out"));
|
|
4133
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
4134
|
+
if (signal.aborted) onAbort();
|
|
4135
|
+
try {
|
|
4136
|
+
while (true) {
|
|
4137
|
+
const { done, value } = await Promise.race([reader.read(), aborted]);
|
|
4138
|
+
if (done) {
|
|
4139
|
+
completed = true;
|
|
4140
|
+
return body + decoder.decode();
|
|
4141
|
+
}
|
|
4142
|
+
totalBytes += value.byteLength;
|
|
4143
|
+
if (totalBytes > MAX_EXCHANGE_RESPONSE_BYTES) {
|
|
4144
|
+
throw new Error("response body exceeded 1 MiB");
|
|
4145
|
+
}
|
|
4146
|
+
body += decoder.decode(value, { stream: true });
|
|
4147
|
+
}
|
|
4148
|
+
} finally {
|
|
4149
|
+
signal.removeEventListener("abort", onAbort);
|
|
4150
|
+
if (!completed) void reader.cancel().catch(() => void 0);
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
async function exchangeCode(code, options = {}) {
|
|
3570
4154
|
const url = `${WEB_URL}/api/cli/exchange`;
|
|
4155
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
4156
|
+
const timeoutMs = options.timeoutMs ?? EXCHANGE_TIMEOUT_MS;
|
|
4157
|
+
const controller = new AbortController();
|
|
4158
|
+
let timeoutId;
|
|
4159
|
+
let rejectTimeout;
|
|
4160
|
+
const timedOut = new Promise((_, reject) => {
|
|
4161
|
+
rejectTimeout = reject;
|
|
4162
|
+
});
|
|
3571
4163
|
try {
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
4164
|
+
timeoutId = setTimeout(() => {
|
|
4165
|
+
controller.abort();
|
|
4166
|
+
rejectTimeout(new Error("request timed out"));
|
|
4167
|
+
}, timeoutMs);
|
|
4168
|
+
const res = await Promise.race([
|
|
4169
|
+
fetchImpl(url, {
|
|
4170
|
+
method: "POST",
|
|
4171
|
+
headers: { "Content-Type": "application/json" },
|
|
4172
|
+
body: JSON.stringify({ code }),
|
|
4173
|
+
signal: controller.signal
|
|
4174
|
+
}),
|
|
4175
|
+
timedOut
|
|
4176
|
+
]);
|
|
4177
|
+
const body = await Promise.race([
|
|
4178
|
+
readBoundedResponseBody(res, controller.signal),
|
|
4179
|
+
timedOut
|
|
4180
|
+
]);
|
|
3577
4181
|
if (!res.ok) {
|
|
3578
|
-
const body = await res.text().catch(() => "");
|
|
3579
4182
|
console.error(
|
|
3580
4183
|
pc2.red(
|
|
3581
4184
|
`Exchange failed: HTTP ${res.status} from ${url}${body ? ` \u2014 ${body.slice(0, 200)}` : ""}`
|
|
@@ -3583,7 +4186,13 @@ async function exchangeCode(code) {
|
|
|
3583
4186
|
);
|
|
3584
4187
|
return null;
|
|
3585
4188
|
}
|
|
3586
|
-
|
|
4189
|
+
let data;
|
|
4190
|
+
try {
|
|
4191
|
+
data = JSON.parse(body);
|
|
4192
|
+
} catch {
|
|
4193
|
+
console.error(pc2.red(`Exchange failed: malformed response from ${url}`));
|
|
4194
|
+
return null;
|
|
4195
|
+
}
|
|
3587
4196
|
if (typeof data.publishableKey !== "string" || typeof data.secretKey !== "string" || typeof data.tenantName !== "string" || typeof data.tenantId !== "string") {
|
|
3588
4197
|
console.error(pc2.red(`Exchange failed: malformed response from ${url}`));
|
|
3589
4198
|
return null;
|
|
@@ -3604,10 +4213,12 @@ async function exchangeCode(code) {
|
|
|
3604
4213
|
)
|
|
3605
4214
|
);
|
|
3606
4215
|
return null;
|
|
4216
|
+
} finally {
|
|
4217
|
+
clearTimeout(timeoutId);
|
|
3607
4218
|
}
|
|
3608
4219
|
}
|
|
3609
4220
|
function startAuthServer(options) {
|
|
3610
|
-
return new Promise((
|
|
4221
|
+
return new Promise((resolve3, reject) => {
|
|
3611
4222
|
const server = createServer((req, res) => {
|
|
3612
4223
|
if (!req.url) {
|
|
3613
4224
|
res.writeHead(400).end();
|
|
@@ -3620,7 +4231,10 @@ function startAuthServer(options) {
|
|
|
3620
4231
|
}
|
|
3621
4232
|
const error = url.searchParams.get("error");
|
|
3622
4233
|
if (error) {
|
|
3623
|
-
res.writeHead(200, {
|
|
4234
|
+
res.writeHead(200, {
|
|
4235
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
4236
|
+
Connection: "close"
|
|
4237
|
+
}).end(ERROR_HTML(error));
|
|
3624
4238
|
console.error(pc2.red(`Login failed: ${error}`));
|
|
3625
4239
|
cleanup(2);
|
|
3626
4240
|
return;
|
|
@@ -3628,19 +4242,32 @@ function startAuthServer(options) {
|
|
|
3628
4242
|
const code = url.searchParams.get("code");
|
|
3629
4243
|
const receivedState = url.searchParams.get("state");
|
|
3630
4244
|
if (!code || !receivedState) {
|
|
3631
|
-
res.writeHead(400, {
|
|
4245
|
+
res.writeHead(400, {
|
|
4246
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
4247
|
+
Connection: "close"
|
|
4248
|
+
}).end(ERROR_HTML('Missing code or state. Start over with "01 login".'));
|
|
3632
4249
|
cleanup(2);
|
|
3633
4250
|
return;
|
|
3634
4251
|
}
|
|
3635
4252
|
if (receivedState !== options.state) {
|
|
3636
|
-
res.writeHead(403, {
|
|
4253
|
+
res.writeHead(403, {
|
|
4254
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
4255
|
+
Connection: "close"
|
|
4256
|
+
}).end(ERROR_HTML('State mismatch. Start over with "01 login".'));
|
|
3637
4257
|
console.error(pc2.red("Login failed: state mismatch."));
|
|
3638
4258
|
cleanup(2);
|
|
3639
4259
|
return;
|
|
3640
4260
|
}
|
|
3641
4261
|
exchangeCode(code).then((creds) => {
|
|
3642
4262
|
if (!creds) {
|
|
3643
|
-
res.writeHead(400, {
|
|
4263
|
+
res.writeHead(400, {
|
|
4264
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
4265
|
+
Connection: "close"
|
|
4266
|
+
}).end(
|
|
4267
|
+
ERROR_HTML(
|
|
4268
|
+
'Invalid or expired code. Start over with "01 login".'
|
|
4269
|
+
)
|
|
4270
|
+
);
|
|
3644
4271
|
console.error(pc2.red("Login failed: code exchange failed."));
|
|
3645
4272
|
cleanup(2);
|
|
3646
4273
|
return;
|
|
@@ -3657,7 +4284,10 @@ function startAuthServer(options) {
|
|
|
3657
4284
|
console.log(pc2.green(`
|
|
3658
4285
|
Logged in successfully!`));
|
|
3659
4286
|
console.log(pc2.dim(`Tenant: ${creds.tenantName}`));
|
|
3660
|
-
res.writeHead(200, {
|
|
4287
|
+
res.writeHead(200, {
|
|
4288
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
4289
|
+
Connection: "close"
|
|
4290
|
+
}).end(SUCCESS_HTML);
|
|
3661
4291
|
cleanup(0);
|
|
3662
4292
|
});
|
|
3663
4293
|
});
|
|
@@ -3682,15 +4312,15 @@ Logged in successfully!`));
|
|
|
3682
4312
|
);
|
|
3683
4313
|
cleanup(4);
|
|
3684
4314
|
}, TIMEOUT_MS);
|
|
3685
|
-
|
|
4315
|
+
resolve3({ port: addr.port, cleanup });
|
|
3686
4316
|
});
|
|
3687
4317
|
server.on("error", (err) => {
|
|
3688
4318
|
reject(err);
|
|
3689
4319
|
});
|
|
3690
4320
|
});
|
|
3691
4321
|
}
|
|
3692
|
-
function registerAuthCommands(
|
|
3693
|
-
|
|
4322
|
+
function registerAuthCommands(program) {
|
|
4323
|
+
program.command("login").description("Login via browser and store credentials").action(async () => {
|
|
3694
4324
|
const state = randomBytes2(32).toString("hex");
|
|
3695
4325
|
try {
|
|
3696
4326
|
const { port } = await startAuthServer({
|
|
@@ -3715,7 +4345,7 @@ ${loginUrl}`));
|
|
|
3715
4345
|
process.exit(4);
|
|
3716
4346
|
}
|
|
3717
4347
|
});
|
|
3718
|
-
|
|
4348
|
+
program.command("logout").description("Remove stored credentials").action(() => {
|
|
3719
4349
|
const deleted = deleteCredentials();
|
|
3720
4350
|
if (deleted) {
|
|
3721
4351
|
console.log(pc2.green("Logged out. Credentials removed."));
|
|
@@ -3723,7 +4353,7 @@ ${loginUrl}`));
|
|
|
3723
4353
|
console.log(pc2.dim("No stored credentials found."));
|
|
3724
4354
|
}
|
|
3725
4355
|
});
|
|
3726
|
-
|
|
4356
|
+
program.command("whoami").description("Show current authentication status").action(() => {
|
|
3727
4357
|
const localCreds = loadLocalCredentials();
|
|
3728
4358
|
const globalCreds = loadCredentials();
|
|
3729
4359
|
const creds = localCreds || globalCreds;
|
|
@@ -3741,7 +4371,7 @@ ${loginUrl}`));
|
|
|
3741
4371
|
`File: ${pc2.dim(isLocal ? getLocalCredentialsPath() : getCredentialsPath())}`
|
|
3742
4372
|
);
|
|
3743
4373
|
});
|
|
3744
|
-
const tenant =
|
|
4374
|
+
const tenant = program.command("tenant").description("Manage tenant switching");
|
|
3745
4375
|
tenant.command("list").description("Show cached tenant list").action(() => {
|
|
3746
4376
|
const tenants = loadTenantList();
|
|
3747
4377
|
if (!tenants || tenants.length === 0) {
|
|
@@ -3822,17 +4452,17 @@ ${loginUrl}`));
|
|
|
3822
4452
|
|
|
3823
4453
|
// src/commands/schema.ts
|
|
3824
4454
|
import { SERVER_COLLECTIONS as SERVER_COLLECTIONS2 } from "@01.software/sdk";
|
|
3825
|
-
function registerSchemaCommands(
|
|
3826
|
-
const schema =
|
|
4455
|
+
function registerSchemaCommands(program, getClient, getFormat) {
|
|
4456
|
+
const schema = program.command("schema").description("Collection schema introspection");
|
|
3827
4457
|
schema.command("list").description("List available collections").action(() => {
|
|
3828
|
-
printResult(SERVER_COLLECTIONS2,
|
|
4458
|
+
printResult(SERVER_COLLECTIONS2, getFormat());
|
|
3829
4459
|
});
|
|
3830
4460
|
schema.command("show <collection>").description("Show collection field schema").action(async (collection) => {
|
|
3831
4461
|
try {
|
|
3832
4462
|
const col = validateCollection(collection);
|
|
3833
|
-
const client =
|
|
4463
|
+
const client = getClient();
|
|
3834
4464
|
const result = await client.tenant.collectionSchema(col);
|
|
3835
|
-
printResult(result,
|
|
4465
|
+
printResult(result, getFormat());
|
|
3836
4466
|
} catch (e) {
|
|
3837
4467
|
exitWithError(e);
|
|
3838
4468
|
}
|
|
@@ -3851,8 +4481,8 @@ function flattenProgress(progress) {
|
|
|
3851
4481
|
}))
|
|
3852
4482
|
);
|
|
3853
4483
|
}
|
|
3854
|
-
function registerFeatureCommands(
|
|
3855
|
-
const feature =
|
|
4484
|
+
function registerFeatureCommands(program, getClient, getFormat) {
|
|
4485
|
+
const feature = program.command("feature").description("Feature implementation progress checks");
|
|
3856
4486
|
feature.command("check <feature>").description("Check tenant implementation progress for a feature").option("--evidence", "Include sanitized evidence counts and surface flags").action(async (featureName, options) => {
|
|
3857
4487
|
try {
|
|
3858
4488
|
const input = parseWithSchema(
|
|
@@ -3863,11 +4493,11 @@ function registerFeatureCommands(program2, getClient2, getFormat2) {
|
|
|
3863
4493
|
"feature",
|
|
3864
4494
|
tenantFeatureProgressInputSchema
|
|
3865
4495
|
);
|
|
3866
|
-
const client =
|
|
4496
|
+
const client = getClient();
|
|
3867
4497
|
const result = tenantFeatureProgressResponseSchema.parse(
|
|
3868
4498
|
await client.tenant.featureProgress(input)
|
|
3869
4499
|
);
|
|
3870
|
-
const format =
|
|
4500
|
+
const format = getFormat();
|
|
3871
4501
|
printResult(
|
|
3872
4502
|
format === "table" ? flattenProgress(result) : result,
|
|
3873
4503
|
format
|
|
@@ -4124,18 +4754,18 @@ function assertAgentPlanCapabilityMatrix(matrix) {
|
|
|
4124
4754
|
);
|
|
4125
4755
|
}
|
|
4126
4756
|
const seen = /* @__PURE__ */ new Set();
|
|
4127
|
-
for (const
|
|
4128
|
-
if (!AGENT_PLAN_OPERATIONS.has(
|
|
4757
|
+
for (const operation2 of operations) {
|
|
4758
|
+
if (!AGENT_PLAN_OPERATIONS.has(operation2)) {
|
|
4129
4759
|
throw new Error(
|
|
4130
|
-
`Agent plan capability operation "${
|
|
4760
|
+
`Agent plan capability operation "${operation2}" is invalid for "${collection}".`
|
|
4131
4761
|
);
|
|
4132
4762
|
}
|
|
4133
|
-
if (seen.has(
|
|
4763
|
+
if (seen.has(operation2)) {
|
|
4134
4764
|
throw new Error(
|
|
4135
|
-
`Agent plan capability operation "${
|
|
4765
|
+
`Agent plan capability operation "${operation2}" is duplicated for "${collection}".`
|
|
4136
4766
|
);
|
|
4137
4767
|
}
|
|
4138
|
-
seen.add(
|
|
4768
|
+
seen.add(operation2);
|
|
4139
4769
|
}
|
|
4140
4770
|
}
|
|
4141
4771
|
}
|
|
@@ -4149,19 +4779,19 @@ function isAgentPlanCollection(collection) {
|
|
|
4149
4779
|
function getAgentPlanOperations(collection) {
|
|
4150
4780
|
return isAgentPlanCollection(collection) ? AGENT_PLAN_CAPABILITIES[collection] : [];
|
|
4151
4781
|
}
|
|
4152
|
-
function isAgentPlanCapability(collection,
|
|
4782
|
+
function isAgentPlanCapability(collection, operation2) {
|
|
4153
4783
|
if (!isAgentPlanCollection(collection)) return false;
|
|
4154
4784
|
return AGENT_PLAN_CAPABILITIES[collection].includes(
|
|
4155
|
-
|
|
4785
|
+
operation2
|
|
4156
4786
|
);
|
|
4157
4787
|
}
|
|
4158
|
-
function assertAgentPlanCapability(collection,
|
|
4159
|
-
if (isAgentPlanCapability(collection,
|
|
4788
|
+
function assertAgentPlanCapability(collection, operation2) {
|
|
4789
|
+
if (isAgentPlanCapability(collection, operation2)) {
|
|
4160
4790
|
return collection;
|
|
4161
4791
|
}
|
|
4162
4792
|
throw agentPlanError(
|
|
4163
4793
|
"UNSUPPORTED_OPERATION",
|
|
4164
|
-
`Operation "${
|
|
4794
|
+
`Operation "${operation2}" is not supported for collection "${collection}" in agent plan mutations.`
|
|
4165
4795
|
);
|
|
4166
4796
|
}
|
|
4167
4797
|
|
|
@@ -4260,11 +4890,11 @@ function parseStoredAgentPlan(raw, planId) {
|
|
|
4260
4890
|
throw agentPlanError("PLAN_MISMATCH", "Stored plan has unsupported collection.");
|
|
4261
4891
|
}
|
|
4262
4892
|
const collection = record.collection;
|
|
4263
|
-
const
|
|
4264
|
-
if (
|
|
4893
|
+
const operation2 = record.operation;
|
|
4894
|
+
if (operation2 !== "create" && operation2 !== "update" && operation2 !== "delete") {
|
|
4265
4895
|
throw agentPlanError("PLAN_MISMATCH", "Stored plan has invalid operation.");
|
|
4266
4896
|
}
|
|
4267
|
-
if (!isAgentPlanCapability(collection,
|
|
4897
|
+
if (!isAgentPlanCapability(collection, operation2)) {
|
|
4268
4898
|
throw agentPlanError(
|
|
4269
4899
|
"PLAN_MISMATCH",
|
|
4270
4900
|
"Stored plan has unsupported collection operation."
|
|
@@ -4282,7 +4912,7 @@ function parseStoredAgentPlan(raw, planId) {
|
|
|
4282
4912
|
return {
|
|
4283
4913
|
planId,
|
|
4284
4914
|
planHash: record.planHash,
|
|
4285
|
-
operation,
|
|
4915
|
+
operation: operation2,
|
|
4286
4916
|
collection,
|
|
4287
4917
|
documentId,
|
|
4288
4918
|
payload,
|
|
@@ -4408,8 +5038,8 @@ function readDocumentUpdatedAt(doc) {
|
|
|
4408
5038
|
const updatedAt = doc.updatedAt;
|
|
4409
5039
|
return typeof updatedAt === "string" && updatedAt.length > 0 ? updatedAt : void 0;
|
|
4410
5040
|
}
|
|
4411
|
-
function assertPlanBaseUpdatedAt(
|
|
4412
|
-
if (
|
|
5041
|
+
function assertPlanBaseUpdatedAt(operation2, baseUpdatedAt) {
|
|
5042
|
+
if (operation2 === "create") {
|
|
4413
5043
|
return;
|
|
4414
5044
|
}
|
|
4415
5045
|
if (!baseUpdatedAt) {
|
|
@@ -4675,7 +5305,7 @@ async function runPlanAction(input) {
|
|
|
4675
5305
|
input.outputOptions
|
|
4676
5306
|
);
|
|
4677
5307
|
}
|
|
4678
|
-
function registerAgentPlanCommands(agent,
|
|
5308
|
+
function registerAgentPlanCommands(agent, getClient) {
|
|
4679
5309
|
const plan = configureAgentParser(
|
|
4680
5310
|
agent.command("plan").description("Plan a mutation without executing")
|
|
4681
5311
|
);
|
|
@@ -4694,7 +5324,7 @@ function registerAgentPlanCommands(agent, getClient2) {
|
|
|
4694
5324
|
dataStdin: opts.dataStdin,
|
|
4695
5325
|
dataFile: opts.dataFile,
|
|
4696
5326
|
outputOptions,
|
|
4697
|
-
getClient
|
|
5327
|
+
getClient
|
|
4698
5328
|
});
|
|
4699
5329
|
} catch (error) {
|
|
4700
5330
|
exitWithAgentError(error, outputOptions);
|
|
@@ -4718,7 +5348,7 @@ function registerAgentPlanCommands(agent, getClient2) {
|
|
|
4718
5348
|
dataStdin: opts.dataStdin,
|
|
4719
5349
|
dataFile: opts.dataFile,
|
|
4720
5350
|
outputOptions,
|
|
4721
|
-
getClient
|
|
5351
|
+
getClient
|
|
4722
5352
|
});
|
|
4723
5353
|
} catch (error) {
|
|
4724
5354
|
exitWithAgentError(error, outputOptions);
|
|
@@ -4740,7 +5370,7 @@ function registerAgentPlanCommands(agent, getClient2) {
|
|
|
4740
5370
|
collection,
|
|
4741
5371
|
documentId: id,
|
|
4742
5372
|
outputOptions,
|
|
4743
|
-
getClient
|
|
5373
|
+
getClient
|
|
4744
5374
|
});
|
|
4745
5375
|
} catch (error) {
|
|
4746
5376
|
exitWithAgentError(error, outputOptions);
|
|
@@ -4764,7 +5394,7 @@ function registerAgentPlanCommands(agent, getClient2) {
|
|
|
4764
5394
|
"Plan token does not match --hash."
|
|
4765
5395
|
);
|
|
4766
5396
|
}
|
|
4767
|
-
const client =
|
|
5397
|
+
const client = getClient();
|
|
4768
5398
|
const authFingerprint = buildAuthContextFingerprint({
|
|
4769
5399
|
publishableKey: client.publishableKey,
|
|
4770
5400
|
secretKey: client.secretKey
|
|
@@ -4879,7 +5509,7 @@ function buildAgentManifest() {
|
|
|
4879
5509
|
...AGENT_READ_OPERATIONS,
|
|
4880
5510
|
...collection === "products" ? AGENT_PRODUCT_OPERATIONS : [],
|
|
4881
5511
|
...getAgentPlanOperations(collection).map(
|
|
4882
|
-
(
|
|
5512
|
+
(operation2) => `plan:${operation2}`
|
|
4883
5513
|
)
|
|
4884
5514
|
];
|
|
4885
5515
|
collections[collection] = {
|
|
@@ -4891,7 +5521,8 @@ function buildAgentManifest() {
|
|
|
4891
5521
|
version: AGENT_PROTOCOL_VERSION,
|
|
4892
5522
|
discovery: {
|
|
4893
5523
|
context: { counts: true },
|
|
4894
|
-
schema: { mode: "effective" }
|
|
5524
|
+
schema: { mode: "effective" },
|
|
5525
|
+
doctor: { appIntegration: true }
|
|
4895
5526
|
},
|
|
4896
5527
|
collections
|
|
4897
5528
|
};
|
|
@@ -4904,9 +5535,9 @@ function validateAgentCollection(collection) {
|
|
|
4904
5535
|
throw invalidInput3(message, "collection", collection);
|
|
4905
5536
|
}
|
|
4906
5537
|
}
|
|
4907
|
-
function registerAgentCommands(
|
|
5538
|
+
function registerAgentCommands(program, getClient) {
|
|
4908
5539
|
const agent = configureAgentParser2(
|
|
4909
|
-
|
|
5540
|
+
program.command("agent").description("Machine-stable CLI namespace for coding agents").option("--pretty", "Print 2-space indented success JSON").option(
|
|
4910
5541
|
"--output-file <path>",
|
|
4911
5542
|
"Write success JSON to a secure file and print a receipt"
|
|
4912
5543
|
).addHelpText(
|
|
@@ -4936,7 +5567,7 @@ function registerAgentCommands(program2, getClient2) {
|
|
|
4936
5567
|
const outputOptions = resolveAgentPrintOptions(command);
|
|
4937
5568
|
try {
|
|
4938
5569
|
validateAgentOutputTarget(outputOptions);
|
|
4939
|
-
const client =
|
|
5570
|
+
const client = getClient();
|
|
4940
5571
|
const result = opts.counts ? await client.tenant.context({ includeCounts: true }) : await client.tenant.context();
|
|
4941
5572
|
printAgentSuccess(result, outputOptions);
|
|
4942
5573
|
} catch (error) {
|
|
@@ -4953,7 +5584,7 @@ function registerAgentCommands(program2, getClient2) {
|
|
|
4953
5584
|
try {
|
|
4954
5585
|
validateAgentOutputTarget(outputOptions);
|
|
4955
5586
|
const col = validateAgentCollection(collection);
|
|
4956
|
-
const client =
|
|
5587
|
+
const client = getClient();
|
|
4957
5588
|
const result = await client.tenant.collectionSchema(col);
|
|
4958
5589
|
printAgentSuccess(result, outputOptions);
|
|
4959
5590
|
} catch (error) {
|
|
@@ -4980,7 +5611,7 @@ function registerAgentCommands(program2, getClient2) {
|
|
|
4980
5611
|
if (page != null) options.page = page;
|
|
4981
5612
|
if (opts.sort) options.sort = opts.sort;
|
|
4982
5613
|
if (opts.select) options.select = parseSelect(opts.select);
|
|
4983
|
-
const client =
|
|
5614
|
+
const client = getClient();
|
|
4984
5615
|
const result = await client.collections.from(col).find(options);
|
|
4985
5616
|
printAgentSuccess(result, outputOptions);
|
|
4986
5617
|
} catch (error) {
|
|
@@ -5004,7 +5635,7 @@ function registerAgentCommands(program2, getClient2) {
|
|
|
5004
5635
|
}
|
|
5005
5636
|
const options = {};
|
|
5006
5637
|
if (opts.select) options.select = parseSelect(opts.select);
|
|
5007
|
-
const client =
|
|
5638
|
+
const client = getClient();
|
|
5008
5639
|
const result = await client.collections.from(col).findById(id, options);
|
|
5009
5640
|
printAgentSuccess(result, outputOptions);
|
|
5010
5641
|
} catch (error) {
|
|
@@ -5026,7 +5657,7 @@ function registerAgentCommands(program2, getClient2) {
|
|
|
5026
5657
|
try {
|
|
5027
5658
|
validateAgentOutputTarget(outputOptions);
|
|
5028
5659
|
const params = productDetailParamsFromOptions(opts);
|
|
5029
|
-
const client =
|
|
5660
|
+
const client = getClient();
|
|
5030
5661
|
const result = await client.commerce.product.detail(params);
|
|
5031
5662
|
printAgentSuccess(result, outputOptions);
|
|
5032
5663
|
} catch (error) {
|
|
@@ -5035,37 +5666,542 @@ function registerAgentCommands(program2, getClient2) {
|
|
|
5035
5666
|
}
|
|
5036
5667
|
)
|
|
5037
5668
|
);
|
|
5038
|
-
registerAgentPlanCommands(agent,
|
|
5669
|
+
registerAgentPlanCommands(agent, getClient);
|
|
5670
|
+
return agent;
|
|
5671
|
+
}
|
|
5672
|
+
|
|
5673
|
+
// src/commands/embedded-app.ts
|
|
5674
|
+
function registerEmbeddedAppCommands(program, getClient, getFormat) {
|
|
5675
|
+
const embeddedApp = program.command("embedded-app").description("Manage the active tenant embedded admin app binding");
|
|
5676
|
+
embeddedApp.command("show").description("Show the active tenant embedded app binding").action(async () => {
|
|
5677
|
+
try {
|
|
5678
|
+
const result = await getClient().embeddedAdmin.show();
|
|
5679
|
+
printResult(result, getFormat());
|
|
5680
|
+
} catch (error) {
|
|
5681
|
+
exitWithError(error);
|
|
5682
|
+
}
|
|
5683
|
+
});
|
|
5684
|
+
embeddedApp.command("configure").description("Configure and enable the active tenant embedded app").requiredOption("--label <label>", "Display label shown in Console").requiredOption("--origin <origin>", "Exact HTTPS app origin").option("--path <path>", "Relative app path", "/").option("--dry-run", "Validate inputs without executing").action(
|
|
5685
|
+
async (options) => {
|
|
5686
|
+
try {
|
|
5687
|
+
const client = getClient();
|
|
5688
|
+
const input = {
|
|
5689
|
+
label: options.label,
|
|
5690
|
+
origin: options.origin,
|
|
5691
|
+
path: options.path
|
|
5692
|
+
};
|
|
5693
|
+
const binding = client.embeddedAdmin.validateConfiguration(input);
|
|
5694
|
+
if (options.dryRun) {
|
|
5695
|
+
printResult(
|
|
5696
|
+
{
|
|
5697
|
+
action: "embedded app configure",
|
|
5698
|
+
binding,
|
|
5699
|
+
dryRun: true,
|
|
5700
|
+
valid: true
|
|
5701
|
+
},
|
|
5702
|
+
getFormat()
|
|
5703
|
+
);
|
|
5704
|
+
return;
|
|
5705
|
+
}
|
|
5706
|
+
const result = await client.embeddedAdmin.configure(input);
|
|
5707
|
+
printResult(result, getFormat());
|
|
5708
|
+
} catch (error) {
|
|
5709
|
+
exitWithError(error);
|
|
5710
|
+
}
|
|
5711
|
+
}
|
|
5712
|
+
);
|
|
5713
|
+
embeddedApp.command("disable").description("Disable the active tenant embedded app binding").option("--dry-run", "Validate without executing").action(async (options) => {
|
|
5714
|
+
try {
|
|
5715
|
+
const client = getClient();
|
|
5716
|
+
client.embeddedAdmin.validateManagementAccess();
|
|
5717
|
+
if (options.dryRun) {
|
|
5718
|
+
printResult(
|
|
5719
|
+
{
|
|
5720
|
+
action: "embedded app disable",
|
|
5721
|
+
dryRun: true,
|
|
5722
|
+
valid: true
|
|
5723
|
+
},
|
|
5724
|
+
getFormat()
|
|
5725
|
+
);
|
|
5726
|
+
return;
|
|
5727
|
+
}
|
|
5728
|
+
const result = await client.embeddedAdmin.disable();
|
|
5729
|
+
printResult(result, getFormat());
|
|
5730
|
+
} catch (error) {
|
|
5731
|
+
exitWithError(error);
|
|
5732
|
+
}
|
|
5733
|
+
});
|
|
5734
|
+
}
|
|
5735
|
+
|
|
5736
|
+
// src/lib/doctor.ts
|
|
5737
|
+
import { existsSync as existsSync2, lstatSync as lstatSync2, readFileSync as readFileSync4 } from "fs";
|
|
5738
|
+
import { createRequire } from "module";
|
|
5739
|
+
import { join as join3, resolve as resolve2 } from "path";
|
|
5740
|
+
import { satisfies, validRange } from "semver";
|
|
5741
|
+
import {
|
|
5742
|
+
TenantIntrospectionApi as TenantIntrospectionApi2,
|
|
5743
|
+
TENANT_CONTEXT_PATH
|
|
5744
|
+
} from "@01.software/sdk/server";
|
|
5745
|
+
var PUBLIC_ENV_PREFIXES = [
|
|
5746
|
+
"NEXT_PUBLIC_",
|
|
5747
|
+
"VITE_",
|
|
5748
|
+
"REACT_APP_",
|
|
5749
|
+
"PUBLIC_"
|
|
5750
|
+
];
|
|
5751
|
+
var APP_ENV_PREFIXES = ["", ...PUBLIC_ENV_PREFIXES];
|
|
5752
|
+
var envKey = (prefix, suffix) => `${prefix}${suffix}`;
|
|
5753
|
+
var PUBLISHABLE_KEYS = APP_ENV_PREFIXES.map(
|
|
5754
|
+
(prefix) => envKey(prefix, "SOFTWARE_PUBLISHABLE_KEY")
|
|
5755
|
+
);
|
|
5756
|
+
var SECRET_KEYS = APP_ENV_PREFIXES.map(
|
|
5757
|
+
(prefix) => envKey(prefix, "SOFTWARE_SECRET_KEY")
|
|
5758
|
+
);
|
|
5759
|
+
var SDK_API_URL_KEYS = [
|
|
5760
|
+
"SOFTWARE_API_URL",
|
|
5761
|
+
"NEXT_PUBLIC_SOFTWARE_API_URL"
|
|
5762
|
+
];
|
|
5763
|
+
var DoctorInputError = class extends Error {
|
|
5764
|
+
constructor(field = "envFile") {
|
|
5765
|
+
const message = field === "origin" ? "--origin must be an absolute http(s) URL." : "--app-env-file must name a readable regular environment file.";
|
|
5766
|
+
super(message);
|
|
5767
|
+
Object.assign(this, {
|
|
5768
|
+
type: "validation",
|
|
5769
|
+
code: "invalid_argument",
|
|
5770
|
+
field,
|
|
5771
|
+
detail: {
|
|
5772
|
+
message,
|
|
5773
|
+
field
|
|
5774
|
+
}
|
|
5775
|
+
});
|
|
5776
|
+
this.field = field;
|
|
5777
|
+
}
|
|
5778
|
+
};
|
|
5779
|
+
function doctorInputMessageKey(error) {
|
|
5780
|
+
if (!(error instanceof DoctorInputError)) return void 0;
|
|
5781
|
+
return error.field === "origin" ? "DoctorOriginInputInvalid" : "DoctorEnvFileInvalid";
|
|
5782
|
+
}
|
|
5783
|
+
function statusFromChecks(checks) {
|
|
5784
|
+
if (checks.some((check2) => check2.status === "blocked")) return "blocked";
|
|
5785
|
+
if (checks.some((check2) => check2.status === "attention")) return "attention";
|
|
5786
|
+
return "ready";
|
|
5787
|
+
}
|
|
5788
|
+
function compositeExitCode(checks) {
|
|
5789
|
+
const codes = checks.map((check2) => check2.exitCode).filter((code) => typeof code === "number");
|
|
5790
|
+
for (const preferred of [3, 2, 6, 4, 5, 1]) {
|
|
5791
|
+
if (codes.includes(preferred)) return preferred;
|
|
5792
|
+
}
|
|
5793
|
+
return 0;
|
|
5794
|
+
}
|
|
5795
|
+
function check(id, status, action, exitCode) {
|
|
5796
|
+
return { id, status, action, ...exitCode !== void 0 && { exitCode } };
|
|
5797
|
+
}
|
|
5798
|
+
function readPackage(cwd) {
|
|
5799
|
+
const path2 = join3(cwd, "package.json");
|
|
5800
|
+
if (!existsSync2(path2)) return null;
|
|
5801
|
+
try {
|
|
5802
|
+
const value = JSON.parse(readFileSync4(path2, "utf8"));
|
|
5803
|
+
return value && typeof value === "object" ? value : null;
|
|
5804
|
+
} catch {
|
|
5805
|
+
return null;
|
|
5806
|
+
}
|
|
5807
|
+
}
|
|
5808
|
+
function nodeEngineCheck(engine, nodeVersion = process.versions.node) {
|
|
5809
|
+
if (engine === void 0)
|
|
5810
|
+
return check("node.engine", "attention", "DoctorNodeEngineNotDeclared");
|
|
5811
|
+
if (typeof engine !== "string")
|
|
5812
|
+
return check("node.engine", "attention", "DoctorNodeEngineAttention");
|
|
5813
|
+
const range = validRange(engine);
|
|
5814
|
+
if (!range)
|
|
5815
|
+
return check("node.engine", "attention", "DoctorNodeEngineAttention");
|
|
5816
|
+
return satisfies(nodeVersion, range) ? check("node.engine", "ready", "DoctorNodeEngineReady") : check("node.engine", "attention", "DoctorNodeEngineAttention");
|
|
5817
|
+
}
|
|
5818
|
+
function parseEnv(content, file) {
|
|
5819
|
+
const declarations = [];
|
|
5820
|
+
for (const line of content.split(/\r?\n/)) {
|
|
5821
|
+
const match = line.match(
|
|
5822
|
+
/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/
|
|
5823
|
+
);
|
|
5824
|
+
if (!match) continue;
|
|
5825
|
+
let value = match[2] ?? "";
|
|
5826
|
+
if (value.length >= 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
5827
|
+
value = value.slice(1, -1);
|
|
5828
|
+
} else {
|
|
5829
|
+
value = value.replace(/\s+#.*$/, "");
|
|
5830
|
+
}
|
|
5831
|
+
declarations.push({ key: match[1], value: value.trim(), file });
|
|
5832
|
+
}
|
|
5833
|
+
return declarations;
|
|
5834
|
+
}
|
|
5835
|
+
function readEnvFile(file) {
|
|
5836
|
+
try {
|
|
5837
|
+
if (!lstatSync2(file).isFile()) return null;
|
|
5838
|
+
return parseEnv(readFileSync4(file, "utf8"), file);
|
|
5839
|
+
} catch {
|
|
5840
|
+
return null;
|
|
5841
|
+
}
|
|
5842
|
+
}
|
|
5843
|
+
function existsIncludingSymlink(file) {
|
|
5844
|
+
try {
|
|
5845
|
+
lstatSync2(file);
|
|
5846
|
+
return true;
|
|
5847
|
+
} catch {
|
|
5848
|
+
return false;
|
|
5849
|
+
}
|
|
5850
|
+
}
|
|
5851
|
+
function resolveEnv(declarations) {
|
|
5852
|
+
const values = /* @__PURE__ */ new Map();
|
|
5853
|
+
const ambiguousKeys = /* @__PURE__ */ new Set();
|
|
5854
|
+
const declaredInFile = /* @__PURE__ */ new Set();
|
|
5855
|
+
for (const declaration of declarations) {
|
|
5856
|
+
const identity = `${declaration.file}\0${declaration.key}`;
|
|
5857
|
+
if (declaredInFile.has(identity)) ambiguousKeys.add(declaration.key);
|
|
5858
|
+
declaredInFile.add(identity);
|
|
5859
|
+
values.set(declaration.key, declaration);
|
|
5860
|
+
}
|
|
5861
|
+
return { values, ambiguousKeys, invalid: false };
|
|
5862
|
+
}
|
|
5863
|
+
function envFilesForPackage(pkg) {
|
|
5864
|
+
const deps = {
|
|
5865
|
+
...pkg?.dependencies ?? {},
|
|
5866
|
+
...pkg?.devDependencies ?? {}
|
|
5867
|
+
};
|
|
5868
|
+
if ("next" in deps || "react-scripts" in deps) {
|
|
5869
|
+
return [".env", ".env.development", ".env.local", ".env.development.local"];
|
|
5870
|
+
}
|
|
5871
|
+
if ("vite" in deps) {
|
|
5872
|
+
return [".env", ".env.local", ".env.development", ".env.development.local"];
|
|
5873
|
+
}
|
|
5874
|
+
return [".env", ".env.local"];
|
|
5875
|
+
}
|
|
5876
|
+
function readDoctorEnv(cwd, pkg, explicit) {
|
|
5877
|
+
if (explicit !== void 0) {
|
|
5878
|
+
const file = resolve2(cwd, explicit);
|
|
5879
|
+
const declarations2 = readEnvFile(file);
|
|
5880
|
+
if (!declarations2) throw new DoctorInputError();
|
|
5881
|
+
return resolveEnv(declarations2);
|
|
5882
|
+
}
|
|
5883
|
+
const declarations = [];
|
|
5884
|
+
let found = false;
|
|
5885
|
+
for (const name of envFilesForPackage(pkg)) {
|
|
5886
|
+
const file = join3(cwd, name);
|
|
5887
|
+
if (!existsIncludingSymlink(file)) continue;
|
|
5888
|
+
found = true;
|
|
5889
|
+
const parsed = readEnvFile(file);
|
|
5890
|
+
if (!parsed)
|
|
5891
|
+
return { values: /* @__PURE__ */ new Map(), ambiguousKeys: /* @__PURE__ */ new Set(), invalid: true };
|
|
5892
|
+
declarations.push(...parsed);
|
|
5893
|
+
}
|
|
5894
|
+
return found ? resolveEnv(declarations) : null;
|
|
5895
|
+
}
|
|
5896
|
+
function normalizeOrigin(origin) {
|
|
5897
|
+
try {
|
|
5898
|
+
const value = new URL(origin);
|
|
5899
|
+
if (value.protocol !== "http:" && value.protocol !== "https:" || value.username || value.password || value.origin === "null") {
|
|
5900
|
+
throw new TypeError("invalid origin");
|
|
5901
|
+
}
|
|
5902
|
+
return value.origin;
|
|
5903
|
+
} catch {
|
|
5904
|
+
throw new DoctorInputError("origin");
|
|
5905
|
+
}
|
|
5906
|
+
}
|
|
5907
|
+
function resolveDoctorApiUrl(env) {
|
|
5908
|
+
const buildDefault = true ? "https://api.01.software" : "https://api.01.software";
|
|
5909
|
+
const configured = SDK_API_URL_KEYS.map(
|
|
5910
|
+
(key) => env.values.get(key)?.value
|
|
5911
|
+
).find((value2) => Boolean(value2));
|
|
5912
|
+
const value = configured ?? buildDefault;
|
|
5913
|
+
try {
|
|
5914
|
+
return new URL(value).toString().replace(/\/$/, "");
|
|
5915
|
+
} catch {
|
|
5916
|
+
return null;
|
|
5917
|
+
}
|
|
5918
|
+
}
|
|
5919
|
+
function inspectAppCredentials(declarations) {
|
|
5920
|
+
if (!declarations || declarations.invalid) {
|
|
5921
|
+
return {
|
|
5922
|
+
credential: { ok: false },
|
|
5923
|
+
check: check(
|
|
5924
|
+
"env.app-credentials",
|
|
5925
|
+
"blocked",
|
|
5926
|
+
declarations?.invalid ? "DoctorEnvFileInvalid" : "DoctorEnvCredentialsBlocked",
|
|
5927
|
+
3
|
|
5928
|
+
)
|
|
5929
|
+
};
|
|
5930
|
+
}
|
|
5931
|
+
const publicSecret = SECRET_KEYS.slice(1).some(
|
|
5932
|
+
(key) => declarations.values.has(key)
|
|
5933
|
+
);
|
|
5934
|
+
const publishable = PUBLISHABLE_KEYS.map(
|
|
5935
|
+
(key) => declarations.values.get(key)
|
|
5936
|
+
).filter((value) => value !== void 0);
|
|
5937
|
+
const secret = declarations.values.get("SOFTWARE_SECRET_KEY");
|
|
5938
|
+
const ambiguous = [
|
|
5939
|
+
...PUBLISHABLE_KEYS,
|
|
5940
|
+
...SECRET_KEYS,
|
|
5941
|
+
...SDK_API_URL_KEYS
|
|
5942
|
+
].some((key) => declarations.ambiguousKeys.has(key));
|
|
5943
|
+
const publishableKey = publishable[0]?.value ?? "";
|
|
5944
|
+
const secretKey = secret?.value ?? "";
|
|
5945
|
+
const apiUrl = resolveDoctorApiUrl(declarations);
|
|
5946
|
+
if (publicSecret || ambiguous || publishable.length !== 1 || !secret || !publishableKey || !secretKey || !publishableKey.startsWith("pk01_") || !/^sk01_[a-f0-9]{40}$/.test(secretKey) || !apiUrl) {
|
|
5947
|
+
return {
|
|
5948
|
+
credential: { ok: false },
|
|
5949
|
+
check: check(
|
|
5950
|
+
"env.app-credentials",
|
|
5951
|
+
"blocked",
|
|
5952
|
+
"DoctorEnvCredentialsBlocked",
|
|
5953
|
+
3
|
|
5954
|
+
)
|
|
5955
|
+
};
|
|
5956
|
+
}
|
|
5957
|
+
return {
|
|
5958
|
+
credential: { ok: true, publishableKey, secretKey, apiUrl },
|
|
5959
|
+
check: check("env.app-credentials", "ready", "DoctorEnvCredentialsReady")
|
|
5960
|
+
};
|
|
5961
|
+
}
|
|
5962
|
+
async function defaultOriginProbe(input) {
|
|
5963
|
+
try {
|
|
5964
|
+
const response = await fetch(new URL(TENANT_CONTEXT_PATH, input.apiUrl), {
|
|
5965
|
+
method: "OPTIONS",
|
|
5966
|
+
signal: AbortSignal.timeout(1e4),
|
|
5967
|
+
credentials: "omit",
|
|
5968
|
+
headers: {
|
|
5969
|
+
Origin: input.origin,
|
|
5970
|
+
"X-Publishable-Key": input.publishableKey,
|
|
5971
|
+
"Access-Control-Request-Method": "GET",
|
|
5972
|
+
"Access-Control-Request-Headers": "x-publishable-key"
|
|
5973
|
+
}
|
|
5974
|
+
});
|
|
5975
|
+
if (response.status === 403) return "denied";
|
|
5976
|
+
if (!response.ok || response.status === 408 || response.status === 429 || response.status === 404 || response.status >= 500) {
|
|
5977
|
+
return "indeterminate";
|
|
5978
|
+
}
|
|
5979
|
+
const allowedOrigin = response.headers.get("access-control-allow-origin");
|
|
5980
|
+
const allowsCredentials = response.headers.get("access-control-allow-credentials")?.toLowerCase() === "true";
|
|
5981
|
+
if (allowedOrigin === input.origin) return "allowed";
|
|
5982
|
+
if (allowedOrigin === "*" && !allowsCredentials) return "allowed";
|
|
5983
|
+
return "denied";
|
|
5984
|
+
} catch {
|
|
5985
|
+
return "indeterminate";
|
|
5986
|
+
}
|
|
5987
|
+
}
|
|
5988
|
+
async function runDoctor(options = {}) {
|
|
5989
|
+
const cwd = options.cwd ?? process.cwd();
|
|
5990
|
+
const origin = options.origin === void 0 ? void 0 : normalizeOrigin(options.origin);
|
|
5991
|
+
const checks = [];
|
|
5992
|
+
const pkg = readPackage(cwd);
|
|
5993
|
+
checks.push(
|
|
5994
|
+
pkg ? check("project.package-json", "ready", "DoctorProjectPackageJsonReady") : check(
|
|
5995
|
+
"project.package-json",
|
|
5996
|
+
"blocked",
|
|
5997
|
+
"DoctorProjectPackageJsonBlocked",
|
|
5998
|
+
3
|
|
5999
|
+
)
|
|
6000
|
+
);
|
|
6001
|
+
const engine = pkg?.engines?.node;
|
|
6002
|
+
checks.push(nodeEngineCheck(engine));
|
|
6003
|
+
const deps = {
|
|
6004
|
+
...pkg?.dependencies ?? {},
|
|
6005
|
+
...pkg?.devDependencies ?? {}
|
|
6006
|
+
};
|
|
6007
|
+
checks.push(
|
|
6008
|
+
"@01.software/sdk" in deps ? check("sdk.declaration", "ready", "DoctorSdkDeclarationReady") : check("sdk.declaration", "blocked", "DoctorSdkDeclarationBlocked", 3)
|
|
6009
|
+
);
|
|
6010
|
+
let sdkInstalled = false;
|
|
6011
|
+
try {
|
|
6012
|
+
createRequire(join3(cwd, "package.json")).resolve("@01.software/sdk/server");
|
|
6013
|
+
sdkInstalled = true;
|
|
6014
|
+
} catch {
|
|
6015
|
+
}
|
|
6016
|
+
checks.push(
|
|
6017
|
+
sdkInstalled ? check("sdk.installation", "ready", "DoctorSdkInstallationReady") : check(
|
|
6018
|
+
"sdk.installation",
|
|
6019
|
+
"attention",
|
|
6020
|
+
"DoctorSdkInstallationAttention"
|
|
6021
|
+
)
|
|
6022
|
+
);
|
|
6023
|
+
const inspected = inspectAppCredentials(
|
|
6024
|
+
readDoctorEnv(cwd, pkg, options.envFile)
|
|
6025
|
+
);
|
|
6026
|
+
checks.push(inspected.check);
|
|
6027
|
+
if (inspected.credential.ok) {
|
|
6028
|
+
const { publishableKey, secretKey, apiUrl } = inspected.credential;
|
|
6029
|
+
try {
|
|
6030
|
+
if (options.tenantContext) {
|
|
6031
|
+
await options.tenantContext({ publishableKey, secretKey, apiUrl });
|
|
6032
|
+
} else {
|
|
6033
|
+
await new TenantIntrospectionApi2({
|
|
6034
|
+
publishableKey,
|
|
6035
|
+
secretKey,
|
|
6036
|
+
apiUrl
|
|
6037
|
+
}).context();
|
|
6038
|
+
}
|
|
6039
|
+
checks.push(check("tenant.context", "ready", "DoctorTenantContextReady"));
|
|
6040
|
+
} catch (error) {
|
|
6041
|
+
checks.push(
|
|
6042
|
+
check(
|
|
6043
|
+
"tenant.context",
|
|
6044
|
+
"blocked",
|
|
6045
|
+
"DoctorTenantContextBlocked",
|
|
6046
|
+
getExitCode(error)
|
|
6047
|
+
)
|
|
6048
|
+
);
|
|
6049
|
+
}
|
|
6050
|
+
if (origin) {
|
|
6051
|
+
const outcome = await (options.originProbe ?? defaultOriginProbe)({
|
|
6052
|
+
origin,
|
|
6053
|
+
apiUrl,
|
|
6054
|
+
publishableKey
|
|
6055
|
+
});
|
|
6056
|
+
checks.push(
|
|
6057
|
+
outcome === "allowed" ? check("origin.cors", "ready", "DoctorOriginCorsReady") : outcome === "denied" ? check("origin.cors", "blocked", "DoctorOriginCorsBlocked", 2) : check("origin.cors", "attention", "DoctorOriginCorsAttention")
|
|
6058
|
+
);
|
|
6059
|
+
}
|
|
6060
|
+
} else {
|
|
6061
|
+
checks.push(
|
|
6062
|
+
check("tenant.context", "blocked", "DoctorTenantContextBlocked", 3)
|
|
6063
|
+
);
|
|
6064
|
+
if (origin)
|
|
6065
|
+
checks.push(
|
|
6066
|
+
check("origin.cors", "attention", "DoctorOriginCorsAttention")
|
|
6067
|
+
);
|
|
6068
|
+
}
|
|
6069
|
+
return {
|
|
6070
|
+
version: 1,
|
|
6071
|
+
status: statusFromChecks(checks),
|
|
6072
|
+
exitCode: compositeExitCode(checks),
|
|
6073
|
+
checks
|
|
6074
|
+
};
|
|
6075
|
+
}
|
|
6076
|
+
function actionText(key, locale) {
|
|
6077
|
+
const table = locale === "ko" ? CLI_I18N_KO : CLI_I18N_EN;
|
|
6078
|
+
return table[key];
|
|
6079
|
+
}
|
|
6080
|
+
function doctorHumanLines(result, locale) {
|
|
6081
|
+
const copy = locale === "ko" ? {
|
|
6082
|
+
status: "\uC0C1\uD0DC",
|
|
6083
|
+
ready: "\uC900\uBE44\uB428",
|
|
6084
|
+
attention: "\uD655\uC778 \uD544\uC694",
|
|
6085
|
+
blocked: "\uCC28\uB2E8\uB428"
|
|
6086
|
+
} : {
|
|
6087
|
+
status: "Status",
|
|
6088
|
+
ready: "ready",
|
|
6089
|
+
attention: "attention",
|
|
6090
|
+
blocked: "blocked"
|
|
6091
|
+
};
|
|
6092
|
+
return [
|
|
6093
|
+
`${copy.status}: ${copy[result.status]}`,
|
|
6094
|
+
...result.checks.map(
|
|
6095
|
+
(item) => `[${copy[item.status]}] ${item.id}: ${actionText(item.action, locale)}`
|
|
6096
|
+
)
|
|
6097
|
+
];
|
|
6098
|
+
}
|
|
6099
|
+
|
|
6100
|
+
// src/commands/doctor.ts
|
|
6101
|
+
function selectedHumanFormat(command) {
|
|
6102
|
+
const options = command.optsWithGlobals();
|
|
6103
|
+
return options.format ?? process.env.OUTPUT_FORMAT;
|
|
6104
|
+
}
|
|
6105
|
+
function registerDoctorCommands(program, agent) {
|
|
6106
|
+
program.command("doctor").description("Check local app integration without exposing credentials").option("--app-env-file <path>", "Read one explicit app environment file").option("--origin <origin>", "Optionally probe one browser origin for CORS").action(async (options, command) => {
|
|
6107
|
+
const format = selectedHumanFormat(command);
|
|
6108
|
+
try {
|
|
6109
|
+
const result = await runDoctor({
|
|
6110
|
+
envFile: options.appEnvFile,
|
|
6111
|
+
origin: options.origin
|
|
6112
|
+
});
|
|
6113
|
+
if (format === "json") {
|
|
6114
|
+
printJson(result);
|
|
6115
|
+
} else if (format === "ndjson") {
|
|
6116
|
+
printResult(result, "ndjson");
|
|
6117
|
+
} else {
|
|
6118
|
+
for (const line of doctorHumanLines(result, detectLocale()))
|
|
6119
|
+
console.log(line);
|
|
6120
|
+
}
|
|
6121
|
+
process.exitCode = result.exitCode;
|
|
6122
|
+
} catch (error) {
|
|
6123
|
+
printError(error, {
|
|
6124
|
+
format: format ?? "table",
|
|
6125
|
+
headlineKey: doctorInputMessageKey(error)
|
|
6126
|
+
});
|
|
6127
|
+
process.exitCode = getExitCode(error);
|
|
6128
|
+
}
|
|
6129
|
+
});
|
|
6130
|
+
configureAgentParser2(
|
|
6131
|
+
agent.command("doctor").description("Check local app integration with stable JSON output").option("--app-env-file <path>", "Read one explicit app environment file").option(
|
|
6132
|
+
"--origin <origin>",
|
|
6133
|
+
"Optionally probe one browser origin for CORS"
|
|
6134
|
+
).option("--pretty", "Print 2-space indented success JSON").option(
|
|
6135
|
+
"--output-file <path>",
|
|
6136
|
+
"Write success JSON to a secure file and print a receipt"
|
|
6137
|
+
).action(async (options, command) => {
|
|
6138
|
+
const output = resolveAgentPrintOptions(command);
|
|
6139
|
+
try {
|
|
6140
|
+
validateAgentOutputTarget(output);
|
|
6141
|
+
const result = await runDoctor({
|
|
6142
|
+
envFile: options.appEnvFile,
|
|
6143
|
+
origin: options.origin
|
|
6144
|
+
});
|
|
6145
|
+
printAgentSuccess(result, output);
|
|
6146
|
+
process.exitCode = 0;
|
|
6147
|
+
} catch (error) {
|
|
6148
|
+
const envelope = printAgentError(error, output);
|
|
6149
|
+
process.exitCode = agentErrorExitCode(envelope.error.code);
|
|
6150
|
+
}
|
|
6151
|
+
})
|
|
6152
|
+
);
|
|
5039
6153
|
}
|
|
5040
6154
|
|
|
5041
6155
|
// src/index.ts
|
|
5042
|
-
var require2 =
|
|
6156
|
+
var require2 = createRequire2(import.meta.url);
|
|
5043
6157
|
var { version } = require2("../package.json");
|
|
5044
|
-
|
|
5045
|
-
program
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
registerCrudCommands(program, getClient, getFormat);
|
|
5059
|
-
registerOrderCommands(program, getClient, getFormat);
|
|
5060
|
-
registerReturnCommands(program, getClient, getFormat);
|
|
5061
|
-
registerCartCommands(program, getClient, getFormat);
|
|
5062
|
-
registerStockCommands(program, getClient, getFormat);
|
|
5063
|
-
registerCommerceSessionCommands(program, getClient, getFormat);
|
|
5064
|
-
registerProductCommands(program, getClient, getFormat);
|
|
5065
|
-
registerDiscountCommands(program, getClient, getFormat);
|
|
5066
|
-
registerShippingCommands(program, getClient, getFormat);
|
|
5067
|
-
registerSchemaCommands(program, getClient, getFormat);
|
|
5068
|
-
registerFeatureCommands(program, getClient, getFormat);
|
|
5069
|
-
|
|
5070
|
-
program
|
|
6158
|
+
function createCliProgram() {
|
|
6159
|
+
const program = new Command();
|
|
6160
|
+
program.name("01").description("CLI for the 01.software platform").version(version).option("--api-key <key>", "API key (sk01_... or pat01_... token)").option("--format <format>", "Output format: json, table, or ndjson").option("--lang <locale>", "Force locale (ko or en)");
|
|
6161
|
+
const getFormat = () => program.opts().format ?? process.env.OUTPUT_FORMAT ?? "json";
|
|
6162
|
+
program.hook("preAction", () => {
|
|
6163
|
+
const lang = program.opts().lang;
|
|
6164
|
+
if (lang === "ko" || lang === "en") setLocale(lang);
|
|
6165
|
+
const format = program.opts().format;
|
|
6166
|
+
if (format) process.env.OUTPUT_FORMAT = format;
|
|
6167
|
+
});
|
|
6168
|
+
const getClient = () => resolveClient(program.opts().apiKey);
|
|
6169
|
+
const getAgentClient = () => resolveClientOrThrow(program.opts().apiKey);
|
|
6170
|
+
const agent = registerAgentCommands(program, getAgentClient);
|
|
6171
|
+
registerDoctorCommands(program, agent);
|
|
6172
|
+
registerCrudCommands(program, getClient, getFormat);
|
|
6173
|
+
registerOrderCommands(program, getClient, getFormat);
|
|
6174
|
+
registerReturnCommands(program, getClient, getFormat);
|
|
6175
|
+
registerCartCommands(program, getClient, getFormat);
|
|
6176
|
+
registerStockCommands(program, getClient, getFormat);
|
|
6177
|
+
registerCommerceSessionCommands(program, getClient, getFormat);
|
|
6178
|
+
registerProductCommands(program, getClient, getFormat);
|
|
6179
|
+
registerDiscountCommands(program, getClient, getFormat);
|
|
6180
|
+
registerShippingCommands(program, getClient, getFormat);
|
|
6181
|
+
registerSchemaCommands(program, getClient, getFormat);
|
|
6182
|
+
registerFeatureCommands(program, getClient, getFormat);
|
|
6183
|
+
registerEmbeddedAppCommands(program, getClient, getFormat);
|
|
6184
|
+
registerAuthCommands(program);
|
|
6185
|
+
return program;
|
|
6186
|
+
}
|
|
6187
|
+
function isDirectExecution() {
|
|
6188
|
+
if (process.argv[1] === void 0) return false;
|
|
6189
|
+
try {
|
|
6190
|
+
return realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url));
|
|
6191
|
+
} catch {
|
|
6192
|
+
return false;
|
|
6193
|
+
}
|
|
6194
|
+
}
|
|
6195
|
+
if (isDirectExecution()) {
|
|
6196
|
+
const program = createCliProgram();
|
|
6197
|
+
process.on("unhandledRejection", (err) => {
|
|
6198
|
+
exitWithError(err, {
|
|
6199
|
+
format: program.opts().format ?? process.env.OUTPUT_FORMAT ?? "json"
|
|
6200
|
+
});
|
|
6201
|
+
});
|
|
6202
|
+
program.parse();
|
|
6203
|
+
}
|
|
6204
|
+
export {
|
|
6205
|
+
createCliProgram
|
|
6206
|
+
};
|
|
5071
6207
|
//# sourceMappingURL=index.js.map
|