shipthis 0.1.25 → 0.1.26

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 (84) hide show
  1. package/dist/AppleBundleIdDetails-mPUG2R4N.js +76 -0
  2. package/dist/Command-B3AmRt2w.js +28 -0
  3. package/dist/CommandGame-BCMzP9pc.js +9 -0
  4. package/dist/Create-CsJxpzUs.js +59 -0
  5. package/dist/Import-v0M_ygyF.js +110 -0
  6. package/dist/JobProgress-9uvq8IBn.js +121 -0
  7. package/dist/JobStatusTable-Bf7J9WXe.js +191 -0
  8. package/dist/NextSteps-CK9zHOCt.js +18 -0
  9. package/dist/ProgressSpinner-6pw1T8Iw.js +16 -0
  10. package/dist/ProjectCredentialsTable-CTkP1mvy.js +37 -0
  11. package/dist/RunWithSpinner-BVXNWGD3.js +27 -0
  12. package/dist/StatusTable-Dm5St4g-.js +33 -0
  13. package/dist/Table-CvM6pccN.js +101 -0
  14. package/dist/Title-BCQtayg6.js +6 -0
  15. package/dist/UserCredentialsTable-DhtM_iTG.js +82 -0
  16. package/dist/baseAppleCommand-IGl6KTvv.js +10 -0
  17. package/dist/baseGameAndroidCommand-DFn4zMvq.js +43 -0
  18. package/dist/commands/apple/apiKey/create.js +103 -0
  19. package/dist/commands/apple/apiKey/export.js +81 -0
  20. package/dist/commands/apple/apiKey/import.js +85 -0
  21. package/dist/commands/apple/apiKey/status.js +122 -0
  22. package/dist/commands/apple/certificate/create.js +133 -0
  23. package/dist/commands/apple/certificate/export.js +81 -0
  24. package/dist/commands/apple/certificate/import.js +85 -0
  25. package/dist/commands/apple/certificate/status.js +130 -0
  26. package/dist/commands/apple/login.js +76 -0
  27. package/dist/commands/apple/status.js +79 -0
  28. package/dist/commands/dashboard.js +38 -0
  29. package/dist/commands/game/android/apiKey/connect.js +74 -0
  30. package/dist/commands/game/android/apiKey/create.js +74 -0
  31. package/dist/commands/game/android/apiKey/export.js +84 -0
  32. package/dist/commands/game/android/apiKey/import.js +93 -0
  33. package/dist/commands/game/android/apiKey/invite.js +81 -0
  34. package/dist/commands/game/android/apiKey/status.js +87 -0
  35. package/dist/commands/game/android/keyStore/create.js +69 -0
  36. package/dist/commands/game/android/keyStore/export.js +83 -0
  37. package/dist/commands/game/android/keyStore/import.js +112 -0
  38. package/dist/commands/game/android/keyStore/status.js +70 -0
  39. package/dist/commands/game/android/status.js +84 -0
  40. package/dist/commands/game/build/download.js +80 -0
  41. package/dist/commands/game/build/list.js +94 -0
  42. package/dist/commands/game/create.js +67 -0
  43. package/dist/commands/game/details.js +113 -0
  44. package/dist/commands/game/export.js +58 -0
  45. package/dist/commands/game/ios/app/addTester.js +124 -0
  46. package/dist/commands/game/ios/app/create.js +117 -0
  47. package/dist/commands/game/ios/app/status.js +66 -0
  48. package/dist/commands/game/ios/app/sync.js +95 -0
  49. package/dist/commands/game/ios/profile/create.js +129 -0
  50. package/dist/commands/game/ios/profile/export.js +83 -0
  51. package/dist/commands/game/ios/profile/import.js +92 -0
  52. package/dist/commands/game/ios/profile/status.js +139 -0
  53. package/dist/commands/game/ios/status.js +92 -0
  54. package/dist/commands/game/ios/wizard.js +153 -0
  55. package/dist/commands/game/job/list.js +91 -0
  56. package/dist/commands/game/job/status.js +91 -0
  57. package/dist/commands/game/list.js +83 -0
  58. package/dist/commands/game/ship.js +216 -0
  59. package/dist/commands/game/status.js +114 -0
  60. package/dist/commands/game/wizard.js +686 -0
  61. package/dist/commands/internal/fastlane.js +74 -0
  62. package/dist/commands/internal/readme.js +937 -0
  63. package/dist/commands/login.js +92 -0
  64. package/dist/commands/status.js +76 -0
  65. package/dist/export-CVs_xoDN.js +36 -0
  66. package/dist/git-DREGq-jc.js +32 -0
  67. package/dist/import-Ch5O7xfN.js +47 -0
  68. package/dist/index-BB00V5oF.js +136 -0
  69. package/dist/index-BD1WLuFJ.js +125 -0
  70. package/dist/index-CIa2EDQ6.js +24 -0
  71. package/dist/index-CboPN9aq.js +138 -0
  72. package/dist/index-DkNQs11R.js +711 -0
  73. package/dist/index-nnzhQ3nY.js +209 -0
  74. package/dist/index.d.ts +1 -0
  75. package/dist/index.js +1 -0
  76. package/dist/upload-CRE2nVdd.js +60 -0
  77. package/dist/useAndroidServiceAccountTestResult-DcYDam-p.js +52 -0
  78. package/dist/useAppleApp-B16WbUxJ.js +32 -0
  79. package/dist/useAppleBundleId-DobPATan.js +64 -0
  80. package/dist/useJobWatching--BvVn7xS.js +45 -0
  81. package/dist/useProjectCredentials-Btnr7WK3.js +54 -0
  82. package/dist/useWebSocket-ByuNoqRw.js +36 -0
  83. package/dist/utils/help.js +14 -0
  84. package/package.json +1 -1
