@tenderprompt/cli 0.1.30 → 0.1.31

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.
Files changed (2) hide show
  1. package/dist/index.js +65 -17
  2. 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 parseShopifyAppUrlFlag(args, index) {
2152
- const value = args[index + 1];
2181
+ function parseShopifyAppUrl(value, flag) {
2153
2182
  if (!value || value.startsWith('-')) {
2154
- throw new TenderCliUsageError('--shopify-app-url requires a Shopify Admin App Home URL.');
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('--shopify-app-url requires a valid Shopify Admin App Home URL.');
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('--shopify-app-url must start with https://admin.shopify.com/.');
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('--shopify-app-url must look like https://admin.shopify.com/store/<store>/apps/tender-prompt/shopify.');
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('--shopify-app-url should not include a query string or hash.');
2204
+ throw new TenderCliUsageError(`${flag} should not include a query string or hash.`);
2176
2205
  }
2177
- const store = parseShopifyStoreHandle(parts[1], '--shopify-app-url');
2178
- const appHandle = parseShopifyStoreHandle(parts[3], '--shopify-app-url');
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.replace(/\/+$/, '')}/device?user_code=${encodeURIComponent(input.userCode)}`;
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];
@@ -8226,6 +8261,8 @@ async function runAuthStatus(command, io, runtime) {
8226
8261
  artifactId: profile?.artifactId ?? null,
8227
8262
  permissions: profile?.permissions ?? [],
8228
8263
  expiresAt: formatExpiry(profile?.expiresAt),
8264
+ shopifyAppUrl: profile?.shopifyAppUrl ?? null,
8265
+ shopifyStore: profile?.shopifyStore ?? null,
8229
8266
  };
8230
8267
  if (command.json) {
8231
8268
  io.stdout(JSON.stringify(result, null, 2));
@@ -8240,6 +8277,7 @@ async function runAuthStatus(command, io, runtime) {
8240
8277
  `app_id: ${profile.artifactId ?? '(account)'}`,
8241
8278
  `permissions: ${(profile.permissions ?? []).join(' ') || '(unknown)'}`,
8242
8279
  `expires_at: ${formatExpiry(profile.expiresAt) ?? '(unknown)'}`,
8280
+ `shopify_app_url: ${profile.shopifyAppUrl ?? '(none)'}`,
8243
8281
  ].join('\n'));
8244
8282
  }
8245
8283
  else {
@@ -8284,6 +8322,8 @@ async function runAuthStatus(command, io, runtime) {
8284
8322
  artifactId: profile?.artifactId ?? null,
8285
8323
  permissions: profile?.permissions ?? [],
8286
8324
  expiresAt: formatExpiry(profile?.expiresAt),
8325
+ shopifyAppUrl: profile?.shopifyAppUrl ?? null,
8326
+ shopifyStore: profile?.shopifyStore ?? null,
8287
8327
  };
8288
8328
  if (command.json) {
8289
8329
  io.stdout(JSON.stringify(result, null, 2));
@@ -8298,6 +8338,7 @@ async function runAuthStatus(command, io, runtime) {
8298
8338
  `app_id: ${profile.artifactId ?? '(account)'}`,
8299
8339
  `permissions: ${(profile.permissions ?? []).join(' ') || '(unknown)'}`,
8300
8340
  `expires_at: ${formatExpiry(profile.expiresAt) ?? '(unknown)'}`,
8341
+ `shopify_app_url: ${profile.shopifyAppUrl ?? '(none)'}`,
8301
8342
  ].join('\n'));
8302
8343
  }
8303
8344
  else {
@@ -8314,7 +8355,11 @@ async function runAuthLogin(command, io, runtime) {
8314
8355
  const fetcher = runtime.fetcher ?? fetch;
8315
8356
  const sleeper = runtime.sleeper ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
8316
8357
  const now = runtime.now ?? Date.now;
8317
- const baseUrl = command.baseUrl ?? readDefaultBaseUrl(env);
8358
+ const config = await readConfig(env);
8359
+ const existingProfile = config.profiles?.[command.saveProfile] ?? null;
8360
+ const baseUrl = command.baseUrl ?? existingProfile?.baseUrl ?? readDefaultBaseUrl(env);
8361
+ const shopifyAppUrl = command.shopifyAppUrl ?? existingProfile?.shopifyAppUrl ?? null;
8362
+ const shopifyStore = command.shopifyStore ?? existingProfile?.shopifyStore ?? null;
8318
8363
  const deviceResponse = await fetcher(`${baseUrl}/oauth/device/code`, {
8319
8364
  method: 'POST',
8320
8365
  headers: {
@@ -8330,19 +8375,19 @@ async function runAuthLogin(command, io, runtime) {
8330
8375
  if (!deviceResponse.ok || !devicePayload?.device_code || !devicePayload.user_code || !devicePayload.verification_uri_complete) {
8331
8376
  throw new Error(devicePayload?.error_description ?? devicePayload?.error ?? `Device authorization failed with HTTP ${deviceResponse.status}.`);
8332
8377
  }
8333
- const verificationUriComplete = command.shopifyAppUrl
8378
+ const verificationUriComplete = shopifyAppUrl
8334
8379
  ? shopifyDeviceVerificationUrl({
8335
- shopifyAppUrl: command.shopifyAppUrl,
8380
+ shopifyAppUrl,
8336
8381
  userCode: devicePayload.user_code,
8337
8382
  })
8338
8383
  : devicePayload.verification_uri_complete;
8339
- const verificationUri = command.shopifyAppUrl ? `${command.shopifyAppUrl}/device` : devicePayload.verification_uri;
8384
+ const verificationUri = shopifyAppUrl ? shopifyDeviceVerificationUri(shopifyAppUrl) : devicePayload.verification_uri;
8340
8385
  const pendingResult = {
8341
8386
  ok: true,
8342
8387
  command: command.command,
8343
8388
  baseUrl,
8344
- shopifyAppUrl: command.shopifyAppUrl,
8345
- shopifyStore: command.shopifyStore,
8389
+ shopifyAppUrl,
8390
+ shopifyStore,
8346
8391
  profile: command.tokenProfile,
8347
8392
  saveProfile: command.saveProfile,
8348
8393
  userCode: devicePayload.user_code,
@@ -8383,7 +8428,6 @@ async function runAuthLogin(command, io, runtime) {
8383
8428
  });
8384
8429
  const tokenPayload = await parseJsonResponse(tokenResponse);
8385
8430
  if (tokenResponse.ok && tokenPayload?.access_token) {
8386
- const config = await readConfig(env);
8387
8431
  const profiles = config.profiles ?? {};
8388
8432
  profiles[command.saveProfile] = {
8389
8433
  baseUrl,
@@ -8393,6 +8437,8 @@ async function runAuthLogin(command, io, runtime) {
8393
8437
  artifactId: tokenPayload.artifact_id,
8394
8438
  expiresAt: tokenPayload.expires_at,
8395
8439
  permissions: splitScope(tokenPayload.scope),
8440
+ ...(shopifyAppUrl ? { shopifyAppUrl } : {}),
8441
+ ...(shopifyStore ? { shopifyStore } : {}),
8396
8442
  };
8397
8443
  await writeConfig(env, {
8398
8444
  ...config,
@@ -8410,6 +8456,8 @@ async function runAuthLogin(command, io, runtime) {
8410
8456
  artifactId: tokenPayload.artifact_id ?? null,
8411
8457
  permissions: splitScope(tokenPayload.scope),
8412
8458
  expiresAt: formatExpiry(tokenPayload.expires_at),
8459
+ shopifyAppUrl,
8460
+ shopifyStore,
8413
8461
  configPath: readConfigPath(env),
8414
8462
  };
8415
8463
  if (command.json) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tenderprompt/cli",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "tender": "bin/tender.js"