@tenderprompt/cli 0.1.30 → 0.1.32
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 +84 -17
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2037,8 +2037,38 @@ function normalizeStoredProfile(value) {
|
|
|
2037
2037
|
permissions: Array.isArray(record.permissions)
|
|
2038
2038
|
? record.permissions.filter((permission) => typeof permission === 'string')
|
|
2039
2039
|
: undefined,
|
|
2040
|
+
...normalizeStoredShopifyContext(record),
|
|
2040
2041
|
};
|
|
2041
2042
|
}
|
|
2043
|
+
function normalizeStoredShopifyContext(record) {
|
|
2044
|
+
const shopifyAppUrl = typeof record.shopifyAppUrl === 'string' ? record.shopifyAppUrl : null;
|
|
2045
|
+
if (shopifyAppUrl) {
|
|
2046
|
+
try {
|
|
2047
|
+
const parsed = parseShopifyAppUrl(shopifyAppUrl, 'profile.shopifyAppUrl');
|
|
2048
|
+
return {
|
|
2049
|
+
shopifyAppUrl: parsed.appUrl,
|
|
2050
|
+
shopifyStore: parsed.store,
|
|
2051
|
+
};
|
|
2052
|
+
}
|
|
2053
|
+
catch {
|
|
2054
|
+
return {};
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
const shopifyStore = typeof record.shopifyStore === 'string' ? record.shopifyStore : null;
|
|
2058
|
+
if (shopifyStore) {
|
|
2059
|
+
try {
|
|
2060
|
+
const store = parseShopifyStoreHandle(shopifyStore, 'profile.shopifyStore');
|
|
2061
|
+
return {
|
|
2062
|
+
shopifyAppUrl: shopifyAppUrlForStore(store),
|
|
2063
|
+
shopifyStore: store,
|
|
2064
|
+
};
|
|
2065
|
+
}
|
|
2066
|
+
catch {
|
|
2067
|
+
return {};
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
return {};
|
|
2071
|
+
}
|
|
2042
2072
|
function normalizeConfig(value) {
|
|
2043
2073
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
2044
2074
|
return {};
|
|
@@ -2148,20 +2178,19 @@ function parseShopifyStoreHandle(value, flag) {
|
|
|
2148
2178
|
function shopifyAppUrlForStore(store) {
|
|
2149
2179
|
return `https://admin.shopify.com/store/${store}/apps/tender-prompt/shopify`;
|
|
2150
2180
|
}
|
|
2151
|
-
function
|
|
2152
|
-
const value = args[index + 1];
|
|
2181
|
+
function parseShopifyAppUrl(value, flag) {
|
|
2153
2182
|
if (!value || value.startsWith('-')) {
|
|
2154
|
-
throw new TenderCliUsageError(
|
|
2183
|
+
throw new TenderCliUsageError(`${flag} requires a Shopify Admin App Home URL.`);
|
|
2155
2184
|
}
|
|
2156
2185
|
let url;
|
|
2157
2186
|
try {
|
|
2158
2187
|
url = new URL(value);
|
|
2159
2188
|
}
|
|
2160
2189
|
catch {
|
|
2161
|
-
throw new TenderCliUsageError(
|
|
2190
|
+
throw new TenderCliUsageError(`${flag} requires a valid Shopify Admin App Home URL.`);
|
|
2162
2191
|
}
|
|
2163
2192
|
if (url.protocol !== 'https:' || url.hostname !== 'admin.shopify.com') {
|
|
2164
|
-
throw new TenderCliUsageError(
|
|
2193
|
+
throw new TenderCliUsageError(`${flag} must start with https://admin.shopify.com/.`);
|
|
2165
2194
|
}
|
|
2166
2195
|
const parts = url.pathname.split('/').filter(Boolean);
|
|
2167
2196
|
const deviceSuffix = parts[5] === 'device' ? parts[5] : null;
|
|
@@ -2169,20 +2198,26 @@ function parseShopifyAppUrlFlag(args, index) {
|
|
|
2169
2198
|
parts[0] !== 'store' ||
|
|
2170
2199
|
parts[2] !== 'apps' ||
|
|
2171
2200
|
parts[4] !== 'shopify') {
|
|
2172
|
-
throw new TenderCliUsageError(
|
|
2201
|
+
throw new TenderCliUsageError(`${flag} must look like https://admin.shopify.com/store/<store>/apps/tender-prompt/shopify.`);
|
|
2173
2202
|
}
|
|
2174
2203
|
if (url.search || url.hash) {
|
|
2175
|
-
throw new TenderCliUsageError(
|
|
2204
|
+
throw new TenderCliUsageError(`${flag} should not include a query string or hash.`);
|
|
2176
2205
|
}
|
|
2177
|
-
const store = parseShopifyStoreHandle(parts[1],
|
|
2178
|
-
const appHandle = parseShopifyStoreHandle(parts[3],
|
|
2206
|
+
const store = parseShopifyStoreHandle(parts[1], flag);
|
|
2207
|
+
const appHandle = parseShopifyStoreHandle(parts[3], flag);
|
|
2179
2208
|
return {
|
|
2180
2209
|
store,
|
|
2181
2210
|
appUrl: `https://admin.shopify.com/store/${store}/apps/${appHandle}/shopify`,
|
|
2182
2211
|
};
|
|
2183
2212
|
}
|
|
2213
|
+
function parseShopifyAppUrlFlag(args, index) {
|
|
2214
|
+
return parseShopifyAppUrl(args[index + 1], '--shopify-app-url');
|
|
2215
|
+
}
|
|
2216
|
+
function shopifyDeviceVerificationUri(shopifyAppUrl) {
|
|
2217
|
+
return `${shopifyAppUrl.replace(/\/+$/, '')}/device`;
|
|
2218
|
+
}
|
|
2184
2219
|
function shopifyDeviceVerificationUrl(input) {
|
|
2185
|
-
return `${input.shopifyAppUrl
|
|
2220
|
+
return `${shopifyDeviceVerificationUri(input.shopifyAppUrl)}?user_code=${encodeURIComponent(input.userCode)}`;
|
|
2186
2221
|
}
|
|
2187
2222
|
function parseTokenFlag(args, index) {
|
|
2188
2223
|
const value = args[index + 1];
|
|
@@ -8013,6 +8048,11 @@ function readObjectString(value, key) {
|
|
|
8013
8048
|
const field = record?.[key];
|
|
8014
8049
|
return typeof field === 'string' && field.trim() ? field : null;
|
|
8015
8050
|
}
|
|
8051
|
+
function readObjectArray(value, key) {
|
|
8052
|
+
const record = readObject(value);
|
|
8053
|
+
const field = record?.[key];
|
|
8054
|
+
return Array.isArray(field) ? field : [];
|
|
8055
|
+
}
|
|
8016
8056
|
function readPreviewUrlFromJob(job) {
|
|
8017
8057
|
return readObjectString(job?.result, 'previewUrl');
|
|
8018
8058
|
}
|
|
@@ -8037,8 +8077,22 @@ function readReleaseGitRefFromResult(result) {
|
|
|
8037
8077
|
function formatPublishResultLines(result) {
|
|
8038
8078
|
const record = readObject(result);
|
|
8039
8079
|
const releaseGitRef = readReleaseGitRefFromResult(result);
|
|
8080
|
+
const publishedAssets = readObjectArray(record, 'publishedAssets');
|
|
8081
|
+
const pinnedClientAsset = publishedAssets
|
|
8082
|
+
.map((asset) => readObject(asset))
|
|
8083
|
+
.find((asset) => asset?.sourcePath === 'client.js' && readObjectString(asset, 'pinnedUrl')) ??
|
|
8084
|
+
publishedAssets
|
|
8085
|
+
.map((asset) => readObject(asset))
|
|
8086
|
+
.find((asset) => asset?.assetPath === 'client.js' && readObjectString(asset, 'pinnedUrl'));
|
|
8087
|
+
const integrationSnippets = readObject(record?.integrationSnippets);
|
|
8088
|
+
const pinnedClientUrl = readObjectString(pinnedClientAsset, 'pinnedUrl');
|
|
8089
|
+
const pinnedModuleScript = readObjectString(integrationSnippets, 'moduleScript');
|
|
8040
8090
|
return [
|
|
8041
8091
|
...(readObjectString(record, 'publishedUrl') ? [`published_url: ${readObjectString(record, 'publishedUrl')}`] : []),
|
|
8092
|
+
...(readObjectString(record, 'versionUrl') ? [`version_url: ${readObjectString(record, 'versionUrl')}`] : []),
|
|
8093
|
+
...(readObjectString(record, 'releaseId') ? [`release_id: ${readObjectString(record, 'releaseId')}`] : []),
|
|
8094
|
+
...(pinnedClientUrl ? [`pinned_client_asset: ${pinnedClientUrl}`] : []),
|
|
8095
|
+
...(pinnedModuleScript ? [`pinned_module_script: ${pinnedModuleScript}`] : []),
|
|
8042
8096
|
...(releaseGitRef?.tagName ? [`release_tag: ${releaseGitRef.tagName}`] : []),
|
|
8043
8097
|
...(releaseGitRef?.commitSha ? [`source_commit: ${releaseGitRef.commitSha}`] : []),
|
|
8044
8098
|
];
|
|
@@ -8226,6 +8280,8 @@ async function runAuthStatus(command, io, runtime) {
|
|
|
8226
8280
|
artifactId: profile?.artifactId ?? null,
|
|
8227
8281
|
permissions: profile?.permissions ?? [],
|
|
8228
8282
|
expiresAt: formatExpiry(profile?.expiresAt),
|
|
8283
|
+
shopifyAppUrl: profile?.shopifyAppUrl ?? null,
|
|
8284
|
+
shopifyStore: profile?.shopifyStore ?? null,
|
|
8229
8285
|
};
|
|
8230
8286
|
if (command.json) {
|
|
8231
8287
|
io.stdout(JSON.stringify(result, null, 2));
|
|
@@ -8240,6 +8296,7 @@ async function runAuthStatus(command, io, runtime) {
|
|
|
8240
8296
|
`app_id: ${profile.artifactId ?? '(account)'}`,
|
|
8241
8297
|
`permissions: ${(profile.permissions ?? []).join(' ') || '(unknown)'}`,
|
|
8242
8298
|
`expires_at: ${formatExpiry(profile.expiresAt) ?? '(unknown)'}`,
|
|
8299
|
+
`shopify_app_url: ${profile.shopifyAppUrl ?? '(none)'}`,
|
|
8243
8300
|
].join('\n'));
|
|
8244
8301
|
}
|
|
8245
8302
|
else {
|
|
@@ -8284,6 +8341,8 @@ async function runAuthStatus(command, io, runtime) {
|
|
|
8284
8341
|
artifactId: profile?.artifactId ?? null,
|
|
8285
8342
|
permissions: profile?.permissions ?? [],
|
|
8286
8343
|
expiresAt: formatExpiry(profile?.expiresAt),
|
|
8344
|
+
shopifyAppUrl: profile?.shopifyAppUrl ?? null,
|
|
8345
|
+
shopifyStore: profile?.shopifyStore ?? null,
|
|
8287
8346
|
};
|
|
8288
8347
|
if (command.json) {
|
|
8289
8348
|
io.stdout(JSON.stringify(result, null, 2));
|
|
@@ -8298,6 +8357,7 @@ async function runAuthStatus(command, io, runtime) {
|
|
|
8298
8357
|
`app_id: ${profile.artifactId ?? '(account)'}`,
|
|
8299
8358
|
`permissions: ${(profile.permissions ?? []).join(' ') || '(unknown)'}`,
|
|
8300
8359
|
`expires_at: ${formatExpiry(profile.expiresAt) ?? '(unknown)'}`,
|
|
8360
|
+
`shopify_app_url: ${profile.shopifyAppUrl ?? '(none)'}`,
|
|
8301
8361
|
].join('\n'));
|
|
8302
8362
|
}
|
|
8303
8363
|
else {
|
|
@@ -8314,7 +8374,11 @@ async function runAuthLogin(command, io, runtime) {
|
|
|
8314
8374
|
const fetcher = runtime.fetcher ?? fetch;
|
|
8315
8375
|
const sleeper = runtime.sleeper ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
|
|
8316
8376
|
const now = runtime.now ?? Date.now;
|
|
8317
|
-
const
|
|
8377
|
+
const config = await readConfig(env);
|
|
8378
|
+
const existingProfile = config.profiles?.[command.saveProfile] ?? null;
|
|
8379
|
+
const baseUrl = command.baseUrl ?? existingProfile?.baseUrl ?? readDefaultBaseUrl(env);
|
|
8380
|
+
const shopifyAppUrl = command.shopifyAppUrl ?? existingProfile?.shopifyAppUrl ?? null;
|
|
8381
|
+
const shopifyStore = command.shopifyStore ?? existingProfile?.shopifyStore ?? null;
|
|
8318
8382
|
const deviceResponse = await fetcher(`${baseUrl}/oauth/device/code`, {
|
|
8319
8383
|
method: 'POST',
|
|
8320
8384
|
headers: {
|
|
@@ -8330,19 +8394,19 @@ async function runAuthLogin(command, io, runtime) {
|
|
|
8330
8394
|
if (!deviceResponse.ok || !devicePayload?.device_code || !devicePayload.user_code || !devicePayload.verification_uri_complete) {
|
|
8331
8395
|
throw new Error(devicePayload?.error_description ?? devicePayload?.error ?? `Device authorization failed with HTTP ${deviceResponse.status}.`);
|
|
8332
8396
|
}
|
|
8333
|
-
const verificationUriComplete =
|
|
8397
|
+
const verificationUriComplete = shopifyAppUrl
|
|
8334
8398
|
? shopifyDeviceVerificationUrl({
|
|
8335
|
-
shopifyAppUrl
|
|
8399
|
+
shopifyAppUrl,
|
|
8336
8400
|
userCode: devicePayload.user_code,
|
|
8337
8401
|
})
|
|
8338
8402
|
: devicePayload.verification_uri_complete;
|
|
8339
|
-
const verificationUri =
|
|
8403
|
+
const verificationUri = shopifyAppUrl ? shopifyDeviceVerificationUri(shopifyAppUrl) : devicePayload.verification_uri;
|
|
8340
8404
|
const pendingResult = {
|
|
8341
8405
|
ok: true,
|
|
8342
8406
|
command: command.command,
|
|
8343
8407
|
baseUrl,
|
|
8344
|
-
shopifyAppUrl
|
|
8345
|
-
shopifyStore
|
|
8408
|
+
shopifyAppUrl,
|
|
8409
|
+
shopifyStore,
|
|
8346
8410
|
profile: command.tokenProfile,
|
|
8347
8411
|
saveProfile: command.saveProfile,
|
|
8348
8412
|
userCode: devicePayload.user_code,
|
|
@@ -8383,7 +8447,6 @@ async function runAuthLogin(command, io, runtime) {
|
|
|
8383
8447
|
});
|
|
8384
8448
|
const tokenPayload = await parseJsonResponse(tokenResponse);
|
|
8385
8449
|
if (tokenResponse.ok && tokenPayload?.access_token) {
|
|
8386
|
-
const config = await readConfig(env);
|
|
8387
8450
|
const profiles = config.profiles ?? {};
|
|
8388
8451
|
profiles[command.saveProfile] = {
|
|
8389
8452
|
baseUrl,
|
|
@@ -8393,6 +8456,8 @@ async function runAuthLogin(command, io, runtime) {
|
|
|
8393
8456
|
artifactId: tokenPayload.artifact_id,
|
|
8394
8457
|
expiresAt: tokenPayload.expires_at,
|
|
8395
8458
|
permissions: splitScope(tokenPayload.scope),
|
|
8459
|
+
...(shopifyAppUrl ? { shopifyAppUrl } : {}),
|
|
8460
|
+
...(shopifyStore ? { shopifyStore } : {}),
|
|
8396
8461
|
};
|
|
8397
8462
|
await writeConfig(env, {
|
|
8398
8463
|
...config,
|
|
@@ -8410,6 +8475,8 @@ async function runAuthLogin(command, io, runtime) {
|
|
|
8410
8475
|
artifactId: tokenPayload.artifact_id ?? null,
|
|
8411
8476
|
permissions: splitScope(tokenPayload.scope),
|
|
8412
8477
|
expiresAt: formatExpiry(tokenPayload.expires_at),
|
|
8478
|
+
shopifyAppUrl,
|
|
8479
|
+
shopifyStore,
|
|
8413
8480
|
configPath: readConfigPath(env),
|
|
8414
8481
|
};
|
|
8415
8482
|
if (command.json) {
|