@@ -0,0 +1,711 @@
1
+ import path from 'path';
2
+ import * as fs from 'fs';
3
+ import fs__default from 'fs';
4
+ import { Command, Flags } from '@oclif/core';
5
+ import * as expo from '@expo/apple-utils/build/index.js';
6
+ import axios from 'axios';
7
+ import CryptoJS from 'crypto-js';
8
+ import { v4 } from 'uuid';
9
+ import { DateTime } from 'luxon';
10
+ import 'crypto';
11
+ import 'readline-sync';
12
+ import 'node:readline';
13
+ import 'node:path';
14
+ import 'node:url';
15
+ import 'isomorphic-git';
16
+ import { parse } from 'ini';
17
+ import merge from 'deepmerge';
18
+ import 'react';
19
+ import { QueryClient } from '@tanstack/react-query';
20
+ import 'fast-glob';
21
+ import 'yazl';
22
+ import 'socket.io-client';
23
+
24
+ const defaultExport = expo.default;
25
+ const {
26
+ ApiKey,
27
+ ApiKeyType,
28
+ App,
29
+ Auth,
30
+ BundleId,
31
+ CapabilityType,
32
+ CapabilityTypeOption,
33
+ Certificate,
34
+ CertificateType,
35
+ Profile,
36
+ ProfileType,
37
+ Session,
38
+ UserRole,
39
+ BetaGroup
40
+ } = defaultExport;
41
+
42
+ const DEFAULT_SHIPPED_FILES_GLOBS = ["**/*"];
43
+ const DEFAULT_IGNORED_FILES_GLOBS = [".git", ".gitignore", "shipthis.json", "shipthis-*.zip"];
44
+ const PRIMARY_DOMAIN = "shipth.is";
45
+ function getUrlsForDomain(domain) {
46
+ const isPublic = domain.includes(PRIMARY_DOMAIN);
47
+ const apiDomain = (isPublic ? `api.` : "") + domain;
48
+ const wsDomain = (isPublic ? `ws.` : "") + domain;
49
+ return {
50
+ api: `https://${apiDomain}/api/1.0.0`,
51
+ ws: `wss://${wsDomain}`,
52
+ web: `https://${domain}/`
53
+ };
54
+ }
55
+ const DOMAIN_ENV_VAR_NAME = "SHIPTHIS_DOMAIN";
56
+ const DOMAIN = process.env[DOMAIN_ENV_VAR_NAME] || PRIMARY_DOMAIN;
57
+ const BACKEND_URLS = getUrlsForDomain(DOMAIN);
58
+ const API_URL = BACKEND_URLS.api;
59
+ const WS_URL = BACKEND_URLS.ws;
60
+ const WEB_URL = BACKEND_URLS.web;
61
+
62
+ const DEFAULT_LOCALE = "en-US";
63
+ function castObjectDates(apiObject, keys = ["createdAt", "updatedAt"]) {
64
+ if (!apiObject) return apiObject;
65
+ const datesOnly = Object.keys(apiObject).filter((k) => keys.includes(k)).reduce((a, c) => {
66
+ a[c] = DateTime.fromISO(apiObject[c]);
67
+ return a;
68
+ }, {});
69
+ return {
70
+ ...apiObject,
71
+ ...datesOnly
72
+ };
73
+ }
74
+ function castArrayObjectDates(apiArray, keys = ["createdAt", "updatedAt"]) {
75
+ return apiArray.map((apiObject) => castObjectDates(apiObject, keys));
76
+ }
77
+ function castJobDates(jobObject) {
78
+ if (jobObject.build) return castObjectDates({ ...jobObject, build: castObjectDates(jobObject.build) });
79
+ return castObjectDates(jobObject);
80
+ }
81
+ function getDateLocale() {
82
+ const fallback = Intl.DateTimeFormat().resolvedOptions().locale.replace(/_/g, "-") || DEFAULT_LOCALE;
83
+ try {
84
+ const env = process.env;
85
+ const fullLocale = env.LC_TIME || env.LANG || env.LANGUAGE || env.LC_ALL || env.LC_MESSAGES;
86
+ const shortLocale = fullLocale?.split(".")[0].replace(/_/g, "-");
87
+ const finalLocal = shortLocale || fallback;
88
+ const _ = DateTime.now().toLocaleString(DateTime.DATE_SHORT, { locale: finalLocal });
89
+ return finalLocal;
90
+ } catch (e) {
91
+ return fallback;
92
+ }
93
+ }
94
+ function getShortDate(inputDate) {
95
+ const locale = getDateLocale();
96
+ return inputDate.toLocaleString(DateTime.DATE_SHORT, { locale });
97
+ }
98
+ function getShortDateTime(inputDate, extraFormatOpts = {}) {
99
+ const locale = getDateLocale();
100
+ const formatOpts = { ...DateTime.DATETIME_SHORT, ...extraFormatOpts };
101
+ return inputDate.toLocaleString(formatOpts, { locale });
102
+ }
103
+ function getShortTime(inputDate, extraFormatOpts = { fractionalSecondDigits: 3 }) {
104
+ const locale = getDateLocale();
105
+ const formatOpts = { ...DateTime.TIME_24_WITH_SECONDS, ...extraFormatOpts };
106
+ return inputDate.toLocaleString(formatOpts, { locale });
107
+ }
108
+ function getShortTimeDelta(start, end) {
109
+ return end.diff(start).rescale().set({ milliseconds: 0 }).shiftTo("minutes", "seconds").toHuman({
110
+ listStyle: "short",
111
+ unitDisplay: "short"
112
+ });
113
+ }
114
+
115
+ const AUTH_ENV_VAR_NAME = "SHIPTHIS_TOKEN";
116
+ function setAuthToken(token) {
117
+ process.env[AUTH_ENV_VAR_NAME] = token;
118
+ }
119
+ function getAuthToken() {
120
+ return process.env[AUTH_ENV_VAR_NAME];
121
+ }
122
+ function getAuthedHeaders() {
123
+ return {
124
+ Authorization: `Bearer ${process.env[AUTH_ENV_VAR_NAME]}`
125
+ };
126
+ }
127
+ async function createProject(props) {
128
+ const headers = getAuthedHeaders();
129
+ const opt = { headers };
130
+ const { data } = await axios.post(`${API_URL}/projects`, props, opt);
131
+ return castObjectDates(data);
132
+ }
133
+ async function getProject(projectId) {
134
+ const headers = getAuthedHeaders();
135
+ const opt = { headers };
136
+ const { data } = await axios.get(`${API_URL}/projects/${projectId}`, opt);
137
+ return castObjectDates(data);
138
+ }
139
+ async function getProjects(params) {
140
+ const headers = getAuthedHeaders();
141
+ const opt = { headers, params };
142
+ const { data: rawData } = await axios.get(`${API_URL}/projects`, opt);
143
+ const data = castArrayObjectDates(rawData.data);
144
+ return {
145
+ data,
146
+ pageCount: rawData.pageCount
147
+ };
148
+ }
149
+ async function updateProject(projectId, edits) {
150
+ const headers = getAuthedHeaders();
151
+ const opt = { headers };
152
+ const { data } = await axios.put(`${API_URL}/projects/${projectId}`, edits, opt);
153
+ return castObjectDates(data);
154
+ }
155
+ async function getProjectPlatformProgress(projectId, platform) {
156
+ const headers = getAuthedHeaders();
157
+ const opt = { headers };
158
+ const { data } = await axios.get(`${API_URL}/projects/${projectId}/${platform}/progress`, opt);
159
+ return data;
160
+ }
161
+ async function getNewUploadTicket(projectId) {
162
+ const headers = getAuthedHeaders();
163
+ const opt = { headers };
164
+ const { data } = await axios.post(`${API_URL}/upload/${projectId}/url`, {}, opt);
165
+ return data;
166
+ }
167
+ async function startJobsFromUpload(uploadTicketId, startOptions) {
168
+ const headers = getAuthedHeaders();
169
+ const opt = { headers };
170
+ const { data } = await axios.post(`${API_URL}/upload/start/${uploadTicketId}`, startOptions, opt);
171
+ return castArrayObjectDates(data);
172
+ }
173
+ async function getProjectJobs(projectId, params) {
174
+ const headers = getAuthedHeaders();
175
+ const opt = { headers, params };
176
+ const { data: rawData } = await axios.get(`${API_URL}/projects/${projectId}/jobs`, opt);
177
+ const data = castArrayObjectDates(rawData.data);
178
+ return {
179
+ data,
180
+ pageCount: rawData.pageCount
181
+ };
182
+ }
183
+ async function getJob(jobId, projectId) {
184
+ const headers = getAuthedHeaders();
185
+ const opt = { headers };
186
+ const { data } = await axios.get(`${API_URL}/projects/${projectId}/jobs/${jobId}`, opt);
187
+ return castJobDates(data);
188
+ }
189
+ async function getSingleUseUrl(destination) {
190
+ const headers = await getAuthedHeaders();
191
+ const { data } = await axios.post(`${API_URL}/me/otp`, {}, { headers });
192
+ const queryString = Object.entries({ ...data, destination }).map(([key, value]) => `${key}=${encodeURIComponent(`${value}`)}`).join("&");
193
+ const url = `${WEB_URL}exchange/?${queryString}`;
194
+ return url;
195
+ }
196
+ async function getShortAuthRequiredUrl(destination) {
197
+ const { email } = await getSelf();
198
+ const key = v4();
199
+ const salt = "Na (s) + 1/2 Cl\u2082 (g) \u2192 NaCl (s)";
200
+ const fullKey = `${key}${salt}`;
201
+ const token = CryptoJS.AES.encrypt(email, fullKey).toString();
202
+ const params = {
203
+ key,
204
+ token,
205
+ destination
206
+ };
207
+ const queryString = Object.entries(params).map(([key2, value]) => `${key2}=${encodeURIComponent(`${value}`)}`).join("&");
208
+ const url = `${WEB_URL}login/?${queryString}`;
209
+ const headers = await getAuthedHeaders();
210
+ const { data } = await axios.post(
211
+ `${API_URL}/me/shorten`,
212
+ {
213
+ url
214
+ },
215
+ { headers }
216
+ );
217
+ return data.url;
218
+ }
219
+ async function getBuild(projectId, buildId) {
220
+ const headers = getAuthedHeaders();
221
+ const opt = { headers };
222
+ const { data } = await axios.get(`${API_URL}/projects/${projectId}/builds/${buildId}`, opt);
223
+ return castObjectDates(data);
224
+ }
225
+ async function getSelf() {
226
+ const headers = getAuthedHeaders();
227
+ const opt = { headers };
228
+ const { data } = await axios.get(`${API_URL}/me`, opt);
229
+ return castObjectDates(data);
230
+ }
231
+ async function acceptTerms() {
232
+ const headers = getAuthedHeaders();
233
+ const opt = { headers };
234
+ const { data } = await axios.post(`${API_URL}/me/acceptTerms`, {}, opt);
235
+ return castObjectDates(data);
236
+ }
237
+ async function getGoogleAuthUrl(projectId) {
238
+ const headers = getAuthedHeaders();
239
+ const opt = { headers };
240
+ const web = encodeURIComponent(new URL("/google/redirect/", WEB_URL).href);
241
+ const url = `${API_URL}/projects/${projectId}/credentials/android/key/connect`;
242
+ const { data } = await axios.get(`${url}?redirectUri=${web}`, opt);
243
+ const response = data;
244
+ return await getShortAuthRequiredUrl(response.url);
245
+ }
246
+ async function disconnectGoogle() {
247
+ const headers = getAuthedHeaders();
248
+ const opt = { headers };
249
+ await axios.delete(`${API_URL}/me/google/connect`, opt);
250
+ }
251
+ async function getGoogleStatus() {
252
+ const headers = getAuthedHeaders();
253
+ const opt = { headers };
254
+ const { data } = await axios.get(`${API_URL}/me/google/status`, opt);
255
+ return data;
256
+ }
257
+ async function inviteServiceAccount(projectId, developerId) {
258
+ try {
259
+ const headers = getAuthedHeaders();
260
+ const { data } = await axios.post(
261
+ `${API_URL}/projects/${projectId}/credentials/android/key/invite/`,
262
+ { developerId },
263
+ {
264
+ headers
265
+ }
266
+ );
267
+ return data;
268
+ } catch (error) {
269
+ console.error("inviteServiceAccount Error", error);
270
+ throw error;
271
+ }
272
+ }
273
+ async function downloadBuildById(projectId, buildId, fileName) {
274
+ const build = await getBuild(projectId, buildId);
275
+ const url = build.url;
276
+ const writer = fs.createWriteStream(fileName);
277
+ const response = await axios({
278
+ url,
279
+ method: "GET",
280
+ responseType: "stream"
281
+ });
282
+ response.data.pipe(writer);
283
+ return new Promise((resolve, reject) => {
284
+ writer.on("finish", resolve);
285
+ writer.on("error", reject);
286
+ });
287
+ }
288
+
289
+ var Platform = /* @__PURE__ */ ((Platform2) => {
290
+ Platform2["IOS"] = "IOS";
291
+ Platform2["ANDROID"] = "ANDROID";
292
+ return Platform2;
293
+ })(Platform || {});
294
+ var GameEngine = /* @__PURE__ */ ((GameEngine2) => {
295
+ GameEngine2["GODOT"] = "godot";
296
+ return GameEngine2;
297
+ })(GameEngine || {});
298
+ var JobStatus = /* @__PURE__ */ ((JobStatus2) => {
299
+ JobStatus2["PENDING"] = "PENDING";
300
+ JobStatus2["PROCESSING"] = "PROCESSING";
301
+ JobStatus2["COMPLETED"] = "COMPLETED";
302
+ JobStatus2["FAILED"] = "FAILED";
303
+ return JobStatus2;
304
+ })(JobStatus || {});
305
+ var JobStage = /* @__PURE__ */ ((JobStage2) => {
306
+ JobStage2["SETUP"] = "SETUP";
307
+ JobStage2["EXPORT"] = "EXPORT";
308
+ JobStage2["CONFIGURE"] = "CONFIGURE";
309
+ JobStage2["BUILD"] = "BUILD";
310
+ JobStage2["PUBLISH"] = "PUBLISH";
311
+ return JobStage2;
312
+ })(JobStage || {});
313
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
314
+ LogLevel2["INFO"] = "INFO";
315
+ LogLevel2["WARN"] = "WARN";
316
+ LogLevel2["ERROR"] = "ERROR";
317
+ return LogLevel2;
318
+ })(LogLevel || {});
319
+ var CredentialsType = /* @__PURE__ */ ((CredentialsType2) => {
320
+ CredentialsType2["CERTIFICATE"] = "CERTIFICATE";
321
+ CredentialsType2["KEY"] = "KEY";
322
+ return CredentialsType2;
323
+ })(CredentialsType || {});
324
+
325
+ function isCWDGodotGame() {
326
+ const cwd = process.cwd();
327
+ const godotProject = path.join(cwd, "project.godot");
328
+ return fs__default.existsSync(godotProject);
329
+ }
330
+ const GODOT_CAPABILITIES = [
331
+ // TODO: how about capabilities from godot extensions
332
+ { name: "Access WiFi", key: "capabilities/access_wifi", type: CapabilityType.ACCESS_WIFI },
333
+ { name: "Push Notifications", key: "capabilities/push_notifications", type: CapabilityType.PUSH_NOTIFICATIONS }
334
+ ];
335
+ function getGodotProjectCapabilities(platform) {
336
+ const exportPresets = getGodotExportPresets(platform);
337
+ const options = exportPresets.options;
338
+ const capabilities = [];
339
+ for (const capability of GODOT_CAPABILITIES) {
340
+ if (!(capability.key in options)) continue;
341
+ if (`${options[capability.key]}`.toLocaleLowerCase() == "true") capabilities.push(capability.type);
342
+ }
343
+ return capabilities;
344
+ }
345
+ function getGodotProjectConfig() {
346
+ const cwd = process.cwd();
347
+ const projectGodotPath = path.join(cwd, "project.godot");
348
+ const projectGodotContent = fs__default.readFileSync(projectGodotPath, "utf8");
349
+ return parse(projectGodotContent);
350
+ }
351
+ function getGodotProjectName() {
352
+ try {
353
+ const projectGodotConfig = getGodotProjectConfig();
354
+ return projectGodotConfig["application"]["config/name"];
355
+ } catch (e) {
356
+ return null;
357
+ }
358
+ }
359
+ function getGodotAppleBundleIdentifier() {
360
+ try {
361
+ const preset = getGodotExportPresets(Platform.IOS);
362
+ return preset.options["application/bundle_identifier"];
363
+ } catch (e) {
364
+ console.log(e);
365
+ return null;
366
+ }
367
+ }
368
+ function getGodotAndroidPackageName() {
369
+ try {
370
+ const preset = getGodotExportPresets(Platform.ANDROID);
371
+ return preset.options["package/unique_name"];
372
+ } catch (e) {
373
+ console.log(e);
374
+ return null;
375
+ }
376
+ }
377
+ function getGodotVersion() {
378
+ const projectGodotConfig = getGodotProjectConfig();
379
+ if ("config/features" in projectGodotConfig["application"]) {
380
+ const features = projectGodotConfig["application"]["config/features"];
381
+ const match = features.match(/"(\d+\.\d+)"/);
382
+ if (!match) throw new Error("Couldn't find Godot version in project.godot");
383
+ return match[1];
384
+ }
385
+ return "3.6";
386
+ }
387
+ function getGodotExportPresets(platform) {
388
+ const { warn } = console;
389
+ let presetConfig = platform === Platform.IOS ? getBaseExportPresets_iOS() : getBaseExportPresets_Android();
390
+ const cwd = process.cwd();
391
+ const filename = "export_presets.cfg";
392
+ const exportPresetsPath = path.join(cwd, filename);
393
+ const isFound = fs__default.existsSync(exportPresetsPath);
394
+ if (!isFound) {
395
+ warn(`${filename} not found at ${exportPresetsPath}`);
396
+ } else {
397
+ const exportPresetsContent = fs__default.readFileSync(exportPresetsPath, "utf8");
398
+ const exportPresetsIni = parse(exportPresetsContent);
399
+ const presetIndexes = Object.keys(exportPresetsIni.preset);
400
+ const presetIndex = presetIndexes.find((index) => {
401
+ const current = exportPresetsIni.preset[index];
402
+ return `${current.name}`.toUpperCase() === platform;
403
+ });
404
+ if (!presetIndex) {
405
+ warn(`Preset ${platform} not found in ${filename} - will use defaults`);
406
+ } else {
407
+ presetConfig = merge(presetConfig, exportPresetsIni.preset[presetIndex]);
408
+ }
409
+ }
410
+ return presetConfig;
411
+ }
412
+ function getBaseExportPresets_iOS() {
413
+ return {
414
+ name: "iOS",
415
+ platform: "iOS",
416
+ runnable: true,
417
+ dedicated_server: false,
418
+ custom_features: "",
419
+ export_filter: "all_resources",
420
+ include_filter: "",
421
+ exclude_filter: "",
422
+ export_path: "output",
423
+ encryption_include_filters: "",
424
+ encryption_exclude_filters: "",
425
+ encrypt_pck: false,
426
+ encrypt_directory: false,
427
+ options: {
428
+ "custom_template/debug": "",
429
+ "custom_template/release": "",
430
+ "architectures/arm64": true,
431
+ "application/signature": "",
432
+ "application/icon_interpolation": "4",
433
+ "application/launch_screens_interpolation": "4",
434
+ "application/export_project_only": true,
435
+ "capabilities/access_wifi": false,
436
+ "capabilities/push_notifications": false,
437
+ "user_data/accessible_from_files_app": false,
438
+ "user_data/accessible_from_itunes_sharing": false,
439
+ "privacy/camera_usage_description": "",
440
+ "privacy/camera_usage_description_localized": "{}",
441
+ "privacy/microphone_usage_description": "",
442
+ "privacy/microphone_usage_description_localized": "{}",
443
+ "privacy/photolibrary_usage_description": "",
444
+ "privacy/photolibrary_usage_description_localized": "{}",
445
+ "icons/iphone_120x120": "",
446
+ "icons/iphone_180x180": "",
447
+ "icons/ipad_76x76": "",
448
+ "icons/ipad_152x152": "",
449
+ "icons/ipad_167x167": "",
450
+ "icons/app_store_1024x1024": "",
451
+ "icons/spotlight_40x40": "",
452
+ "icons/spotlight_80x80": "",
453
+ "icons/settings_58x58": "",
454
+ "icons/settings_87x87": "",
455
+ "icons/notification_40x40": "",
456
+ "icons/notification_60x60": "",
457
+ "storyboard/use_launch_screen_storyboard": true,
458
+ "storyboard/image_scale_mode": "0",
459
+ "storyboard/custom_image@2x": "",
460
+ "storyboard/custom_image@3x": "",
461
+ "storyboard/use_custom_bg_color": false,
462
+ "storyboard/custom_bg_color": "Color(0, 0, 0, 1)",
463
+ "landscape_launch_screens/iphone_2436x1125": "",
464
+ "landscape_launch_screens/iphone_2208x1242": "",
465
+ "landscape_launch_screens/ipad_1024x768": "",
466
+ "landscape_launch_screens/ipad_2048x1536": "",
467
+ "portrait_launch_screens/iphone_640x960": "",
468
+ "portrait_launch_screens/iphone_640x1136": "",
469
+ "portrait_launch_screens/iphone_750x1334": "",
470
+ "portrait_launch_screens/iphone_1125x2436": "",
471
+ "portrait_launch_screens/ipad_768x1024": "",
472
+ "portrait_launch_screens/ipad_1536x2048": "",
473
+ "portrait_launch_screens/iphone_1242x2208": "",
474
+ "application/short_version": "1.0.0"
475
+ // default version number
476
+ }
477
+ };
478
+ }
479
+ function getBaseExportPresets_Android() {
480
+ return {
481
+ name: "Android",
482
+ platform: "Android",
483
+ // TODO
484
+ options: {
485
+ // TODO
486
+ }
487
+ };
488
+ }
489
+
490
+ const queryClient = new QueryClient({
491
+ defaultOptions: {
492
+ queries: {
493
+ staleTime: 50
494
+ }
495
+ }
496
+ });
497
+
498
+ class BaseCommand extends Command {
499
+ // add the --json flag
500
+ static enableJsonFlag = false;
501
+ // define flags that can be inherited by any command that extends BaseCommand
502
+ static baseFlags = {};
503
+ flags;
504
+ args;
505
+ async init() {
506
+ process.on("SIGINT", () => process.exit(0));
507
+ process.on("SIGTERM", () => process.exit(0));
508
+ await super.init();
509
+ const { args, flags } = await this.parse({
510
+ flags: this.ctor.flags,
511
+ baseFlags: super.ctor.baseFlags,
512
+ enableJsonFlag: this.ctor.enableJsonFlag,
513
+ args: this.ctor.args,
514
+ strict: this.ctor.strict
515
+ });
516
+ this.flags = flags;
517
+ this.args = args;
518
+ if (this.hasAuthConfig()) await this.loadAuthConfig();
519
+ }
520
+ async catch(err) {
521
+ return super.catch(err);
522
+ }
523
+ async finally(_) {
524
+ return super.finally(_);
525
+ }
526
+ // Exposing it to the react components using the CommandContext
527
+ getFlags() {
528
+ return this.flags;
529
+ }
530
+ getAuthConfigPath() {
531
+ return path.join(this.config.home, ".shipthis.auth.json");
532
+ }
533
+ hasAuthConfig() {
534
+ const configPath = this.getAuthConfigPath();
535
+ return fs__default.existsSync(configPath);
536
+ }
537
+ async getAuthConfig() {
538
+ const baseConfig = {};
539
+ const configPath = this.getAuthConfigPath();
540
+ if (!fs__default.existsSync(configPath)) return baseConfig;
541
+ const raw = await fs__default.promises.readFile(configPath, "utf8");
542
+ const typesConfig = JSON.parse(raw);
543
+ return {
544
+ ...baseConfig,
545
+ ...typesConfig
546
+ };
547
+ }
548
+ async setAuthConfig(config) {
549
+ const configPath = this.getAuthConfigPath();
550
+ await fs__default.promises.writeFile(configPath, JSON.stringify(config, null, 2));
551
+ }
552
+ async loadAuthConfig() {
553
+ const authConfig = await this.getAuthConfig();
554
+ if (!authConfig.shipThisUser) {
555
+ throw new Error("You must be logged in to use this command");
556
+ }
557
+ setAuthToken(authConfig.shipThisUser.jwt);
558
+ }
559
+ getProjectConfigPath() {
560
+ return path.join(process.cwd(), "shipthis.json");
561
+ }
562
+ hasProjectConfig() {
563
+ const configPath = this.getProjectConfigPath();
564
+ return fs__default.existsSync(configPath);
565
+ }
566
+ async getProjectConfig() {
567
+ if (!this.hasProjectConfig()) throw new Error("No project config found");
568
+ return this.getProjectConfigSafe();
569
+ }
570
+ async getProjectConfigSafe() {
571
+ if (!this.hasProjectConfig()) return {};
572
+ const configPath = this.getProjectConfigPath();
573
+ const raw = await fs__default.promises.readFile(configPath, "utf8");
574
+ return JSON.parse(raw);
575
+ }
576
+ async setProjectConfig(config) {
577
+ const configPath = this.getProjectConfigPath();
578
+ await fs__default.promises.writeFile(configPath, JSON.stringify(config, null, 2));
579
+ }
580
+ async updateProjectConfig(update) {
581
+ const config = await this.getProjectConfig();
582
+ await this.setProjectConfig({ ...config, ...update });
583
+ }
584
+ // Used in baseGameCommand and the other commands that need to ensure that the CWD is a Godot project
585
+ ensureWeAreInAProjectDir() {
586
+ if (!isCWDGodotGame()) {
587
+ this.error("No Godot project detected. Please run this from a godot project directory.", { exit: 1 });
588
+ }
589
+ if (!this.hasProjectConfig()) {
590
+ this.error(
591
+ 'No ShipThis config found. Please run `shipthis game create --name "Space Invaders"` to create a game.',
592
+ { exit: 1 }
593
+ );
594
+ }
595
+ }
596
+ async refreshAppleAuthState() {
597
+ const cookies = await this.getAppleCookies();
598
+ const rerunMessage = "Please run shipthis apple login to authenticate with Apple.";
599
+ if (!cookies) throw new Error(`No Apple cookies found. ${rerunMessage}`);
600
+ const authState = await Auth.loginWithCookiesAsync(
601
+ {
602
+ cookies
603
+ },
604
+ {}
605
+ );
606
+ if (!authState) throw new Error(`Failed to refresh Apple auth state. ${rerunMessage}`);
607
+ return authState;
608
+ }
609
+ // Tests the apple cookies
610
+ async hasValidAppleAuthState() {
611
+ try {
612
+ await this.refreshAppleAuthState();
613
+ return true;
614
+ } catch (e) {
615
+ return false;
616
+ }
617
+ }
618
+ // Used in the apple commands to get the cookies from the auth file
619
+ async getAppleCookies() {
620
+ const authConfig = await this.getAuthConfig();
621
+ if (!authConfig.appleCookies) return null;
622
+ return authConfig.appleCookies;
623
+ }
624
+ async setAppleCookies(cookies) {
625
+ const authConfig = await this.getAuthConfig();
626
+ await this.setAuthConfig({ ...authConfig, appleCookies: cookies });
627
+ }
628
+ ensureWeHaveAppleCookies() {
629
+ if (!this.hasAuthConfig()) {
630
+ this.error("You must be authenticated with Apple in to use this command. Please run shipthis apple login", {
631
+ exit: 1
632
+ });
633
+ }
634
+ }
635
+ // Returns the values of the flags in DetailsFlags
636
+ // This is used to expose the flags to the Android Wizard
637
+ getDetailsFlagsValues() {
638
+ const keys = Object.keys(DetailsFlags);
639
+ const values = {};
640
+ for (const key of keys) {
641
+ if (this.flags[key]) values[key] = this.flags[key];
642
+ }
643
+ return values;
644
+ }
645
+ async getGameId() {
646
+ const { flags } = this;
647
+ if (flags.gameId) return flags.gameId;
648
+ const { project } = await this.getProjectConfigSafe();
649
+ if (!project) return null;
650
+ return project.id;
651
+ }
652
+ }
653
+
654
+ class BaseAuthenticatedCommand extends BaseCommand {
655
+ static flags = {};
656
+ async init() {
657
+ await super.init();
658
+ if (!this.hasAuthConfig()) {
659
+ this.error("No auth config found. Please run `shipthis login` to authenticate.", { exit: 1 });
660
+ }
661
+ const self = await getSelf();
662
+ const accepted = !!self.details?.hasAcceptedTerms;
663
+ if (!accepted) {
664
+ this.error("You must accept the terms and conditions. Please run `shipthis login --force` to re-authenticate", {
665
+ exit: 1
666
+ });
667
+ }
668
+ }
669
+ }
670
+
671
+ class BaseGameCommand extends BaseAuthenticatedCommand {
672
+ static flags = {
673
+ ...BaseAuthenticatedCommand.flags,
674
+ gameId: Flags.string({ char: "g", description: "The ID of the game" })
675
+ };
676
+ async getGame() {
677
+ try {
678
+ const gameId = await this.getGameId();
679
+ if (!gameId) this.error("No game ID found.");
680
+ return await getProject(gameId);
681
+ } catch (e) {
682
+ if (e?.response?.status === 404) {
683
+ this.error("Game not found - please check you have access");
684
+ } else throw e;
685
+ }
686
+ }
687
+ async updateGame(update) {
688
+ const project = await this.getGame();
689
+ const projectUpdate = {
690
+ ...project,
691
+ ...update
692
+ };
693
+ const updatedProject = await updateProject(project.id, projectUpdate);
694
+ await this.updateProjectConfig({ project: updatedProject });
695
+ return updatedProject;
696
+ }
697
+ }
698
+
699
+ const DetailsFlags = {
700
+ name: Flags.string({ char: "n", description: "The name of the game" }),
701
+ buildNumber: Flags.integer({ char: "b", description: "Set the build number" }),
702
+ semanticVersion: Flags.string({ char: "s", description: "Set the semantic version" }),
703
+ gameEngine: Flags.string({ char: "e", description: "Set the game engine" }),
704
+ gameEngineVersion: Flags.string({ char: "v", description: "Set the game engine version" }),
705
+ iosBundleId: Flags.string({ char: "i", description: "Set the iOS bundle ID" }),
706
+ androidPackageName: Flags.string({ char: "a", description: "Set the Android package name" }),
707
+ gcpProjectId: Flags.string({ char: "g", description: "Set the GCP project ID" }),
708
+ gcpServiceAccountId: Flags.string({ char: "c", description: "Set the GCP service account ID" })
709
+ };
710
+
711
+ export { acceptTerms as $, ApiKey as A, BaseAuthenticatedCommand as B, CredentialsType as C, DetailsFlags as D, getJob as E, castJobDates as F, GODOT_CAPABILITIES as G, castObjectDates as H, getProject as I, JobStatus as J, downloadBuildById as K, castArrayObjectDates as L, queryClient as M, JobStage as N, LogLevel as O, Platform as P, getAuthToken as Q, WS_URL as R, getGodotAndroidPackageName as S, getGoogleStatus as T, UserRole as U, inviteServiceAccount as V, WEB_URL as W, disconnectGoogle as X, BaseCommand as Y, getSingleUseUrl as Z, setAuthToken as _, ApiKeyType as a, Auth as a0, getNewUploadTicket as a1, startJobsFromUpload as a2, getShortAuthRequiredUrl as a3, getGoogleAuthUrl as a4, getShortTime as a5, getShortDateTime as a6, getShortTimeDelta as a7, updateProject as a8, getShortDate as b, BaseGameCommand as c, getGodotAppleBundleIdentifier as d, BundleId as e, App as f, getProjects as g, CapabilityTypeOption as h, BetaGroup as i, isCWDGodotGame as j, getProjectPlatformProgress as k, Certificate as l, CertificateType as m, Profile as n, ProfileType as o, getAuthedHeaders as p, API_URL as q, getGodotProjectCapabilities as r, CapabilityType as s, GameEngine as t, getGodotVersion as u, createProject as v, DEFAULT_IGNORED_FILES_GLOBS as w, DEFAULT_SHIPPED_FILES_GLOBS as x, getGodotProjectName as y, getProjectJobs as z };