lim 0.19.4 → 0.20.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/README.md +16 -0
- package/dist/commands/gradle/build.d.ts +7 -0
- package/dist/commands/gradle/build.d.ts.map +1 -1
- package/dist/commands/gradle/build.js +66 -2
- package/dist/commands/gradle/build.js.map +1 -1
- package/dist/commands/xcode/run.d.ts +26 -0
- package/dist/commands/xcode/run.d.ts.map +1 -0
- package/dist/commands/xcode/run.js +134 -0
- package/dist/commands/xcode/run.js.map +1 -0
- package/dist/lib/android-keystore.d.ts +15 -0
- package/dist/lib/android-keystore.d.ts.map +1 -0
- package/dist/lib/android-keystore.js +65 -0
- package/dist/lib/android-keystore.js.map +1 -0
- package/dist/lib/android-keystore.test.d.ts +2 -0
- package/dist/lib/android-keystore.test.d.ts.map +1 -0
- package/dist/lib/android-keystore.test.js +43 -0
- package/dist/lib/android-keystore.test.js.map +1 -0
- package/dist/lib/auth.d.ts +1 -0
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +1 -0
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/backend.d.ts +32 -0
- package/dist/lib/backend.d.ts.map +1 -0
- package/dist/lib/backend.js +81 -0
- package/dist/lib/backend.js.map +1 -0
- package/dist/lib/backend.test.d.ts +2 -0
- package/dist/lib/backend.test.d.ts.map +1 -0
- package/dist/lib/backend.test.js +124 -0
- package/dist/lib/backend.test.js.map +1 -0
- package/dist/lib/gradle-build-options.d.ts +21 -0
- package/dist/lib/gradle-build-options.d.ts.map +1 -1
- package/dist/lib/gradle-build-options.js +41 -0
- package/dist/lib/gradle-build-options.js.map +1 -1
- package/dist/lib/gradle-build-options.test.d.ts +2 -0
- package/dist/lib/gradle-build-options.test.d.ts.map +1 -0
- package/dist/lib/gradle-build-options.test.js +63 -0
- package/dist/lib/gradle-build-options.test.js.map +1 -0
- package/dist/lib/gradle-signing.d.ts +44 -0
- package/dist/lib/gradle-signing.d.ts.map +1 -0
- package/dist/lib/gradle-signing.js +167 -0
- package/dist/lib/gradle-signing.js.map +1 -0
- package/dist/lib/gradle-signing.test.d.ts +2 -0
- package/dist/lib/gradle-signing.test.d.ts.map +1 -0
- package/dist/lib/gradle-signing.test.js +111 -0
- package/dist/lib/gradle-signing.test.js.map +1 -0
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -424,6 +424,9 @@ lim xcode create --rm --region us-west --hard-timeout 1h
|
|
|
424
424
|
# Build (automatically syncs the project path first)
|
|
425
425
|
lim xcode build ./MyProject --scheme MyApp --workspace MyApp.xcworkspace
|
|
426
426
|
|
|
427
|
+
# Run a project command (syncs the current directory first)
|
|
428
|
+
lim xcode run -- make api
|
|
429
|
+
|
|
427
430
|
# Build and upload artifact
|
|
428
431
|
lim xcode build ./MyProject --scheme MyApp --upload my-app-build
|
|
429
432
|
|
|
@@ -670,6 +673,19 @@ lim asset pull my-app-build -o ./build-output
|
|
|
670
673
|
|
|
671
674
|
`lim xcode build [PATH]` automatically performs a one-shot code sync for the given project path before invoking `xcodebuild`. The sync step automatically ignores build artifacts (`build/`, `DerivedData/`, `.build/`), dependency folders (`Pods/`, `Carthage/Build/`, `.swiftpm/`), and user-specific files (`xcuserdata/`, `.dSYM/`).
|
|
672
675
|
|
|
676
|
+
#### Run project commands
|
|
677
|
+
|
|
678
|
+
`lim xcode run [RELATIVE_CWD] -- <COMMAND...>` syncs the current directory and runs a one-shot command in the Xcode sandbox. The remote working directory defaults to the synced workspace root:
|
|
679
|
+
|
|
680
|
+
```bash
|
|
681
|
+
lim xcode run -- make api
|
|
682
|
+
lim xcode run apps/api -- make generate
|
|
683
|
+
lim xcode run --env API_ENV=development -- npm run generate
|
|
684
|
+
lim xcode run --no-sync -- mise run build
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
The sandbox includes Node, Ruby, CMake, Mint, and mise. mise and Mint installs are scoped to the instance's sandbox home. Homebrew is not available because its macOS packages require a shared system prefix; use mise, Mint, SwiftPM, or project-local binaries instead. Commands stream stdout and stderr and return the remote exit code, but do not provide an interactive terminal.
|
|
688
|
+
|
|
673
689
|
For [XcodeGen](https://github.com/yonaskolb/XcodeGen) projects whose generated `.xcodeproj` is gitignored, the server generates it from your synced `project.yml` automatically before the build — it looks next to a pinned `--project`/`--workspace` path, at the synced folder root, and one directory level down. If your spec has a different name or location, pin it with `--xcodegen-spec <path>`, optionally control the output directory with `--xcodegen-project <dir>`, and anchor relative paths in the spec with `--xcodegen-project-root <dir>`; all paths are relative to the synced folder root and mirror `xcodegen generate --spec/--project/--project-root`. Passing any of these flags always regenerates the project on the server:
|
|
674
690
|
|
|
675
691
|
```bash
|
|
@@ -14,6 +14,13 @@ export default class GradleBuild extends BaseCommand {
|
|
|
14
14
|
abi: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
15
|
upload: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
16
|
'signed-upload-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
17
|
+
sign: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
'application-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
|
+
keystore: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
20
|
+
'keystore-password': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
21
|
+
'key-alias': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
22
|
+
'key-password': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
23
|
+
'save-key': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
24
|
'basis-cache-dir': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
25
|
ignore: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
26
|
include: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/gradle/build.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/commands/gradle/build.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAgBjD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,WAAW;IAClD,MAAM,CAAC,OAAO,SAAmD;IACjE,MAAM,CAAC,WAAW,SAEgG;IAElH,MAAM,CAAC,QAAQ,WAQb;IAEF,MAAM,CAAC,IAAI;;MAKT;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;;;;;;;;;;;;;;MAmEV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA0G3B"}
|
|
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const base_command_1 = require("../../base-command");
|
|
5
5
|
const ignore_patterns_1 = require("../../lib/ignore-patterns");
|
|
6
6
|
const gradle_build_options_1 = require("../../lib/gradle-build-options");
|
|
7
|
+
const gradle_signing_1 = require("../../lib/gradle-signing");
|
|
7
8
|
const duration_1 = require("../../lib/duration");
|
|
8
9
|
const bytes_1 = require("../../lib/bytes");
|
|
9
10
|
class GradleBuild extends base_command_1.BaseCommand {
|
|
@@ -14,16 +15,47 @@ class GradleBuild extends base_command_1.BaseCommand {
|
|
|
14
15
|
// auto-create a billed instance, which a doomed flag combination must
|
|
15
16
|
// never reach.
|
|
16
17
|
let options;
|
|
18
|
+
let applicationId;
|
|
19
|
+
const syncPath = args.path ?? process.cwd();
|
|
17
20
|
try {
|
|
18
21
|
options = (0, gradle_build_options_1.gradleBuildOptionsFromFlags)(flags);
|
|
22
|
+
if (flags.sign || flags['save-key']) {
|
|
23
|
+
applicationId = (0, gradle_signing_1.resolveApplicationId)({
|
|
24
|
+
explicit: flags['application-id'],
|
|
25
|
+
syncPath,
|
|
26
|
+
expoAppDir: flags['expo-app-dir'],
|
|
27
|
+
projectPath: flags['project-path'],
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (flags.keystore) {
|
|
31
|
+
options.signing = (0, gradle_signing_1.readProvidedSigning)({
|
|
32
|
+
keystore: flags.keystore,
|
|
33
|
+
keystorePassword: flags['keystore-password'],
|
|
34
|
+
keyAlias: flags['key-alias'],
|
|
35
|
+
keyPassword: flags['key-password'],
|
|
36
|
+
});
|
|
37
|
+
}
|
|
19
38
|
}
|
|
20
39
|
catch (err) {
|
|
21
40
|
return this.error(err instanceof Error ? err.message : String(err));
|
|
22
41
|
}
|
|
23
42
|
await this.withAuth(async () => {
|
|
43
|
+
// Escrow round-trips run BEFORE resolveGradleTargetOrCreate for the
|
|
44
|
+
// same reason flag validation does: a failure here must not leave a
|
|
45
|
+
// freshly created billed instance behind.
|
|
46
|
+
if (applicationId && flags['save-key'] && options.signing) {
|
|
47
|
+
const saved = await (0, gradle_signing_1.saveProvidedKey)(this.client, applicationId, options.signing);
|
|
48
|
+
this.info(saved ?
|
|
49
|
+
`Escrowed the provided keystore as the organization's upload key for ${applicationId}.`
|
|
50
|
+
: `The provided keystore is already escrowed for ${applicationId}.`);
|
|
51
|
+
}
|
|
52
|
+
else if (applicationId && flags.sign) {
|
|
53
|
+
const { signing, created } = await (0, gradle_signing_1.resolveEscrowedSigning)(this.client, applicationId);
|
|
54
|
+
options.signing = signing;
|
|
55
|
+
this.info(`Signing with the organization's upload key for ${applicationId} (${created ? 'newly generated' : 'existing'}).`);
|
|
56
|
+
}
|
|
24
57
|
const target = await this.resolveGradleTargetOrCreate(flags.id);
|
|
25
58
|
const id = target.id;
|
|
26
|
-
const syncPath = args.path ?? process.cwd();
|
|
27
59
|
const gradleClient = await this.resolveGradleClient(target);
|
|
28
60
|
this.info(`Syncing ${syncPath} to instance ${id}...`);
|
|
29
61
|
const syncStart = Date.now();
|
|
@@ -51,7 +83,14 @@ class GradleBuild extends base_command_1.BaseCommand {
|
|
|
51
83
|
this.error(`gradle build failed with exit code ${result.exitCode}`, { exit: result.exitCode });
|
|
52
84
|
}
|
|
53
85
|
this.output(`\nBuild succeeded (exit code ${result.exitCode})`);
|
|
54
|
-
|
|
86
|
+
// Signing only yields a Play-ready AAB when a bundle task ran (no
|
|
87
|
+
// explicit tasks means the server defaulted to bundleRelease); a BYO
|
|
88
|
+
// keystore with an explicit assemble task still produces an APK.
|
|
89
|
+
const builtSignedBundle = options.signing && (!flags.task?.length || (0, gradle_build_options_1.tasksIncludeBundle)(flags.task));
|
|
90
|
+
if (flags.upload && builtSignedBundle) {
|
|
91
|
+
this.output(`Uploaded the signed app bundle as asset '${flags.upload}'.`);
|
|
92
|
+
}
|
|
93
|
+
else if (flags.upload) {
|
|
55
94
|
this.output(`Uploaded APK as asset '${flags.upload}'.`);
|
|
56
95
|
this.output(`Run it with: lim android create --install-asset=${flags.upload}`);
|
|
57
96
|
}
|
|
@@ -70,6 +109,8 @@ GradleBuild.examples = [
|
|
|
70
109
|
'<%= config.bin %> gradle build --task bundleRelease',
|
|
71
110
|
'<%= config.bin %> gradle build --id <gradle-instance-ID> --project-path android',
|
|
72
111
|
'<%= config.bin %> gradle build ./my-monorepo --expo-app-dir apps/mobile',
|
|
112
|
+
'<%= config.bin %> gradle build --sign --upload myapp.aab',
|
|
113
|
+
'<%= config.bin %> gradle build --keystore upload.jks --keystore-password *** --key-alias upload --key-password *** --save-key',
|
|
73
114
|
];
|
|
74
115
|
GradleBuild.args = {
|
|
75
116
|
path: core_1.Args.string({
|
|
@@ -101,6 +142,29 @@ GradleBuild.flags = {
|
|
|
101
142
|
'signed-upload-url': core_1.Flags.string({
|
|
102
143
|
description: 'Presigned URL to upload the resulting APK to.',
|
|
103
144
|
}),
|
|
145
|
+
sign: core_1.Flags.boolean({
|
|
146
|
+
description: "Sign the release build with the organization's escrowed upload key for this app, generating and escrowing one on first use. Makes bundleRelease the default task.",
|
|
147
|
+
default: false,
|
|
148
|
+
}),
|
|
149
|
+
'application-id': core_1.Flags.string({
|
|
150
|
+
description: 'Android application ID naming the escrowed key. Defaults to the value detected from app.json or app/build.gradle.',
|
|
151
|
+
}),
|
|
152
|
+
keystore: core_1.Flags.string({
|
|
153
|
+
description: 'Path to your own upload keystore for release signing. Requires --keystore-password, --key-alias and --key-password.',
|
|
154
|
+
}),
|
|
155
|
+
'keystore-password': core_1.Flags.string({
|
|
156
|
+
description: 'Password of the --keystore file.',
|
|
157
|
+
env: 'LIM_KEYSTORE_PASSWORD',
|
|
158
|
+
}),
|
|
159
|
+
'key-alias': core_1.Flags.string({ description: 'Alias of the signing key inside the --keystore file.' }),
|
|
160
|
+
'key-password': core_1.Flags.string({
|
|
161
|
+
description: 'Password of the key behind --key-alias.',
|
|
162
|
+
env: 'LIM_KEY_PASSWORD',
|
|
163
|
+
}),
|
|
164
|
+
'save-key': core_1.Flags.boolean({
|
|
165
|
+
description: "Escrow the provided --keystore as the organization's upload key for this app, so later builds can use --sign. Fails if a different key is already escrowed.",
|
|
166
|
+
default: false,
|
|
167
|
+
}),
|
|
104
168
|
'basis-cache-dir': core_1.Flags.string({
|
|
105
169
|
description: 'Directory for the client-side folder-sync cache.',
|
|
106
170
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/commands/gradle/build.ts"],"names":[],"mappings":";;AAAA,sCAA0C;AAE1C,qDAAiD;AACjD,+DAAkE;AAClE,
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/commands/gradle/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
export default class XcodeRun extends BaseCommand {
|
|
3
|
+
static summary: string;
|
|
4
|
+
static description: string;
|
|
5
|
+
static examples: string[];
|
|
6
|
+
static args: {
|
|
7
|
+
cwd: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
8
|
+
};
|
|
9
|
+
static flags: {
|
|
10
|
+
id: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
env: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
timeout: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
'no-sync': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
'basis-cache-dir': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
|
+
ignore: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
|
+
include: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
17
|
+
'additional-file': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
|
+
'api-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
20
|
+
quiet: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
21
|
+
create: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
22
|
+
workspace: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
23
|
+
};
|
|
24
|
+
run(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/xcode/run.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAMjD,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,WAAW;IAC/C,MAAM,CAAC,OAAO,SAAuC;IACrD,MAAM,CAAC,WAAW,SAC8F;IAEhH,MAAM,CAAC,QAAQ,WAKb;IAEF,MAAM,CAAC,IAAI;;MAMT;IAEF,MAAM,CAAC,KAAK;;;;;;;;;;;;;;MAuCV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAyD3B"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../../base-command");
|
|
5
|
+
const ignore_patterns_1 = require("../../lib/ignore-patterns");
|
|
6
|
+
const duration_1 = require("../../lib/duration");
|
|
7
|
+
const bytes_1 = require("../../lib/bytes");
|
|
8
|
+
const additional_files_1 = require("../../lib/additional-files");
|
|
9
|
+
class XcodeRun extends base_command_1.BaseCommand {
|
|
10
|
+
async run() {
|
|
11
|
+
const delimiter = this.argv.indexOf('--');
|
|
12
|
+
if (delimiter < 0) {
|
|
13
|
+
this.error('Separate the remote command with `--`, for example: lim xcode run -- make api');
|
|
14
|
+
}
|
|
15
|
+
const commandArgs = this.argv.slice(delimiter + 1);
|
|
16
|
+
if (commandArgs.length === 0) {
|
|
17
|
+
this.error('A command is required after `--`.');
|
|
18
|
+
}
|
|
19
|
+
const { args, flags } = await this.parse(XcodeRun, this.argv.slice(0, delimiter));
|
|
20
|
+
this.setParsedFlags(flags);
|
|
21
|
+
const env = parseEnvironmentEntries(flags.env ?? [], (message) => this.error(message));
|
|
22
|
+
const commandLine = commandArgs.length === 1 ? commandArgs[0] : commandArgs.map(quoteShellArgument).join(' ');
|
|
23
|
+
await this.withAuth(async () => {
|
|
24
|
+
const target = await this.resolveXcodeTargetOrCreate(flags.id);
|
|
25
|
+
const xcodeClient = await this.resolveXcodeClient(target);
|
|
26
|
+
if (!flags['no-sync']) {
|
|
27
|
+
const syncPath = process.cwd();
|
|
28
|
+
this.info(`Syncing ${syncPath} to instance ${target.id}...`);
|
|
29
|
+
const syncStart = Date.now();
|
|
30
|
+
const result = await xcodeClient.sync(syncPath, {
|
|
31
|
+
watch: false,
|
|
32
|
+
install: false,
|
|
33
|
+
basisCacheDir: flags['basis-cache-dir'],
|
|
34
|
+
ignore: (0, ignore_patterns_1.compileIgnorePatterns)(flags.ignore),
|
|
35
|
+
include: (0, ignore_patterns_1.compileIgnorePatterns)(flags.include),
|
|
36
|
+
additionalFiles: (0, additional_files_1.parseAdditionalFileFlags)(flags['additional-file']),
|
|
37
|
+
});
|
|
38
|
+
const syncDuration = (0, duration_1.formatDurationMs)(Date.now() - syncStart);
|
|
39
|
+
const syncedSize = result.bytesSent !== undefined ? ` (${(0, bytes_1.formatBytes)(result.bytesSent)} sent)` : '';
|
|
40
|
+
this.info(`Sync completed in ${syncDuration}${syncedSize}.`);
|
|
41
|
+
}
|
|
42
|
+
this.info(`Running in ${args.cwd ?? '.'}: ${commandLine}`);
|
|
43
|
+
const proc = xcodeClient.run(commandLine, {
|
|
44
|
+
cwd: args.cwd ?? '.',
|
|
45
|
+
...(env && { env }),
|
|
46
|
+
...(flags.timeout !== undefined && { timeoutSeconds: flags.timeout }),
|
|
47
|
+
});
|
|
48
|
+
proc.stdout.on('data', (line) => process.stdout.write(line + '\n'));
|
|
49
|
+
proc.stderr.on('data', (line) => process.stderr.write(line + '\n'));
|
|
50
|
+
const result = await proc;
|
|
51
|
+
if (result.exitCode !== 0) {
|
|
52
|
+
if (result.timedOut) {
|
|
53
|
+
this.error('Timed out waiting for the command to finish; the remote command may still be running.', { exit: result.exitCode });
|
|
54
|
+
}
|
|
55
|
+
this.error(`Command failed with exit code ${result.exitCode}`, { exit: result.exitCode });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
XcodeRun.summary = 'Run a command on an Xcode sandbox';
|
|
61
|
+
XcodeRun.description = 'Sync the current directory, then run a one-shot shell command in the remote workspace with streamed output.';
|
|
62
|
+
XcodeRun.examples = [
|
|
63
|
+
'<%= config.bin %> xcode run -- make api',
|
|
64
|
+
'<%= config.bin %> xcode run apps/api -- make generate',
|
|
65
|
+
'<%= config.bin %> xcode run --env API_ENV=development -- npm run generate',
|
|
66
|
+
'<%= config.bin %> xcode run --no-sync -- mise run build',
|
|
67
|
+
];
|
|
68
|
+
XcodeRun.args = {
|
|
69
|
+
cwd: core_1.Args.string({
|
|
70
|
+
description: 'Remote working directory relative to the synced workspace root. Defaults to ".".',
|
|
71
|
+
required: false,
|
|
72
|
+
default: '.',
|
|
73
|
+
}),
|
|
74
|
+
};
|
|
75
|
+
XcodeRun.flags = {
|
|
76
|
+
...base_command_1.BaseCommand.baseFlags,
|
|
77
|
+
id: core_1.Flags.string({
|
|
78
|
+
description: 'Xcode instance ID to run on. Defaults to the most recent standalone Xcode target.',
|
|
79
|
+
}),
|
|
80
|
+
env: core_1.Flags.string({
|
|
81
|
+
description: 'Environment variable in KEY=VALUE form. Repeat for multiple variables.',
|
|
82
|
+
multiple: true,
|
|
83
|
+
multipleNonGreedy: true,
|
|
84
|
+
}),
|
|
85
|
+
timeout: core_1.Flags.integer({
|
|
86
|
+
description: 'Server-side command timeout in seconds. Defaults to 3600, max 21600.',
|
|
87
|
+
min: 1,
|
|
88
|
+
max: 21600,
|
|
89
|
+
}),
|
|
90
|
+
'no-sync': core_1.Flags.boolean({
|
|
91
|
+
description: 'Skip syncing the current directory before running the command.',
|
|
92
|
+
default: false,
|
|
93
|
+
}),
|
|
94
|
+
'basis-cache-dir': core_1.Flags.string({
|
|
95
|
+
description: 'Directory to use for the client-side delta sync cache.',
|
|
96
|
+
}),
|
|
97
|
+
ignore: core_1.Flags.string({
|
|
98
|
+
description: 'Regular expression to ignore matching relative paths during sync. Repeat for multiple.',
|
|
99
|
+
multiple: true,
|
|
100
|
+
multipleNonGreedy: true,
|
|
101
|
+
}),
|
|
102
|
+
include: core_1.Flags.string({
|
|
103
|
+
description: 'Regular expression to force-sync matching relative paths even when gitignored. Repeat for multiple.',
|
|
104
|
+
multiple: true,
|
|
105
|
+
multipleNonGreedy: true,
|
|
106
|
+
}),
|
|
107
|
+
'additional-file': core_1.Flags.string({
|
|
108
|
+
description: 'Additional file to sync as localPath=remotePath, for example ~/.netrc=~/.netrc. Repeat for multiple.',
|
|
109
|
+
multiple: true,
|
|
110
|
+
multipleNonGreedy: true,
|
|
111
|
+
}),
|
|
112
|
+
};
|
|
113
|
+
exports.default = XcodeRun;
|
|
114
|
+
function quoteShellArgument(value) {
|
|
115
|
+
return `'${value.split("'").join("'\"'\"'")}'`;
|
|
116
|
+
}
|
|
117
|
+
function parseEnvironmentEntries(entries, fail) {
|
|
118
|
+
if (entries.length === 0)
|
|
119
|
+
return undefined;
|
|
120
|
+
const env = {};
|
|
121
|
+
for (const entry of entries) {
|
|
122
|
+
const separator = entry.indexOf('=');
|
|
123
|
+
if (separator <= 0) {
|
|
124
|
+
fail(`Invalid --env value ${JSON.stringify(entry)}; expected KEY=VALUE.`);
|
|
125
|
+
}
|
|
126
|
+
const key = entry.slice(0, separator);
|
|
127
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
128
|
+
fail(`Invalid environment variable name ${JSON.stringify(key)}.`);
|
|
129
|
+
}
|
|
130
|
+
env[key] = entry.slice(separator + 1);
|
|
131
|
+
}
|
|
132
|
+
return env;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/commands/xcode/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type AndroidSigningKey = {
|
|
2
|
+
keystoreBase64: string;
|
|
3
|
+
keystorePassword: string;
|
|
4
|
+
keyAlias: string;
|
|
5
|
+
keyPassword: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Generates an Android upload keystore entirely in JS: a local JDK cannot
|
|
9
|
+
* be assumed since builds run remotely. The output is a PKCS12 the JDK's
|
|
10
|
+
* dual-format keystore reader auto-detects; 3DES encryption keeps it
|
|
11
|
+
* readable by every Java version. Store and key password are the same
|
|
12
|
+
* value, which PKCS12 under Java effectively requires.
|
|
13
|
+
*/
|
|
14
|
+
export declare function generateAndroidSigningKey(applicationId: string): AndroidSigningKey;
|
|
15
|
+
//# sourceMappingURL=android-keystore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android-keystore.d.ts","sourceRoot":"","sources":["../../src/lib/android-keystore.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAmBF;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,aAAa,EAAE,MAAM,GAAG,iBAAiB,CAqClF"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateAndroidSigningKey = generateAndroidSigningKey;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const node_forge_1 = __importDefault(require("node-forge"));
|
|
9
|
+
// Google Play requires upload-key certificates to stay valid well past
|
|
10
|
+
// 2033; ~27 years matches what Android Studio generates.
|
|
11
|
+
const validityDays = 10000;
|
|
12
|
+
const keyAlias = 'upload';
|
|
13
|
+
// Alphanumeric only: the values end up in gradle.properties, which Gradle
|
|
14
|
+
// reads as ISO-8859-1, and must survive any shell quoting users apply.
|
|
15
|
+
const passwordAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
16
|
+
function generatePassword(length = 24) {
|
|
17
|
+
let out = '';
|
|
18
|
+
for (let i = 0; i < length; i++) {
|
|
19
|
+
out += passwordAlphabet[(0, node_crypto_1.randomInt)(passwordAlphabet.length)];
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generates an Android upload keystore entirely in JS: a local JDK cannot
|
|
25
|
+
* be assumed since builds run remotely. The output is a PKCS12 the JDK's
|
|
26
|
+
* dual-format keystore reader auto-detects; 3DES encryption keeps it
|
|
27
|
+
* readable by every Java version. Store and key password are the same
|
|
28
|
+
* value, which PKCS12 under Java effectively requires.
|
|
29
|
+
*/
|
|
30
|
+
function generateAndroidSigningKey(applicationId) {
|
|
31
|
+
const password = generatePassword();
|
|
32
|
+
// Native keygen (hundreds of ms) instead of node-forge's pure-JS one
|
|
33
|
+
// (many seconds of silent event-loop blocking); forge only assembles
|
|
34
|
+
// the certificate and PKCS12, mirroring the ui package's apple crypto.
|
|
35
|
+
const { privateKey: privateKeyPem } = (0, node_crypto_1.generateKeyPairSync)('rsa', {
|
|
36
|
+
modulusLength: 2048,
|
|
37
|
+
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
38
|
+
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
|
|
39
|
+
});
|
|
40
|
+
const privateKey = node_forge_1.default.pki.privateKeyFromPem(privateKeyPem);
|
|
41
|
+
const publicKey = node_forge_1.default.pki.setRsaPublicKey(privateKey.n, privateKey.e);
|
|
42
|
+
const certificate = node_forge_1.default.pki.createCertificate();
|
|
43
|
+
certificate.publicKey = publicKey;
|
|
44
|
+
certificate.serialNumber = '01' + node_forge_1.default.util.bytesToHex(node_forge_1.default.random.getBytesSync(15));
|
|
45
|
+
certificate.validity.notBefore = new Date();
|
|
46
|
+
certificate.validity.notAfter = new Date(Date.now() + validityDays * 24 * 60 * 60 * 1000);
|
|
47
|
+
certificate.setSubject([
|
|
48
|
+
{ name: 'commonName', value: applicationId },
|
|
49
|
+
{ name: 'organizationName', value: 'Limrun' },
|
|
50
|
+
]);
|
|
51
|
+
certificate.setIssuer(certificate.subject.attributes);
|
|
52
|
+
certificate.sign(privateKey, node_forge_1.default.md.sha256.create());
|
|
53
|
+
const p12 = node_forge_1.default.pkcs12.toPkcs12Asn1(privateKey, [certificate], password, {
|
|
54
|
+
algorithm: '3des',
|
|
55
|
+
friendlyName: keyAlias,
|
|
56
|
+
});
|
|
57
|
+
const keystoreBase64 = node_forge_1.default.util.encode64(node_forge_1.default.asn1.toDer(p12).getBytes());
|
|
58
|
+
return {
|
|
59
|
+
keystoreBase64,
|
|
60
|
+
keystorePassword: password,
|
|
61
|
+
keyAlias,
|
|
62
|
+
keyPassword: password,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=android-keystore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android-keystore.js","sourceRoot":"","sources":["../../src/lib/android-keystore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android-keystore.test.d.ts","sourceRoot":"","sources":["../../src/lib/android-keystore.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_forge_1 = __importDefault(require("node-forge"));
|
|
7
|
+
const android_keystore_1 = require("./android-keystore");
|
|
8
|
+
describe('generateAndroidSigningKey', () => {
|
|
9
|
+
// One shared key: RSA generation dominates test time.
|
|
10
|
+
const key = (0, android_keystore_1.generateAndroidSigningKey)('com.example.app');
|
|
11
|
+
it('produces the exact androidSigningKey secret data shape', () => {
|
|
12
|
+
expect(Object.keys(key).sort()).toEqual([
|
|
13
|
+
'keyAlias',
|
|
14
|
+
'keyPassword',
|
|
15
|
+
'keystoreBase64',
|
|
16
|
+
'keystorePassword',
|
|
17
|
+
]);
|
|
18
|
+
expect(key.keyAlias).toBe('upload');
|
|
19
|
+
expect(key.keystorePassword).toBe(key.keyPassword);
|
|
20
|
+
expect(key.keystorePassword).toMatch(/^[A-Za-z0-9]{24}$/);
|
|
21
|
+
});
|
|
22
|
+
it('builds a PKCS12 that opens with the emitted password and holds a long-lived RSA-2048 key', () => {
|
|
23
|
+
const der = node_forge_1.default.util.decode64(key.keystoreBase64);
|
|
24
|
+
expect(der.length).toBeGreaterThan(0);
|
|
25
|
+
const p12 = node_forge_1.default.pkcs12.pkcs12FromAsn1(node_forge_1.default.asn1.fromDer(der), key.keystorePassword);
|
|
26
|
+
const keyBags = p12.getBags({ bagType: node_forge_1.default.pki.oids.pkcs8ShroudedKeyBag })[node_forge_1.default.pki.oids.pkcs8ShroudedKeyBag];
|
|
27
|
+
expect(keyBags).toHaveLength(1);
|
|
28
|
+
expect(keyBags[0].attributes.friendlyName?.[0]).toBe('upload');
|
|
29
|
+
const privateKey = keyBags[0].key;
|
|
30
|
+
expect(privateKey.n.bitLength()).toBe(2048);
|
|
31
|
+
const certBags = p12.getBags({ bagType: node_forge_1.default.pki.oids.certBag })[node_forge_1.default.pki.oids.certBag];
|
|
32
|
+
expect(certBags).toHaveLength(1);
|
|
33
|
+
const cert = certBags[0].cert;
|
|
34
|
+
// Play requires upload certificates valid well past 2033.
|
|
35
|
+
expect(cert.validity.notAfter.getFullYear()).toBeGreaterThan(2034);
|
|
36
|
+
expect(cert.subject.getField('CN').value).toBe('com.example.app');
|
|
37
|
+
});
|
|
38
|
+
it('rejects the wrong password', () => {
|
|
39
|
+
const der = node_forge_1.default.util.decode64(key.keystoreBase64);
|
|
40
|
+
expect(() => node_forge_1.default.pkcs12.pkcs12FromAsn1(node_forge_1.default.asn1.fromDer(der), 'wrong-password')).toThrow();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=android-keystore.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android-keystore.test.js","sourceRoot":"","sources":["../../src/lib/android-keystore.test.ts"],"names":[],"mappings":";;;;;AAAA,4DAA+B;AAE/B,yDAA+D;AAE/D,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,sDAAsD;IACtD,MAAM,GAAG,GAAG,IAAA,4CAAyB,EAAC,iBAAiB,CAAC,CAAC;IAEzD,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC;YACtC,UAAU;YACV,aAAa;YACb,gBAAgB;YAChB,kBAAkB;SACnB,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACnD,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0FAA0F,EAAE,GAAG,EAAE;QAClG,MAAM,GAAG,GAAG,oBAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,oBAAK,CAAC,MAAM,CAAC,cAAc,CAAC,oBAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAEvF,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,oBAAK,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAC1E,oBAAK,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,CACnC,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,OAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChE,MAAM,UAAU,GAAG,OAAQ,CAAC,CAAC,CAAC,CAAC,GAA+B,CAAC;QAC/D,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE5C,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,oBAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,oBAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1F,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,QAAS,CAAC,CAAC,CAAC,CAAC,IAAK,CAAC;QAChC,0DAA0D;QAC1D,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACnE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,GAAG,GAAG,oBAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,EAAE,CAAC,oBAAK,CAAC,MAAM,CAAC,cAAc,CAAC,oBAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IACjG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/lib/auth.d.ts
CHANGED
|
@@ -13,5 +13,6 @@ interface LoginOptions {
|
|
|
13
13
|
type LoginRuntimeOptions = Omit<LoginOptions, 'apiEndpoint' | 'consoleEndpoint' | 'version'>;
|
|
14
14
|
export declare function login(apiEndpoint: string, consoleEndpoint: string, version: string, options?: LoginRuntimeOptions): Promise<void>;
|
|
15
15
|
export declare function loginWithOptions(options: LoginOptions): Promise<void>;
|
|
16
|
+
export declare function responseMessage(response: Response): Promise<string>;
|
|
16
17
|
export {};
|
|
17
18
|
//# sourceMappingURL=auth.d.ts.map
|
package/dist/lib/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAe,MAAM,UAAU,CAAC;AAIpD,UAAU,YAAY;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE,OAAO,WAAW,CAAC;IAClC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACrD,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgBD,KAAK,mBAAmB,GAAG,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,iBAAiB,GAAG,SAAS,CAAC,CAAC;AAa7F,wBAAsB,KAAK,CACzB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA8C3E"}
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAe,MAAM,UAAU,CAAC;AAIpD,UAAU,YAAY;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE,OAAO,WAAW,CAAC;IAClC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACrD,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgBD,KAAK,mBAAmB,GAAG,IAAI,CAAC,YAAY,EAAE,aAAa,GAAG,iBAAiB,GAAG,SAAS,CAAC,CAAC;AAa7F,wBAAsB,KAAK,CACzB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA8C3E;AAyHD,wBAAsB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAOzE"}
|
package/dist/lib/auth.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.login = login;
|
|
7
7
|
exports.loginWithOptions = loginWithOptions;
|
|
8
|
+
exports.responseMessage = responseMessage;
|
|
8
9
|
const child_process_1 = require("child_process");
|
|
9
10
|
const os_1 = __importDefault(require("os"));
|
|
10
11
|
const process_1 = __importDefault(require("process"));
|
package/dist/lib/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":";;;;;AA8CA,sBAOC;AAED,4CA8CC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import Limrun from '@limrun/api';
|
|
2
|
+
/**
|
|
3
|
+
* Backend API endpoints the generated resources do not cover (Stainless
|
|
4
|
+
* consumes the director spec only). Rides the SDK client's transport, so
|
|
5
|
+
* auth headers, retries and the 401 -> AuthenticationError mapping that
|
|
6
|
+
* withAuth's re-login relies on all come for free.
|
|
7
|
+
*/
|
|
8
|
+
export type SecretData = Record<string, string>;
|
|
9
|
+
export type PutSecretResult = {
|
|
10
|
+
data: SecretData;
|
|
11
|
+
/** True when this call created the secret, false on a get-or-create hit. */
|
|
12
|
+
created: boolean;
|
|
13
|
+
};
|
|
14
|
+
export declare const androidSigningKeySecretType = "androidSigningKey";
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the organization the API key acts for. `lim login` keys are
|
|
17
|
+
* organization tokens, so `organization` is the normal path; hand-set
|
|
18
|
+
* user API keys fall back to the user's default organization, which
|
|
19
|
+
* /v1/whoami nests inside `user`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function whoAmI(client: Limrun): Promise<string>;
|
|
22
|
+
/** Fetches a secret's data, or undefined when it does not exist. */
|
|
23
|
+
export declare function getSecret(client: Limrun, organizationId: string, secretType: string, secretName: string): Promise<SecretData | undefined>;
|
|
24
|
+
/**
|
|
25
|
+
* Get-or-create put. The response data is authoritative: on a hit the
|
|
26
|
+
* submitted data was NOT stored and the caller must adopt the returned
|
|
27
|
+
* material instead. Creation is signaled by the response body's
|
|
28
|
+
* `created` today and by HTTP 201 after the status-split hardening;
|
|
29
|
+
* accept both so either server version works.
|
|
30
|
+
*/
|
|
31
|
+
export declare function putSecret(client: Limrun, organizationId: string, secretType: string, secretName: string, data: SecretData): Promise<PutSecretResult>;
|
|
32
|
+
//# sourceMappingURL=backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/lib/backend.ts"],"names":[],"mappings":"AAAA,OAAO,MAAwD,MAAM,aAAa,CAAC;AAEnF;;;;;GAKG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEhD,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAU/D;;;;;GAKG;AACH,wBAAsB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAY5D;AAQD,oEAAoE;AACpE,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAcjC;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,eAAe,CAAC,CAgB1B"}
|