@solana-mobile/dapp-store-cli 0.11.0 → 0.13.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/lib/CliUtils.js CHANGED
@@ -145,6 +145,7 @@ import { readFile } from 'fs/promises';
145
145
  var cliPackage = JSON.parse((await readFile(new URL("./package.json", import.meta.url))).toString());
146
146
  import boxen from "boxen";
147
147
  import ver from "semver";
148
+ import path from "path";
148
149
  import { CachedStorageDriver } from "./upload/CachedStorageDriver.js";
149
150
  import { EnvVariables } from "./config/index.js";
150
151
  import { S3Client } from "@aws-sdk/client-s3";
@@ -154,12 +155,12 @@ export var Constants = function Constants() {
154
155
  "use strict";
155
156
  _class_call_check(this, Constants);
156
157
  };
157
- _define_property(Constants, "CLI_VERSION", "0.11.0");
158
+ _define_property(Constants, "CLI_VERSION", "0.13.0");
158
159
  _define_property(Constants, "CONFIG_FILE_NAME", "config.yaml");
159
160
  _define_property(Constants, "DEFAULT_RPC_DEVNET", "https://api.devnet.solana.com");
160
161
  _define_property(Constants, "DEFAULT_PRIORITY_FEE", 500000);
161
162
  _define_property(Constants, "getConfigFilePath", function() {
162
- return "".concat(process.cwd(), "/").concat(Constants.CONFIG_FILE_NAME);
163
+ return path.join(process.cwd(), Constants.CONFIG_FILE_NAME);
163
164
  });
164
165
  export var debug = debugModule("CLI");
