@tenderprompt/cli 0.1.29 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.js +96 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -60,6 +60,7 @@ tender --version
|
|
|
60
60
|
tender capabilities --json
|
|
61
61
|
|
|
62
62
|
tender auth login --device --profile edit-preview --artifact artifact_123 --ttl 7d
|
|
63
|
+
tender auth login --device --profile create --shopify-store tender-prompt --json
|
|
63
64
|
|
|
64
65
|
tender app init artifact_123 --dir ./widget --preview --json
|
|
65
66
|
|
package/dist/index.js
CHANGED
|
@@ -295,18 +295,21 @@ Commands:
|
|
|
295
295
|
Examples:
|
|
296
296
|
tender auth login --device --profile edit-preview --artifact artifact_123 --ttl 7d
|
|
297
297
|
tender auth login --device --profile publish --artifact artifact_123 --ttl 7d --save-profile publish
|
|
298
|
+
tender auth login --device --profile create --shopify-store tender-prompt --json
|
|
298
299
|
tender auth status --json`;
|
|
299
300
|
}
|
|
300
301
|
function authLoginHelp() {
|
|
301
|
-
return `Usage: tender auth login --device [--base-url <url>] [--profile <edit-preview|publish|create|db-read>] [--artifact <artifact-id>] [--ttl <7d|14d|30d>] [--save-profile <name>] [--no-poll] [--json]
|
|
302
|
+
return `Usage: tender auth login --device [--base-url <url>] [--shopify-store <store>] [--shopify-app-url <url>] [--profile <edit-preview|publish|create|db-read>] [--artifact <artifact-id>] [--ttl <7d|14d|30d>] [--save-profile <name>] [--no-poll] [--json]
|
|
302
303
|
|
|
303
304
|
Options:
|
|
304
305
|
--device Use the OAuth device-code flow.
|
|
305
306
|
--base-url <url> Tender base URL. Defaults to TENDER_BASE_URL or https://app.tenderprompt.com.
|
|
307
|
+
--shopify-store <store> Approve the device code in Shopify Admin for this store handle.
|
|
308
|
+
--shopify-app-url <url> Approve the device code through a Tender Prompt Shopify App Home URL.
|
|
306
309
|
--profile <value> Token permission profile: edit-preview, publish, create, or db-read. Defaults to edit-preview.
|
|
307
310
|
--artifact <artifact-id> Scope the token to one artifact. Required for normal edit-preview agent work.
|
|
308
311
|
--ttl <value> Token lifetime: 7d, 14d, or 30d. Defaults to 7d.
|
|
309
|
-
--save-profile <name> Local config profile name. Defaults to default.
|
|
312
|
+
--save-profile <name> Local config profile name. Defaults to default, or shopify-<store> with Shopify approval.
|
|
310
313
|
--no-poll Print the verification URL and exit without waiting for approval.
|
|
311
314
|
--json Emit stable JSON for coding agents.
|
|
312
315
|
|
|
@@ -314,6 +317,7 @@ Examples:
|
|
|
314
317
|
tender auth login --device --profile edit-preview --artifact artifact_123 --ttl 7d
|
|
315
318
|
tender auth login --device --profile publish --artifact artifact_123 --ttl 7d --save-profile publish --json
|
|
316
319
|
tender auth login --device --profile create --ttl 7d --save-profile account
|
|
320
|
+
tender auth login --device --profile create --shopify-store tender-prompt --json
|
|
317
321
|
tender auth login --device --profile db-read --artifact artifact_123 --ttl 7d --save-profile db`;
|
|
318
322
|
}
|
|
319
323
|
function authStatusHelp() {
|
|
@@ -2131,6 +2135,55 @@ function parseBaseUrlFlag(args, index) {
|
|
|
2131
2135
|
}
|
|
2132
2136
|
return normalizeBaseUrl(value);
|
|
2133
2137
|
}
|
|
2138
|
+
function parseShopifyStoreHandle(value, flag) {
|
|
2139
|
+
if (!value || value.startsWith('-')) {
|
|
2140
|
+
throw new TenderCliUsageError(`${flag} requires a Shopify Admin store handle.`);
|
|
2141
|
+
}
|
|
2142
|
+
const normalized = value.trim().toLowerCase();
|
|
2143
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(normalized)) {
|
|
2144
|
+
throw new TenderCliUsageError(`${flag} must be a Shopify Admin store handle, such as tender-prompt.`);
|
|
2145
|
+
}
|
|
2146
|
+
return normalized;
|
|
2147
|
+
}
|
|
2148
|
+
function shopifyAppUrlForStore(store) {
|
|
2149
|
+
return `https://admin.shopify.com/store/${store}/apps/tender-prompt/shopify`;
|
|
2150
|
+
}
|
|
2151
|
+
function parseShopifyAppUrlFlag(args, index) {
|
|
2152
|
+
const value = args[index + 1];
|
|
2153
|
+
if (!value || value.startsWith('-')) {
|
|
2154
|
+
throw new TenderCliUsageError('--shopify-app-url requires a Shopify Admin App Home URL.');
|
|
2155
|
+
}
|
|
2156
|
+
let url;
|
|
2157
|
+
try {
|
|
2158
|
+
url = new URL(value);
|
|
2159
|
+
}
|
|
2160
|
+
catch {
|
|
2161
|
+
throw new TenderCliUsageError('--shopify-app-url requires a valid Shopify Admin App Home URL.');
|
|
2162
|
+
}
|
|
2163
|
+
if (url.protocol !== 'https:' || url.hostname !== 'admin.shopify.com') {
|
|
2164
|
+
throw new TenderCliUsageError('--shopify-app-url must start with https://admin.shopify.com/.');
|
|
2165
|
+
}
|
|
2166
|
+
const parts = url.pathname.split('/').filter(Boolean);
|
|
2167
|
+
const deviceSuffix = parts[5] === 'device' ? parts[5] : null;
|
|
2168
|
+
if ((parts.length !== 5 && !(parts.length === 6 && deviceSuffix)) ||
|
|
2169
|
+
parts[0] !== 'store' ||
|
|
2170
|
+
parts[2] !== 'apps' ||
|
|
2171
|
+
parts[4] !== 'shopify') {
|
|
2172
|
+
throw new TenderCliUsageError('--shopify-app-url must look like https://admin.shopify.com/store/<store>/apps/tender-prompt/shopify.');
|
|
2173
|
+
}
|
|
2174
|
+
if (url.search || url.hash) {
|
|
2175
|
+
throw new TenderCliUsageError('--shopify-app-url should not include a query string or hash.');
|
|
2176
|
+
}
|
|
2177
|
+
const store = parseShopifyStoreHandle(parts[1], '--shopify-app-url');
|
|
2178
|
+
const appHandle = parseShopifyStoreHandle(parts[3], '--shopify-app-url');
|
|
2179
|
+
return {
|
|
2180
|
+
store,
|
|
2181
|
+
appUrl: `https://admin.shopify.com/store/${store}/apps/${appHandle}/shopify`,
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
function shopifyDeviceVerificationUrl(input) {
|
|
2185
|
+
return `${input.shopifyAppUrl.replace(/\/+$/, '')}/device?user_code=${encodeURIComponent(input.userCode)}`;
|
|
2186
|
+
}
|
|
2134
2187
|
function parseTokenFlag(args, index) {
|
|
2135
2188
|
const value = args[index + 1];
|
|
2136
2189
|
if (!value || value.startsWith('-')) {
|
|
@@ -4397,8 +4450,11 @@ function parseAuthLoginArgs(args) {
|
|
|
4397
4450
|
}
|
|
4398
4451
|
let device = false;
|
|
4399
4452
|
let baseUrl = null;
|
|
4453
|
+
let shopifyAppUrl = null;
|
|
4454
|
+
let shopifyStore = null;
|
|
4400
4455
|
let tokenProfile = 'edit-preview';
|
|
4401
4456
|
let saveProfile = DEFAULT_PROFILE_NAME;
|
|
4457
|
+
let saveProfileExplicit = false;
|
|
4402
4458
|
let artifactId = null;
|
|
4403
4459
|
let ttl = '7d';
|
|
4404
4460
|
let json = false;
|
|
@@ -4423,6 +4479,25 @@ function parseAuthLoginArgs(args) {
|
|
|
4423
4479
|
index += 1;
|
|
4424
4480
|
continue;
|
|
4425
4481
|
}
|
|
4482
|
+
if (arg === '--shopify-store') {
|
|
4483
|
+
if (shopifyAppUrl) {
|
|
4484
|
+
throw new TenderCliUsageError('--shopify-store cannot be combined with --shopify-app-url.');
|
|
4485
|
+
}
|
|
4486
|
+
shopifyStore = parseShopifyStoreHandle(args[index + 1], '--shopify-store');
|
|
4487
|
+
shopifyAppUrl = shopifyAppUrlForStore(shopifyStore);
|
|
4488
|
+
index += 1;
|
|
4489
|
+
continue;
|
|
4490
|
+
}
|
|
4491
|
+
if (arg === '--shopify-app-url') {
|
|
4492
|
+
if (shopifyAppUrl) {
|
|
4493
|
+
throw new TenderCliUsageError('--shopify-app-url cannot be combined with --shopify-store.');
|
|
4494
|
+
}
|
|
4495
|
+
const parsed = parseShopifyAppUrlFlag(args, index);
|
|
4496
|
+
shopifyStore = parsed.store;
|
|
4497
|
+
shopifyAppUrl = parsed.appUrl;
|
|
4498
|
+
index += 1;
|
|
4499
|
+
continue;
|
|
4500
|
+
}
|
|
4426
4501
|
if (arg === '--profile') {
|
|
4427
4502
|
tokenProfile = parseTokenProfile(args[index + 1]);
|
|
4428
4503
|
index += 1;
|
|
@@ -4430,6 +4505,7 @@ function parseAuthLoginArgs(args) {
|
|
|
4430
4505
|
}
|
|
4431
4506
|
if (arg === '--save-profile') {
|
|
4432
4507
|
saveProfile = parseProfileName(args[index + 1], '--save-profile');
|
|
4508
|
+
saveProfileExplicit = true;
|
|
4433
4509
|
index += 1;
|
|
4434
4510
|
continue;
|
|
4435
4511
|
}
|
|
@@ -4459,9 +4535,14 @@ function parseAuthLoginArgs(args) {
|
|
|
4459
4535
|
if (tokenProfile === 'db-read' && !artifactId) {
|
|
4460
4536
|
throw new TenderCliUsageError('--profile db-read requires --artifact <artifact-id>.');
|
|
4461
4537
|
}
|
|
4538
|
+
if (shopifyStore && !saveProfileExplicit) {
|
|
4539
|
+
saveProfile = `shopify-${shopifyStore}`;
|
|
4540
|
+
}
|
|
4462
4541
|
return {
|
|
4463
4542
|
command: 'auth login',
|
|
4464
4543
|
baseUrl,
|
|
4544
|
+
shopifyAppUrl,
|
|
4545
|
+
shopifyStore,
|
|
4465
4546
|
device,
|
|
4466
4547
|
tokenProfile,
|
|
4467
4548
|
saveProfile,
|
|
@@ -8249,15 +8330,24 @@ async function runAuthLogin(command, io, runtime) {
|
|
|
8249
8330
|
if (!deviceResponse.ok || !devicePayload?.device_code || !devicePayload.user_code || !devicePayload.verification_uri_complete) {
|
|
8250
8331
|
throw new Error(devicePayload?.error_description ?? devicePayload?.error ?? `Device authorization failed with HTTP ${deviceResponse.status}.`);
|
|
8251
8332
|
}
|
|
8333
|
+
const verificationUriComplete = command.shopifyAppUrl
|
|
8334
|
+
? shopifyDeviceVerificationUrl({
|
|
8335
|
+
shopifyAppUrl: command.shopifyAppUrl,
|
|
8336
|
+
userCode: devicePayload.user_code,
|
|
8337
|
+
})
|
|
8338
|
+
: devicePayload.verification_uri_complete;
|
|
8339
|
+
const verificationUri = command.shopifyAppUrl ? `${command.shopifyAppUrl}/device` : devicePayload.verification_uri;
|
|
8252
8340
|
const pendingResult = {
|
|
8253
8341
|
ok: true,
|
|
8254
8342
|
command: command.command,
|
|
8255
8343
|
baseUrl,
|
|
8344
|
+
shopifyAppUrl: command.shopifyAppUrl,
|
|
8345
|
+
shopifyStore: command.shopifyStore,
|
|
8256
8346
|
profile: command.tokenProfile,
|
|
8257
8347
|
saveProfile: command.saveProfile,
|
|
8258
8348
|
userCode: devicePayload.user_code,
|
|
8259
|
-
verificationUri
|
|
8260
|
-
verificationUriComplete
|
|
8349
|
+
verificationUri,
|
|
8350
|
+
verificationUriComplete,
|
|
8261
8351
|
expiresIn: devicePayload.expires_in ?? null,
|
|
8262
8352
|
interval: devicePayload.interval ?? null,
|
|
8263
8353
|
};
|
|
@@ -8266,13 +8356,13 @@ async function runAuthLogin(command, io, runtime) {
|
|
|
8266
8356
|
io.stdout(JSON.stringify(pendingResult, null, 2));
|
|
8267
8357
|
}
|
|
8268
8358
|
else {
|
|
8269
|
-
io.stdout([`verification_url: ${
|
|
8359
|
+
io.stdout([`verification_url: ${verificationUriComplete}`, `user_code: ${devicePayload.user_code}`].join('\n'));
|
|
8270
8360
|
}
|
|
8271
8361
|
return 0;
|
|
8272
8362
|
}
|
|
8273
8363
|
if (!command.json) {
|
|
8274
8364
|
io.stdout([
|
|
8275
|
-
`Open this URL to approve Tender CLI access: ${
|
|
8365
|
+
`Open this URL to approve Tender CLI access: ${verificationUriComplete}`,
|
|
8276
8366
|
`User code: ${devicePayload.user_code}`,
|
|
8277
8367
|
].join('\n'));
|
|
8278
8368
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenderprompt/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"tender": "bin/tender.js"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"prepack": "yarn build"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@tenderprompt/tender-app-validator": "0.1.
|
|
26
|
+
"@tenderprompt/tender-app-validator": "0.1.5"
|
|
27
27
|
},
|
|
28
28
|
"engines": {
|
|
29
29
|
"node": ">=20"
|