@makefully/adaptfully 4.0.0 → 4.2.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.
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path';
2
- import { loadProjectConfig, resolveServerUrl } from './config.js';
2
+ import { loadProjectConfig, resolveServerUrl, resolveAccessToken, resolveEncryptFlag } from './config.js';
3
3
  import { send } from './deploy.js';
4
4
  import { resolveBuildArtifactDir } from './artifacts.js';
5
5
  import { prebuildPlatform } from './prebuild.js';
@@ -12,6 +12,8 @@ import {
12
12
  import { steamPublishFromCli } from './steam-publish.js';
13
13
  import { googlePublishFromCli } from './google-publish.js';
14
14
  import { applePublishFromCli } from './apple-publish.js';
15
+ import { androidKeystoreFromCli } from './android-keystore.js';
16
+ import { appleSigningFromCli } from './apple-signing.js';
15
17
 
16
18
  /** @typedef {'prebuild' | 'build' | 'deploy' | 'release'} AdaptfullyStage */
17
19
 
@@ -20,6 +22,8 @@ const PUBLISH_COMMANDS = {
20
22
  'steam-publish': steamPublishFromCli,
21
23
  'google-publish': googlePublishFromCli,
22
24
  'apple-publish': applePublishFromCli,
25
+ 'android-keystore': androidKeystoreFromCli,
26
+ 'apple-signing': appleSigningFromCli,
23
27
  };
24
28
 
25
29
  /**
@@ -40,7 +44,7 @@ export function resolveWrapfullyRoute(buildSpec) {
40
44
  /**
41
45
  * @param {AdaptfullyStage} stage
42
46
  * @param {string} platformKey
43
- * @param {{ pkg: object, deployFolder: string, server?: string, mode?: string, deployment?: string, artifactPath?: string, log?: (message: string) => void, outputRoot?: string }} options
47
+ * @param {{ pkg: object, deployFolder: string, server?: string, mode?: string, deployment?: string, artifactPath?: string, log?: (message: string) => void, outputRoot?: string, accessToken?: string, encrypt?: boolean, encryptPublicKey?: string, wrapfullyConfig?: object }} options
44
48
  */
45
49
  export async function runAdaptfullyStage(stage, platformKey, options) {
46
50
  if (!VALID_STAGES.has(stage)) {
@@ -99,7 +103,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
99
103
 
100
104
  log(
101
105
  `adaptfully: ${stage} ${platformKey} → ${buildSpec.family} `
102
- + `(${buildSpec.targets.join(', ')}) via /${wrapfullyRoute}/release`,
106
+ + `(${buildSpec.targets.join(', ')}) via Yap /yap/wrapfully (route ${wrapfullyRoute}/release)`,
103
107
  );
104
108
 
105
109
  log(
@@ -121,6 +125,10 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
121
125
  log,
122
126
  platformKey,
123
127
  deploymentDirs: deploymentDirs.map((dir) => path.resolve(dir)),
128
+ accessToken: options.accessToken,
129
+ encrypt: options.encrypt,
130
+ encryptPublicKey: options.encryptPublicKey,
131
+ wrapfullyConfig: options.wrapfullyConfig,
124
132
  },
125
133
  );
126
134
 
@@ -138,7 +146,7 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
138
146
  log(
139
147
  `adaptfully: ${stage} ${platformKey} → `
140
148
  + `${deploymentKey === 'zip' ? 'artifact zip' : `deployment "${deploymentKey}"`} `
141
- + `via Wrapfully /${wrapfullyRoute}/${wrapStage} (${buildSpec.family})`,
149
+ + `via Yap /yap/wrapfully (route ${wrapfullyRoute}/${wrapStage}, ${buildSpec.family})`,
142
150
  );
143
151
 
144
152
  if (deploymentDirs.length) {
@@ -165,6 +173,10 @@ export async function runAdaptfullyStage(stage, platformKey, options) {
165
173
  platformKey,
166
174
  deploymentKey: wrapStage === 'deploy' ? deploymentKey : undefined,
167
175
  artifactPath,
176
+ accessToken: options.accessToken,
177
+ encrypt: options.encrypt,
178
+ encryptPublicKey: options.encryptPublicKey,
179
+ wrapfullyConfig: options.wrapfullyConfig,
168
180
  },
169
181
  );
170
182
 
@@ -190,7 +202,7 @@ export async function adaptfullyFromCli(argv = process.argv) {
190
202
  }
191
203
 
192
204
  const stage = command;
193
- const { positionals, deployment, artifactPath } = parseStageArgs(argv.slice(3));
205
+ const { positionals, deployment, artifactPath, encrypt, encryptPublicKey } = parseStageArgs(argv.slice(3));
194
206
  const platformKey = positionals[0];
195
207
  const cliServer = positionals[1];
196
208
  const mode = positionals[2] ?? 'extract';
@@ -198,29 +210,42 @@ export async function adaptfullyFromCli(argv = process.argv) {
198
210
  if (!stage || !platformKey) {
199
211
  throw new Error(
200
212
  'Usage:\n'
201
- + ' adaptfully <prebuild|build|deploy|release> <platform> [server] [mode] [--deployment <key>] [--artifact <path>]\n'
213
+ + ' adaptfully <prebuild|build|deploy|release> <platform> [showfullyServer] [mode]\n'
214
+ + ' [--deployment <key>] [--artifact <path>] [--encrypt] [--encrypt-public-key <pem|path>]\n'
202
215
  + ' adaptfully steam-publish [--username U] [--password P] [--deployment steam] [--output path]\n'
203
216
  + ' adaptfully google-publish [--from service-account.json] [--deployment android] [--output path]\n'
204
217
  + ' adaptfully apple-publish [--deployment ios] [--category C] [--identity I] [--username U] [--password P]\n'
218
+ + ' adaptfully android-keystore [--deployment android] [--debug-only] [--yes]\n'
219
+ + ' adaptfully apple-signing [--deployment ios] [--kind development|distribution] [--csr-only] [--from-cer path] [--provision path]\n'
205
220
  + '\n'
206
221
  + 'Stages:\n'
207
222
  + ' prebuild Copy deploy/ and apply platform registrations → output/<platform>-prebuild/\n'
208
- + ' build prebuild + POST /{target|family}/build (zip artifact only)\n'
209
- + ' deploy POST /deploy/{key} with prior artifact + deployment credentials\n'
210
- + ' release prebuild + POST /{target|family}/release (build + configured deployments)\n'
223
+ + ' build prebuild + POST /yap/wrapfully (zip artifact only; Showfully PAT required)\n'
224
+ + ' deploy Yap deploy chore with prior artifact + deployment credentials\n'
225
+ + ' release Yap release chore (build + configured deployments)\n'
211
226
  + '\n'
212
227
  + ' --deployment <key> Target a single named deployment.\n'
213
228
  + ' --artifact <path> Prior build artifact directory (deploy only; default: ./output/ after build).\n'
229
+ + ' --encrypt Envelope-encrypt chore to Wrapfully (optional; default key embedded).\n'
230
+ + ' --encrypt-public-key <pem|path> Override Wrapfully public key when encrypting.\n'
231
+ + '\n'
232
+ + 'Auth / server (wrapfully.json or env):\n'
233
+ + ' SHOWFULLY_PAT / accessToken required PAT from play.makefullystudios.com Settings\n'
234
+ + ' SHOWFULLY_SERVER / server Showfully Yap base (default https://make.makefullystudios.com/)\n'
214
235
  + '\n'
215
236
  + 'Publish credential helpers (one-time local setup):\n'
216
- + ' steam-publish Install steamcmd if needed, log in, write steam deployment steam.json\n'
217
- + ' google-publish Import a Play service-account JSON into the android deployment folder\n'
218
- + ' apple-publish Write App Store Connect credentials into the ios deployment folder',
237
+ + ' steam-publish Install steamcmd if needed, log in, write steam deployment steam.json\n'
238
+ + ' google-publish Import a Play service-account JSON into the android deployment folder\n'
239
+ + ' apple-publish Write App Store Connect credentials into the ios deployment folder\n'
240
+ + ' android-keystore Generate debug/release keystores and write android build.json\n'
241
+ + ' apple-signing Generate CSR, export .p12, place provisioning profiles under ios/apple/',
219
242
  );
220
243
  }
221
244
 
222
245
  const { pkg, wrapfullyConfig } = await loadProjectConfig();
223
246
  const server = resolveServerUrl(wrapfullyConfig, cliServer);
247
+ const accessToken = resolveAccessToken(wrapfullyConfig);
248
+ const encryptFlag = resolveEncryptFlag(wrapfullyConfig, encrypt);
224
249
  const deployFolder = pkg.config?.deployFolder || 'deploy';
225
250
 
226
251
  return runAdaptfullyStage(/** @type {AdaptfullyStage} */ (stage), platformKey, {
@@ -230,18 +255,24 @@ export async function adaptfullyFromCli(argv = process.argv) {
230
255
  mode,
231
256
  deployment,
232
257
  artifactPath,
258
+ accessToken,
259
+ encrypt: encryptFlag,
260
+ encryptPublicKey,
261
+ wrapfullyConfig,
233
262
  });
234
263
  }
235
264
 
236
265
  /**
237
266
  * @param {string[]} args
238
- * @returns {{ positionals: string[], deployment?: string, artifactPath?: string }}
267
+ * @returns {{ positionals: string[], deployment?: string, artifactPath?: string, encrypt?: boolean, encryptPublicKey?: string }}
239
268
  */
240
269
  export function parseStageArgs(args) {
241
270
  /** @type {string[]} */
242
271
  const positionals = [];
243
272
  let deployment;
244
273
  let artifactPath;
274
+ let encrypt;
275
+ let encryptPublicKey;
245
276
 
246
277
  for (let i = 0; i < args.length; i++) {
247
278
  const arg = args[i];
@@ -254,10 +285,16 @@ export function parseStageArgs(args) {
254
285
  artifactPath = args[++i];
255
286
  } else if (arg.startsWith('--artifact=')) {
256
287
  artifactPath = arg.slice('--artifact='.length);
288
+ } else if (arg === '--encrypt') {
289
+ encrypt = true;
290
+ } else if (arg === '--encrypt-public-key' && args[i + 1]) {
291
+ encryptPublicKey = args[++i];
292
+ } else if (arg.startsWith('--encrypt-public-key=')) {
293
+ encryptPublicKey = arg.slice('--encrypt-public-key='.length);
257
294
  } else {
258
295
  positionals.push(arg);
259
296
  }
260
297
  }
261
298
 
262
- return { positionals, deployment, artifactPath };
299
+ return { positionals, deployment, artifactPath, encrypt, encryptPublicKey };
263
300
  }
@@ -211,13 +211,33 @@ export async function promptRequired(prompt, existing) {
211
211
  }
212
212
  }
213
213
 
214
+ /**
215
+ * @param {string} prompt
216
+ * @param {boolean} [defaultYes=false]
217
+ * @returns {Promise<boolean>}
218
+ */
219
+ export async function promptConfirm(prompt, defaultYes = false) {
220
+ const rl = readline.createInterface({ input, output });
221
+ const suffix = defaultYes ? ' [Y/n] ' : ' [y/N] ';
222
+
223
+ try {
224
+ const answer = String(await rl.question(`${prompt}${suffix}`)).trim().toLowerCase();
225
+ if (!answer) {
226
+ return defaultYes;
227
+ }
228
+ return answer === 'y' || answer === 'yes';
229
+ } finally {
230
+ rl.close();
231
+ }
232
+ }
233
+
214
234
  /**
215
235
  * Parse shared CLI flags used by publish credential helpers.
216
236
  * @param {string[]} argv
217
237
  * @param {number} [startIndex=3]
218
238
  */
219
239
  export function parsePublishCredentialArgv(argv, startIndex = 3) {
220
- /** @type {Record<string, string>} */
240
+ /** @type {Record<string, string | boolean>} */
221
241
  const options = {
222
242
  projectRoot: '.',
223
243
  };
@@ -243,6 +263,32 @@ export function parsePublishCredentialArgv(argv, startIndex = 3) {
243
263
  options.username = argv[++i];
244
264
  } else if (arg === '--password' && argv[i + 1]) {
245
265
  options.password = argv[++i];
266
+ } else if (arg === '--debug-only') {
267
+ options.debugOnly = true;
268
+ } else if (arg === '--csr-only') {
269
+ options.csrOnly = true;
270
+ } else if (arg === '--yes' || arg === '-y') {
271
+ options.yes = true;
272
+ } else if (arg === '--from-cer' && argv[i + 1]) {
273
+ options.fromCer = normalizeUserPath(argv[++i]);
274
+ } else if (arg === '--kind' && argv[i + 1]) {
275
+ options.kind = argv[++i];
276
+ } else if (arg === '--provision' && argv[i + 1]) {
277
+ options.provision = normalizeUserPath(argv[++i]);
278
+ } else if (arg === '--workdir' && argv[i + 1]) {
279
+ options.workdir = normalizeUserPath(argv[++i]);
280
+ } else if (arg === '--alias' && argv[i + 1]) {
281
+ options.alias = argv[++i];
282
+ } else if (arg === '--store-password' && argv[i + 1]) {
283
+ options.storePassword = argv[++i];
284
+ } else if (arg === '--key-password' && argv[i + 1]) {
285
+ options.keyPassword = argv[++i];
286
+ } else if (arg === '--p12-password' && argv[i + 1]) {
287
+ options.p12Password = argv[++i];
288
+ } else if (arg === '--cn' && argv[i + 1]) {
289
+ options.cn = argv[++i];
290
+ } else if (arg === '--email' && argv[i + 1]) {
291
+ options.email = argv[++i];
246
292
  }
247
293
  }
248
294
 
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Default Makefully Wrapfully fleet public key (kid: makefully-wrapfully-1).
3
+ * Private key lives only on Wrapfully workers (WRAPFULLY_PRIVATE_KEY / cred.json).
4
+ * Safe to embed in clients — used only to wrap chore AES keys when encrypt: true.
5
+ */
6
+ export const WRAPFULLY_DEFAULT_KID = 'makefully-wrapfully-1';
7
+
8
+ export const WRAPFULLY_DEFAULT_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
9
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArbQGAXiX+XtnsdS0yUPj
10
+ dgM2Vt8lwDXPtLxzjYD45fr/NEOct0+ECsvr3jyIB/cVCjINpJJyKGEBvZk8woFj
11
+ FgyodSWjJrc1UsomeOz6IcOArWu6GnkFo0jn8R0FN8LOhEl1xjqT7VPzF4jd7/P5
12
+ 4WBNeB+wjkY/XBmk5wsNLvGaREp8G4fFfMgDNPpTUy7RB8ezolTiWZH0KgiXZtM8
13
+ yUXk5YBPxTwI28wCB6Om5RGmwozWc66k29qZQRv5d4GRMSM18lMKh3gkjptZRhRD
14
+ D48bKDQwYPX8CWcpl/Q9qm2L0wtikjQWro1NsAreqa3r91wlrsYZ82stYIyKBYhW
15
+ LwIDAQAB
16
+ -----END PUBLIC KEY-----
17
+ `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makefully/adaptfully",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "Platform abstraction and Wrapfully deploy client for Makefully games",
5
5
  "type": "module",
6
6
  "main": "./lib/node/index.js",
@@ -17,6 +17,7 @@
17
17
  "files": [
18
18
  "bin",
19
19
  "lib",
20
+ "docs",
20
21
  "CHANGELOG.md",
21
22
  "LICENSE",
22
23
  "README.md"