165
166
  export var checkForSelfUpdate = function() {
@@ -255,7 +255,14 @@ export var createReleaseCommand = function(param) {
255
255
  4,
256
256
  writeToPublishDetails({
257
257
  release: {
258
- address: releaseAddress
258
+ address: releaseAddress,
259
+ android_details: {
260
+ cert_fingerprint: config.release.android_details.cert_fingerprint,
261
+ min_sdk: config.release.android_details.min_sdk,
262
+ version: config.release.android_details.version,
263
+ version_code: config.release.android_details.version_code,
264
+ locales: config.release.android_details.locales
265
+ }
259
266
  },
260
267
  lastSubmittedVersionOnChain: {
261
268
  address: releaseAddress,
@@ -2,10 +2,11 @@ import { dump } from "js-yaml";
2
2
  import { readFile } from 'fs/promises';
3
3
  var releaseSchema = JSON.parse((await readFile(new URL("../../generated/config_obj.json", import.meta.url))).toString());
4
4
  import fs from "fs";
5
+ import path from "path";
5
6
  import { Constants } from "../../CliUtils.js";
6
7
  export var initScaffold = function() {
7
8
  var outputYaml = Constants.CONFIG_FILE_NAME;
8
- var outFile = "".concat(process.cwd(), "/").concat(outputYaml);
9
+ var outFile = path.join(process.cwd(), outputYaml);
9
10
  if (fs.existsSync(outFile)) {
10
11
  throw Error("Configuration file already present; please use to intialize a new config file.");
11
12
  }
@@ -260,7 +260,7 @@ export var loadPublishDetails = function(configPath) {
260
260
  export var loadPublishDetailsWithChecks = function() {
261
261
  var buildToolsDir = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : null;
262
262
  return _async_to_generator(function() {
263
- var _config_app_media_find, _config_app_media, _config_release_media_find, _config_release_media, _config_release_media_find1, _config_release_media1, _config_release_media_find2, _config_release_media2, _config_release_media3, _config_release_media4, config, apkEntry, apkPath, _, appIcon, iconPath, iconBuffer, releaseIcon, iconPath1, banner, bannerPath, featureGraphic, featureGraphicPath, screenshots, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, item, mediaPath, err, videos, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, video, mediaPath1, err, googlePkg, pkgCompare, alpha_testers, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, wallet;
263
+ var _config_release_android_details, _config_release, _config_app_media_find, _config_app_media, _config_release_media_find, _config_release_media, _config_release_media_find1, _config_release_media1, _config_release_media_find2, _config_release_media2, _config_release_media3, _config_release_media4, config, apkEntry, apkPath, developerOverridenLocales, _, appIcon, iconPath, iconBuffer, releaseIcon, iconPath1, banner, bannerPath, featureGraphic, featureGraphicPath, screenshots, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, item, mediaPath, err, videos, _iteratorNormalCompletion1, _didIteratorError1, _iteratorError1, _iterator1, _step1, video, mediaPath1, err, googlePkg, pkgCompare, alpha_testers, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, wallet;
264
264
  return _ts_generator(this, function(_state) {
265
265
  switch(_state.label){
266
266
  case 0:
@@ -278,6 +278,7 @@ export var loadPublishDetailsWithChecks = function() {
278
278
  if (!fs.existsSync(apkPath)) {
279
279
  throw new Error("Invalid path to APK file.");
280
280
  }
281
+ developerOverridenLocales = (_config_release = config.release) === null || _config_release === void 0 ? void 0 : (_config_release_android_details = _config_release.android_details) === null || _config_release_android_details === void 0 ? void 0 : _config_release_android_details.locales;
281
282
  if (!buildToolsDir) return [
282
283
  3,
283
284
  3
@@ -285,7 +286,7 @@ export var loadPublishDetailsWithChecks = function() {
285
286
  _ = config.release;
286
287
  return [
287
288
  4,
288
- getAndroidDetails(buildToolsDir, apkPath)
289
+ getAndroidDetails(buildToolsDir, apkPath, developerOverridenLocales)
289
290
  ];
290
291
  case 2:
291
292
  _.android_details = _state.sent();
@@ -756,7 +757,7 @@ var checkVideoDimensions = function(imagePath) {
756
757
  });
757
758
  })();
758
759
  };
759
- var getAndroidDetails = function(aaptDir, apkPath) {
760
+ var getAndroidDetails = function(aaptDir, apkPath, developerOverridenLocales) {
760
761
  return _async_to_generator(function() {
761
762
  var stdout, appPackage, versionCode, versionName, minSdk, permissions, locales, isDebuggable, _locales_values, localeArray, localesSrc, _appPackage_, _minSdk_, _versionCode_, _versionName_, _tmp, e;
762
763
  return _ts_generator(this, function(_state) {
@@ -802,6 +803,9 @@ var getAndroidDetails = function(aaptDir, apkPath) {
802
803
  if (permissions.includes("com.solanamobile.seedvault.ACCESS_SEED_VAULT") || permissions.includes("com.solanamobile.seedvault.ACCESS_SEED_VAULT_PRIVILEGED")) {
803
804
  showMessage("App requests Seed Vault permission", "If this is not a wallet application, your app maybe rejected from listing on Solana dApp Store.", "warning");
804
805
  }
806
+ if (developerOverridenLocales == null && localeArray.length >= 60 || (developerOverridenLocales === null || developerOverridenLocales === void 0 ? void 0 : developerOverridenLocales.length) >= 60) {
807
+ showMessage("Excessive language support detected", "The bundle apk claims supports for following locales \n" + localeArray + "\nYou config.yaml claims support for following locales\n" + developerOverridenLocales + "\nIf this release does not support all these locales the release may be rejected\n." + "You can override this list of supported locales in config.yaml" + "\nSee details at https://developer.android.com/guide/topics/resources/multilingual-support#design for configuring the supported locales in your apk file", "warning");
808
+ }
805
809
  _tmp = {
806
810
  android_package: (_appPackage_ = appPackage === null || appPackage === void 0 ? void 0 : appPackage[1]) !== null && _appPackage_ !== void 0 ? _appPackage_ : "",
807
811
  min_sdk: parseInt((_minSdk_ = minSdk === null || minSdk === void 0 ? void 0 : minSdk[1]) !== null && _minSdk_ !== void 0 ? _minSdk_ : "0", 10),
@@ -815,7 +819,7 @@ var getAndroidDetails = function(aaptDir, apkPath) {
815
819
  case 2:
816
820
  return [
817
821
  2,
818
- (_tmp.cert_fingerprint = _state.sent(), _tmp.permissions = permissions, _tmp.locales = localeArray, _tmp)
822
+ (_tmp.cert_fingerprint = _state.sent(), _tmp.permissions = permissions, _tmp.locales = developerOverridenLocales !== null && developerOverridenLocales !== void 0 ? developerOverridenLocales : localeArray, _tmp)
819
823
  ];
820
824
  case 3:
821
825
  e = _state.sent();
@@ -868,7 +872,7 @@ export var extractCertFingerprint = function(aaptDir, apkPath) {
868
872
  export var writeToPublishDetails = function(param) {
869
873
  var app = param.app, release = param.release, lastSubmittedVersionOnChain = param.lastSubmittedVersionOnChain, lastUpdatedVersionOnStore = param.lastUpdatedVersionOnStore;
870
874
  return _async_to_generator(function() {
871
- var currentConfig, _app_address, _release_address, newConfig;
875
+ var _release_android_details, _currentConfig_release_android_details, _release_android_details1, _currentConfig_release_android_details1, _release_android_details2, _currentConfig_release_android_details2, _release_android_details3, _currentConfig_release_android_details3, _release_android_details4, _currentConfig_release_android_details4, currentConfig, _app_address, _release_address, _release_android_details_cert_fingerprint, _release_android_details_min_sdk, _release_android_details_version, _release_android_details_version_code, _release_android_details_locales, newConfig;
872
876
  return _ts_generator(this, function(_state) {
873
877
  switch(_state.label){
874
878
  case 0:
@@ -886,7 +890,14 @@ export var writeToPublishDetails = function(param) {
886
890
  address: (_app_address = app === null || app === void 0 ? void 0 : app.address) !== null && _app_address !== void 0 ? _app_address : currentConfig.app.address
887
891
  }),
888
892
  release: _object_spread_props(_object_spread({}, currentConfig.release), {
889
- address: (_release_address = release === null || release === void 0 ? void 0 : release.address) !== null && _release_address !== void 0 ? _release_address : currentConfig.release.address
893
+ address: (_release_address = release === null || release === void 0 ? void 0 : release.address) !== null && _release_address !== void 0 ? _release_address : currentConfig.release.address,
894
+ android_details: {
895
+ cert_fingerprint: (_release_android_details_cert_fingerprint = release === null || release === void 0 ? void 0 : (_release_android_details = release.android_details) === null || _release_android_details === void 0 ? void 0 : _release_android_details.cert_fingerprint) !== null && _release_android_details_cert_fingerprint !== void 0 ? _release_android_details_cert_fingerprint : (_currentConfig_release_android_details = currentConfig.release.android_details) === null || _currentConfig_release_android_details === void 0 ? void 0 : _currentConfig_release_android_details.cert_fingerprint,
896
+ min_sdk: (_release_android_details_min_sdk = release === null || release === void 0 ? void 0 : (_release_android_details1 = release.android_details) === null || _release_android_details1 === void 0 ? void 0 : _release_android_details1.min_sdk) !== null && _release_android_details_min_sdk !== void 0 ? _release_android_details_min_sdk : (_currentConfig_release_android_details1 = currentConfig.release.android_details) === null || _currentConfig_release_android_details1 === void 0 ? void 0 : _currentConfig_release_android_details1.min_sdk,
897
+ version: (_release_android_details_version = release === null || release === void 0 ? void 0 : (_release_android_details2 = release.android_details) === null || _release_android_details2 === void 0 ? void 0 : _release_android_details2.version) !== null && _release_android_details_version !== void 0 ? _release_android_details_version : (_currentConfig_release_android_details2 = currentConfig.release.android_details) === null || _currentConfig_release_android_details2 === void 0 ? void 0 : _currentConfig_release_android_details2.version,
898
+ version_code: (_release_android_details_version_code = release === null || release === void 0 ? void 0 : (_release_android_details3 = release.android_details) === null || _release_android_details3 === void 0 ? void 0 : _release_android_details3.version_code) !== null && _release_android_details_version_code !== void 0 ? _release_android_details_version_code : (_currentConfig_release_android_details3 = currentConfig.release.android_details) === null || _currentConfig_release_android_details3 === void 0 ? void 0 : _currentConfig_release_android_details3.version_code,
899
+ locales: (_release_android_details_locales = release === null || release === void 0 ? void 0 : (_release_android_details4 = release.android_details) === null || _release_android_details4 === void 0 ? void 0 : _release_android_details4.locales) !== null && _release_android_details_locales !== void 0 ? _release_android_details_locales : (_currentConfig_release_android_details4 = currentConfig.release.android_details) === null || _currentConfig_release_android_details4 === void 0 ? void 0 : _currentConfig_release_android_details4.locales
900
+ }
890
901
  }),
891
902
  solana_mobile_dapp_publisher_portal: currentConfig.solana_mobile_dapp_publisher_portal,
892
903
  lastSubmittedVersionOnChain: lastSubmittedVersionOnChain !== null && lastSubmittedVersionOnChain !== void 0 ? lastSubmittedVersionOnChain : currentConfig.lastSubmittedVersionOnChain,
@@ -1 +1 @@
1
- {"publisher":{"name":"<<YOUR_PUBLISHER_NAME>>","website":"<<URL_OF_PUBLISHER_WEBSITE>>","email":"<<EMAIL_ADDRESS_TO_CONTACT_PUBLISHER>>"},"app":{"name":"<<APP_NAME>>","address":"","android_package":"<<ANDROID_PACKAGE_NAME>>","urls":{"license_url":"<<URL_OF_APP_LICENSE_OR_TERMS_OF_SERVICE>>","copyright_url":"<<URL_OF_COPYRIGHT_DETAILS_FOR_APP>>","privacy_policy_url":"<<URL_OF_APP_PRIVACY_POLICY>>","website":"<<URL_OF_APP_WEBSITE>>"},"media":[{"purpose":"icon","uri":"<<RELATIVE_PATH_TO_APP_ICON>>"}]},"release":{"address":"","media":[{"purpose":"icon","uri":"<<RELATIVE_PATH_TO_RELEASE_ICON>>"},{"purpose":"banner","uri":"<<RELATIVE_PATH_TO_BANNER>>"},{"purpose":"featureGraphic","uri":"<<RELATIVE_PATH_TO_FEATURE_GRAPHIC>>"},{"purpose":"screenshot","uri":"<<RELATIVE_PATH_TO_SCREENSHOT1>>"},{"purpose":"screenshot","uri":"<<RELATIVE_PATH_TO_SCREENSHOT2>>"},{"purpose":"screenshot","uri":"<<RELATIVE_PATH_TO_SCREENSHOT3>>"},{"purpose":"screenshot","uri":"<<RELATIVE_PATH_TO_SCREENSHOT4>>"},{"purpose":"video","uri":"<<RELATIVE_PATH_TO_VIDEO1>>"}],"files":[{"purpose":"install","uri":"<<RELATIVE_PATH_TO_APK>>"}],"catalog":{"en-US":{"name":"<<APP_NAME>>","short_description":"<<SHORT_APP_DESCRIPTION>>","long_description":"<<LONG_APP_DESCRIPTION>>","new_in_version":"<<WHATS_NEW_IN_THIS_VERSION>>","saga_features":"<<ANY_FEATURES_ONLY_AVAILBLE_WHEN_RUNNING_ON_SAGA>>"}}},"solana_mobile_dapp_publisher_portal":{"google_store_package":"<<ANDROID_PACKAGE_NAME_OF_GOOGLE_PLAY_STORE_VERSION_IF_DIFFERENT>>","testing_instructions":"<<TESTING_INSTRUCTIONS>>","alpha_testers":[{"address":"<<genesis token wallet address>>","comment":"<<Optional. For internal use only>>"},{"address":"<<genesis token wallet address>>","comment":"<<Optional. For internal use only>>"}]}}
1
+ {"publisher":{"name":"<<[REQUIRED] YOUR_PUBLISHER_NAME>>","website":"<<[REQUIRED] URL_OF_PUBLISHER_WEBSITE>>","email":"<<[REQUIRED] EMAIL_ADDRESS_TO_CONTACT_PUBLISHER>>"},"app":{"name":"<<[REQUIRED] APP_NAME>>","address":"","android_package":"<<[REQUIRED] ANDROID_PACKAGE_NAME>>","urls":{"license_url":"<<[REQUIRED] URL For App's T&C. Don't put placeholder urls.>>","copyright_url":"<<[REQUIRED] URL For App's Copyright. Don't put placeholder urls.>>","privacy_policy_url":"<<[REQUIRED] URL For App's Privacy Policy. Don't put placeholder urls.>>","website":"<<[REQUIRED] URL_OF_APP_WEBSITE>>"},"media":[{"purpose":"icon","uri":"<<[REQUIRED] RELATIVE_PATH_TO_APP_ICON>>"}]},"release":{"address":"","media":[{"purpose":"icon","uri":"<<[REQUIRED] RELATIVE_PATH_TO_RELEASE_ICON>>"},{"purpose":"banner","uri":"<<[REQUIRED] RELATIVE_PATH_TO_BANNER>>"},{"purpose":"featureGraphic","uri":"<<[Optional] RELATIVE_PATH_TO_FEATURE_GRAPHIC>>"},{"purpose":"screenshot","uri":"<<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT1>>"},{"purpose":"screenshot","uri":"<<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT2>>"},{"purpose":"screenshot","uri":"<<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT3>>"},{"purpose":"screenshot","uri":"<<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT4>>"},{"purpose":"video","uri":"<<[Optional] RELATIVE_PATH_TO_VIDEO1>>"}],"files":[{"purpose":"install","uri":"<<[REQUIRED] RELATIVE_PATH_TO_APK>>"}],"catalog":{"en-US":{"name":"<<[REQUIRED] APP_NAME>>","short_description":"<<[REQUIRED] SHORT_APP_DESCRIPTION>>","long_description":"<<[REQUIRED] LONG_APP_DESCRIPTION>>","new_in_version":"<<[REQUIRED] WHATS_NEW_IN_THIS_VERSION>>","saga_features":"<<[Optional.] ANY_FEATURES_ONLY_AVAILBLE_WHEN_RUNNING_ON_SAGA>>"}},"android_details":{"locales":["en-US","<Add more supported locales>"]}},"solana_mobile_dapp_publisher_portal":{"google_store_package":"<<[Optional] ANDROID_PACKAGE_NAME_OF_GOOGLE_PLAY_STORE_VERSION>>","testing_instructions":"<<[REQUIRED] TESTING_INSTRUCTIONS. Please provide any test account details if applicable>>","alpha_testers":[{"address":"<<Optional. genesis token wallet address>>","comment":"<<Optional. For internal use only>>"},{"address":"<<Optional. genesis token wallet address>>","comment":"<<Optional. For internal use only>>"}]}}
@@ -1 +1 @@
1
- {"type":"object","properties":{"publisher":{"type":"object","properties":{"name":{"type":"string"},"website":{"type":"string"},"email":{"type":"string"}}},"app":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"android_package":{"type":"string"},"urls":{"type":"object","properties":{"license_url":{"type":"string"},"copyright_url":{"type":"string"},"privacy_policy_url":{"type":"string"},"website":{"type":"string"}}},"media":{"type":"array","items":{"type":"object","properties":{"purpose":{"type":"string"},"uri":{"type":"string"}}}}}},"release":{"type":"object","properties":{"address":{"type":"string"},"media":{"type":"array","items":{"type":"object","properties":{"purpose":{"type":"string"},"uri":{"type":"string"}},"required":["purpose","uri"]}},"files":{"type":"array","items":{"type":"object","properties":{"purpose":{"type":"string"},"uri":{"type":"string"}}}},"catalog":{"type":"object","properties":{"en-US":{"type":"object","properties":{"name":{"type":"string"},"short_description":{"type":"string"},"long_description":{"type":"string"},"new_in_version":{"type":"string"},"saga_features":{"type":"string"}},"required":["short_description"]}}}}},"solana_mobile_dapp_publisher_portal":{"type":"object","properties":{"google_store_package":{"type":"string"},"testing_instructions":{"type":"string"},"alpha_testers":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string"},"comment":{"type":"string"}},"required":["address","comment"]}}}}}}
1
+ {"type":"object","properties":{"publisher":{"type":"object","properties":{"name":{"type":"string"},"website":{"type":"string"},"email":{"type":"string"}}},"app":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"android_package":{"type":"string"},"urls":{"type":"object","properties":{"license_url":{"type":"string"},"copyright_url":{"type":"string"},"privacy_policy_url":{"type":"string"},"website":{"type":"string"}}},"media":{"type":"array","items":{"type":"object","properties":{"purpose":{"type":"string"},"uri":{"type":"string"}}}}}},"release":{"type":"object","properties":{"address":{"type":"string"},"media":{"type":"array","items":{"type":"object","properties":{"purpose":{"type":"string"},"uri":{"type":"string"}},"required":["purpose","uri"]}},"files":{"type":"array","items":{"type":"object","properties":{"purpose":{"type":"string"},"uri":{"type":"string"}}}},"catalog":{"type":"object","properties":{"en-US":{"type":"object","properties":{"name":{"type":"string"},"short_description":{"type":"string"},"long_description":{"type":"string"},"new_in_version":{"type":"string"},"saga_features":{"type":"string"}},"required":["short_description"]}}},"android_details":{"type":"object","properties":{"locales":{"type":"array","items":{"type":"string"}}}}}},"solana_mobile_dapp_publisher_portal":{"type":"object","properties":{"google_store_package":{"type":"string"},"testing_instructions":{"type":"string"},"alpha_testers":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string"},"comment":{"type":"string"}},"required":["address","comment"]}}}}}}
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana-mobile/dapp-store-cli",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -53,7 +53,7 @@
53
53
  "dependencies": {
54
54
  "@aws-sdk/client-s3": "^3.321.1",
55
55
  "@metaplex-foundation/js-plugin-aws": "^0.20.0",
56
- "@solana-mobile/dapp-store-publishing-tools": "workspace:0.11.0",
56
+ "@solana-mobile/dapp-store-publishing-tools": "workspace:0.13.0",
57
57
  "@solana/web3.js": "1.92.1",
58
58
  "@types/semver": "^7.3.13",
59
59
  "ajv": "^8.11.0",
@@ -1,59 +1,63 @@
1
1
  publisher:
2
- name: <<YOUR_PUBLISHER_NAME>>
3
- website: <<URL_OF_PUBLISHER_WEBSITE>>
4
- email: <<EMAIL_ADDRESS_TO_CONTACT_PUBLISHER>>
2
+ name: <<[REQUIRED] YOUR_PUBLISHER_NAME>>
3
+ website: <<[REQUIRED] URL_OF_PUBLISHER_WEBSITE>>
4
+ email: <<[REQUIRED] EMAIL_ADDRESS_TO_CONTACT_PUBLISHER>>
5
5
  app:
6
- name: <<APP_NAME>>
6
+ name: <<[REQUIRED] APP_NAME>>
7
7
  address: ""
8
- android_package: <<ANDROID_PACKAGE_NAME>>
8
+ android_package: <<[REQUIRED] ANDROID_PACKAGE_NAME>>
9
9
  urls:
10
- license_url: <<URL_OF_APP_LICENSE_OR_TERMS_OF_SERVICE>>
11
- copyright_url: <<URL_OF_COPYRIGHT_DETAILS_FOR_APP>>
12
- privacy_policy_url: <<URL_OF_APP_PRIVACY_POLICY>>
13
- website: <<URL_OF_APP_WEBSITE>>
10
+ license_url: <<[REQUIRED] URL For App's T&C. Don't put placeholder urls.>>
11
+ copyright_url: <<[REQUIRED] URL For App's Copyright. Don't put placeholder urls.>>
12
+ privacy_policy_url: <<[REQUIRED] URL For App's Privacy Policy. Don't put placeholder urls.>>
13
+ website: <<[REQUIRED] URL_OF_APP_WEBSITE>>
14
14
  media:
15
15
  - purpose: icon
16
- uri: <<RELATIVE_PATH_TO_APP_ICON>>
16
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_APP_ICON>>
17
17
  release:
18
18
  address: ""
19
19
  media:
20
20
  - purpose: icon
21
- uri: <<RELATIVE_PATH_TO_RELEASE_ICON>>
21
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_RELEASE_ICON>>
22
22
  - purpose: banner
23
- uri: <<RELATIVE_PATH_TO_BANNER>>
23
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_BANNER>>
24
24
  - purpose: featureGraphic
25
- uri: <<RELATIVE_PATH_TO_FEATURE_GRAPHIC>>
25
+ uri: <<[Optional] RELATIVE_PATH_TO_FEATURE_GRAPHIC>>
26
26
  - purpose: screenshot
27
- uri: <<RELATIVE_PATH_TO_SCREENSHOT1>>
27
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT1>>
28
28
  - purpose: screenshot
29
- uri: <<RELATIVE_PATH_TO_SCREENSHOT2>>
29
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT2>>
30
30
  - purpose: screenshot
31
- uri: <<RELATIVE_PATH_TO_SCREENSHOT3>>
31
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT3>>
32
32
  - purpose: screenshot
33
- uri: <<RELATIVE_PATH_TO_SCREENSHOT4>>
33
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT4>>
34
34
  - purpose: video
35
- uri: <<RELATIVE_PATH_TO_VIDEO1>>
35
+ uri: <<[Optional] RELATIVE_PATH_TO_VIDEO1>>
36
36
  files:
37
37
  - purpose: install
38
- uri: <<RELATIVE_PATH_TO_APK>>
38
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_APK>>
39
39
  catalog:
40
40
  en-US:
41
41
  name: >-
42
- <<APP_NAME>>
42
+ <<[REQUIRED] APP_NAME>>
43
43
  short_description: >-
44
- <<SHORT_APP_DESCRIPTION>>
44
+ <<[REQUIRED] SHORT_APP_DESCRIPTION>>
45
45
  long_description: >-
46
- <<LONG_APP_DESCRIPTION>>
46
+ <<[REQUIRED] LONG_APP_DESCRIPTION>>
47
47
  new_in_version: >-
48
- <<WHATS_NEW_IN_THIS_VERSION>>
48
+ <<[REQUIRED] WHATS_NEW_IN_THIS_VERSION>>
49
49
  saga_features: >-
50
- <<ANY_FEATURES_ONLY_AVAILBLE_WHEN_RUNNING_ON_SAGA>>
50
+ <<[Optional.] ANY_FEATURES_ONLY_AVAILBLE_WHEN_RUNNING_ON_SAGA>>
51
+ android_details:
52
+ locales:
53
+ - en-US
54
+ - <Add more supported locales>
51
55
  solana_mobile_dapp_publisher_portal:
52
- google_store_package: <<ANDROID_PACKAGE_NAME_OF_GOOGLE_PLAY_STORE_VERSION_IF_DIFFERENT>>
56
+ google_store_package: <<[Optional] ANDROID_PACKAGE_NAME_OF_GOOGLE_PLAY_STORE_VERSION>>
53
57
  testing_instructions: >-
54
- <<TESTING_INSTRUCTIONS>>
58
+ <<[REQUIRED] TESTING_INSTRUCTIONS. Please provide any test account details if applicable>>
55
59
  alpha_testers:
56
- - address: <<genesis token wallet address>>
60
+ - address: <<Optional. genesis token wallet address>>
57
61
  comment: <<Optional. For internal use only>>
58
- - address: <<genesis token wallet address>>
62
+ - address: <<Optional. genesis token wallet address>>
59
63
  comment: <<Optional. For internal use only>>
@@ -166,6 +166,7 @@ function _ts_generator(thisArg, body) {
166
166
  }
167
167
  }
168
168
  import fs from "fs";
169
+ import path from "path";
169
170
  import { createHash } from "crypto";
170
171
  // TODO(jon): We need to manage the removal / replacement of assets in the manifest
171
172
  export var CachedStorageDriver = /*#__PURE__*/ function() {
@@ -267,7 +268,7 @@ export var CachedStorageDriver = /*#__PURE__*/ function() {
267
268
  };
268
269
  return [
269
270
  4,
270
- fs.promises.writeFile("".concat(process.cwd(), "/").concat(this.assetManifestPath), // Something is really weird, I can't seem to stringify `this.assetManifest` straight-up. Here be dragons
271
+ fs.promises.writeFile(path.join(process.cwd(), this.assetManifestPath), // Something is really weird, I can't seem to stringify `this.assetManifest` straight-up. Here be dragons
271
272
  JSON.stringify({
272
273
  assets: _object_spread({}, this.assetManifest.assets)
273
274
  }, null, 2), "utf-8")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana-mobile/dapp-store-cli",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -46,7 +46,7 @@
46
46
  "dependencies": {
47
47
  "@aws-sdk/client-s3": "^3.321.1",
48
48
  "@metaplex-foundation/js-plugin-aws": "^0.20.0",
49
- "@solana-mobile/dapp-store-publishing-tools": "0.11.0",
49
+ "@solana-mobile/dapp-store-publishing-tools": "0.13.0",
50
50
  "@solana/web3.js": "1.92.1",
51
51
  "@types/semver": "^7.3.13",
52
52
  "ajv": "^8.11.0",
package/src/CliUtils.ts CHANGED
@@ -12,6 +12,7 @@ import { readFile } from 'fs/promises';
12
12
  const cliPackage = JSON.parse((await readFile(new URL("./package.json", import.meta.url))).toString());
13
13
  import boxen from "boxen";
14
14
  import ver from "semver";
15
+ import path from "path";
15
16
  import { CachedStorageDriver } from "./upload/CachedStorageDriver.js";
16
17
  import { EnvVariables } from "./config/index.js";
17
18
  import { S3Client } from "@aws-sdk/client-s3";
@@ -19,13 +20,13 @@ import { awsStorage } from "@metaplex-foundation/js-plugin-aws";
19
20
  import { S3StorageManager } from "./config/index.js";
20
21
 
21
22
  export class Constants {
22
- static CLI_VERSION = "0.11.0";
23
+ static CLI_VERSION = "0.13.0";
23
24
  static CONFIG_FILE_NAME = "config.yaml";
24
25
  static DEFAULT_RPC_DEVNET = "https://api.devnet.solana.com";
25
26
  static DEFAULT_PRIORITY_FEE = 500000;
26
27
 
27
28
  static getConfigFilePath = () => {
28
- return `${process.cwd()}/${Constants.CONFIG_FILE_NAME}`;
29
+ return path.join(process.cwd(), Constants.CONFIG_FILE_NAME);
29
30
  };
30
31
  }
31
32
 
@@ -127,7 +127,16 @@ export const createReleaseCommand = async ({
127
127
 
128
128
  await writeToPublishDetails(
129
129
  {
130
- release: { address: releaseAddress },
130
+ release: {
131
+ address: releaseAddress,
132
+ android_details: {
133
+ cert_fingerprint: config.release.android_details.cert_fingerprint,
134
+ min_sdk: config.release.android_details.min_sdk,
135
+ version: config.release.android_details.version,
136
+ version_code: config.release.android_details.version_code,
137
+ locales: config.release.android_details.locales
138
+ }
139
+ },
131
140
  lastSubmittedVersionOnChain: {
132
141
  address: releaseAddress,
133
142
  version_code: config.release.android_details.version_code,
@@ -3,11 +3,12 @@ import yaml, { dump } from "js-yaml";
3
3
  import { readFile } from 'fs/promises';
4
4
  const releaseSchema = JSON.parse((await readFile(new URL("../../generated/config_obj.json", import.meta.url))).toString());
5
5
  import fs from "fs";
6
+ import path from "path";
6
7
  import { Constants } from "../../CliUtils.js";
7
8
 
8
9
  export const initScaffold = (): string => {
9
10
  const outputYaml = Constants.CONFIG_FILE_NAME;
10
- const outFile = `${process.cwd()}/${outputYaml}`;
11
+ const outFile = path.join(process.cwd(), outputYaml);
11
12
 
12
13
  if (fs.existsSync(outFile)) {
13
14
  throw Error("Configuration file already present; please use to intialize a new config file.");
@@ -1,4 +1,4 @@
1
- import type {
1
+ import {
2
2
  AndroidDetails,
3
3
  App,
4
4
  LastSubmittedVersionOnChain,
@@ -48,7 +48,7 @@ const AaptPrefixes = {
48
48
  type SaveToConfigArgs = {
49
49
  publisher?: Pick<Publisher, "address">;
50
50
  app?: Pick<App, "address">;
51
- release?: Pick<Release, "address">;
51
+ release?: Release;
52
52
  lastSubmittedVersionOnChain?: LastSubmittedVersionOnChain;
53
53
  lastUpdatedVersionOnStore?: LastUpdatedVersionOnStore;
54
54
  };
@@ -83,10 +83,13 @@ export const loadPublishDetailsWithChecks = async (
83
83
  throw new Error("Invalid path to APK file.");
84
84
  }
85
85
 
86
+ const developerOverridenLocales = config.release?.android_details?.locales
87
+
86
88
  if (buildToolsDir) {
87
89
  config.release.android_details = await getAndroidDetails(
88
90
  buildToolsDir,
89
- apkPath
91
+ apkPath,
92
+ developerOverridenLocales
90
93
  );
91
94
  }
92
95
 
@@ -312,7 +315,8 @@ const checkVideoDimensions = async (imagePath: string): Promise<boolean> => {
312
315
 
313
316
  const getAndroidDetails = async (
314
317
  aaptDir: string,
315
- apkPath: string
318
+ apkPath: string,
319
+ developerOverridenLocales: [string]
316
320
  ): Promise<AndroidDetails> => {
317
321
  try {
318
322
  const { stdout } = await runExec(`${aaptDir}/aapt2 dump badging "${apkPath}"`);
@@ -371,6 +375,20 @@ const getAndroidDetails = async (
371
375
  );
372
376
  }
373
377
 
378
+ if (developerOverridenLocales == null && localeArray.length >= 60 || developerOverridenLocales?.length >= 60) {
379
+ showMessage(
380
+ "Excessive language support detected",
381
+ "The bundle apk claims supports for following locales \n" +
382
+ localeArray +
383
+ "\nYou config.yaml claims support for following locales\n" +
384
+ developerOverridenLocales +
385
+ "\nIf this release does not support all these locales the release may be rejected\n." +
386
+ "You can override this list of supported locales in config.yaml" +
387
+ "\nSee details at https://developer.android.com/guide/topics/resources/multilingual-support#design for configuring the supported locales in your apk file",
388
+ "warning"
389
+ );
390
+ }
391
+
374
392
  return {
375
393
  android_package: appPackage?.[1] ?? "",
376
394
  min_sdk: parseInt(minSdk?.[1] ?? "0", 10),
@@ -378,7 +396,7 @@ const getAndroidDetails = async (
378
396
  version: versionName?.[1] ?? "0",
379
397
  cert_fingerprint: await extractCertFingerprint(aaptDir, apkPath),
380
398
  permissions: permissions,
381
- locales: localeArray
399
+ locales: developerOverridenLocales ?? localeArray
382
400
  };
383
401
  } catch (e) {
384
402
  if (e instanceof TypeError) {
@@ -418,7 +436,14 @@ export const writeToPublishDetails = async ({ app, release, lastSubmittedVersion
418
436
  },
419
437
  release: {
420
438
  ...currentConfig.release,
421
- address: release?.address ?? currentConfig.release.address
439
+ address: release?.address ?? currentConfig.release.address,
440
+ android_details: {
441
+ cert_fingerprint: release?.android_details?.cert_fingerprint ?? currentConfig.release.android_details?.cert_fingerprint,
442
+ min_sdk: release?.android_details?.min_sdk ?? currentConfig.release.android_details?.min_sdk,
443
+ version: release?.android_details?.version ?? currentConfig.release.android_details?.version,
444
+ version_code: release?.android_details?.version_code ?? currentConfig.release.android_details?.version_code,
445
+ locales: release?.android_details?.locales ?? currentConfig.release.android_details?.locales
446
+ }
422
447
  },
423
448
  solana_mobile_dapp_publisher_portal: currentConfig.solana_mobile_dapp_publisher_portal,
424
449
  lastSubmittedVersionOnChain: lastSubmittedVersionOnChain ?? currentConfig.lastSubmittedVersionOnChain,
@@ -1,59 +1,63 @@
1
1
  publisher:
2
- name: <<YOUR_PUBLISHER_NAME>>
3
- website: <<URL_OF_PUBLISHER_WEBSITE>>
4
- email: <<EMAIL_ADDRESS_TO_CONTACT_PUBLISHER>>
2
+ name: <<[REQUIRED] YOUR_PUBLISHER_NAME>>
3
+ website: <<[REQUIRED] URL_OF_PUBLISHER_WEBSITE>>
4
+ email: <<[REQUIRED] EMAIL_ADDRESS_TO_CONTACT_PUBLISHER>>
5
5
  app:
6
- name: <<APP_NAME>>
6
+ name: <<[REQUIRED] APP_NAME>>
7
7
  address: ""
8
- android_package: <<ANDROID_PACKAGE_NAME>>
8
+ android_package: <<[REQUIRED] ANDROID_PACKAGE_NAME>>
9
9
  urls:
10
- license_url: <<URL_OF_APP_LICENSE_OR_TERMS_OF_SERVICE>>
11
- copyright_url: <<URL_OF_COPYRIGHT_DETAILS_FOR_APP>>
12
- privacy_policy_url: <<URL_OF_APP_PRIVACY_POLICY>>
13
- website: <<URL_OF_APP_WEBSITE>>
10
+ license_url: <<[REQUIRED] URL For App's T&C. Don't put placeholder urls.>>
11
+ copyright_url: <<[REQUIRED] URL For App's Copyright. Don't put placeholder urls.>>
12
+ privacy_policy_url: <<[REQUIRED] URL For App's Privacy Policy. Don't put placeholder urls.>>
13
+ website: <<[REQUIRED] URL_OF_APP_WEBSITE>>
14
14
  media:
15
15
  - purpose: icon
16
- uri: <<RELATIVE_PATH_TO_APP_ICON>>
16
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_APP_ICON>>
17
17
  release:
18
18
  address: ""
19
19
  media:
20
20
  - purpose: icon
21
- uri: <<RELATIVE_PATH_TO_RELEASE_ICON>>
21
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_RELEASE_ICON>>
22
22
  - purpose: banner
23
- uri: <<RELATIVE_PATH_TO_BANNER>>
23
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_BANNER>>
24
24
  - purpose: featureGraphic
25
- uri: <<RELATIVE_PATH_TO_FEATURE_GRAPHIC>>
25
+ uri: <<[Optional] RELATIVE_PATH_TO_FEATURE_GRAPHIC>>
26
26
  - purpose: screenshot
27
- uri: <<RELATIVE_PATH_TO_SCREENSHOT1>>
27
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT1>>
28
28
  - purpose: screenshot
29
- uri: <<RELATIVE_PATH_TO_SCREENSHOT2>>
29
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT2>>
30
30
  - purpose: screenshot
31
- uri: <<RELATIVE_PATH_TO_SCREENSHOT3>>
31
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT3>>
32
32
  - purpose: screenshot
33
- uri: <<RELATIVE_PATH_TO_SCREENSHOT4>>
33
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_SCREENSHOT4>>
34
34
  - purpose: video
35
- uri: <<RELATIVE_PATH_TO_VIDEO1>>
35
+ uri: <<[Optional] RELATIVE_PATH_TO_VIDEO1>>
36
36
  files:
37
37
  - purpose: install
38
- uri: <<RELATIVE_PATH_TO_APK>>
38
+ uri: <<[REQUIRED] RELATIVE_PATH_TO_APK>>
39
39
  catalog:
40
40
  en-US:
41
41
  name: >-
42
- <<APP_NAME>>
42
+ <<[REQUIRED] APP_NAME>>
43
43
  short_description: >-
44
- <<SHORT_APP_DESCRIPTION>>
44
+ <<[REQUIRED] SHORT_APP_DESCRIPTION>>
45
45
  long_description: >-
46
- <<LONG_APP_DESCRIPTION>>
46
+ <<[REQUIRED] LONG_APP_DESCRIPTION>>
47
47
  new_in_version: >-
48
- <<WHATS_NEW_IN_THIS_VERSION>>
48
+ <<[REQUIRED] WHATS_NEW_IN_THIS_VERSION>>
49
49
  saga_features: >-
50
- <<ANY_FEATURES_ONLY_AVAILBLE_WHEN_RUNNING_ON_SAGA>>
50
+ <<[Optional.] ANY_FEATURES_ONLY_AVAILBLE_WHEN_RUNNING_ON_SAGA>>
51
+ android_details:
52
+ locales:
53
+ - en-US
54
+ - <Add more supported locales>
51
55
  solana_mobile_dapp_publisher_portal:
52
- google_store_package: <<ANDROID_PACKAGE_NAME_OF_GOOGLE_PLAY_STORE_VERSION_IF_DIFFERENT>>
56
+ google_store_package: <<[Optional] ANDROID_PACKAGE_NAME_OF_GOOGLE_PLAY_STORE_VERSION>>
53
57
  testing_instructions: >-
54
- <<TESTING_INSTRUCTIONS>>
58
+ <<[REQUIRED] TESTING_INSTRUCTIONS. Please provide any test account details if applicable>>
55
59
  alpha_testers:
56
- - address: <<genesis token wallet address>>
60
+ - address: <<Optional. genesis token wallet address>>
57
61
  comment: <<Optional. For internal use only>>
58
- - address: <<genesis token wallet address>>
62
+ - address: <<Optional. genesis token wallet address>>
59
63
  comment: <<Optional. For internal use only>>
@@ -1,4 +1,5 @@
1
1
  import fs from "fs";
2
+ import path from "path";
2
3
  import type { MetaplexFile, StorageDriver } from "@metaplex-foundation/js";
3
4
  import { createHash } from "crypto";
4
5
 
@@ -86,7 +87,7 @@ export class CachedStorageDriver implements StorageDriver {
86
87
  };
87
88
 
88
89
  await fs.promises.writeFile(
89
- `${process.cwd()}/${this.assetManifestPath}`,
90
+ path.join(process.cwd(), this.assetManifestPath),
90
91
  // Something is really weird, I can't seem to stringify `this.assetManifest` straight-up. Here be dragons
91
92
  JSON.stringify({ assets: { ...this.assetManifest.assets } }, null, 2),
92
93
  "utf-8"