@lynxship/cli 0.1.19 → 0.1.21

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 (193) hide show
  1. package/README.md +66 -5
  2. package/dist/android/signing.d.ts +16 -0
  3. package/dist/android/signing.d.ts.map +1 -0
  4. package/dist/android/signing.js +131 -0
  5. package/dist/android/types.d.ts +12 -0
  6. package/dist/android/types.d.ts.map +1 -0
  7. package/dist/android/types.js +1 -0
  8. package/dist/android-build.d.ts +4 -13
  9. package/dist/android-build.d.ts.map +1 -1
  10. package/dist/android-build.js +14 -133
  11. package/dist/android-toolchain/inspection.d.ts +3 -0
  12. package/dist/android-toolchain/inspection.d.ts.map +1 -0
  13. package/dist/android-toolchain/inspection.js +122 -0
  14. package/dist/android-toolchain/probes.d.ts +23 -0
  15. package/dist/android-toolchain/probes.d.ts.map +1 -0
  16. package/dist/android-toolchain/probes.js +183 -0
  17. package/dist/android-toolchain/types.d.ts +20 -0
  18. package/dist/android-toolchain/types.d.ts.map +1 -0
  19. package/dist/android-toolchain/types.js +1 -0
  20. package/dist/android-toolchain.d.ts +4 -20
  21. package/dist/android-toolchain.d.ts.map +1 -1
  22. package/dist/android-toolchain.js +4 -300
  23. package/dist/app-config.d.ts +25 -0
  24. package/dist/app-config.d.ts.map +1 -0
  25. package/dist/app-config.js +106 -0
  26. package/dist/bundle-build.d.ts.map +1 -1
  27. package/dist/bundle-build.js +11 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +66 -0
  31. package/dist/commands/build-execution.d.ts +41 -0
  32. package/dist/commands/build-execution.d.ts.map +1 -0
  33. package/dist/commands/build-execution.js +182 -0
  34. package/dist/commands/configuration.d.ts +19 -0
  35. package/dist/commands/configuration.d.ts.map +1 -0
  36. package/dist/commands/configuration.js +174 -0
  37. package/dist/commands/development.d.ts +22 -0
  38. package/dist/commands/development.d.ts.map +1 -0
  39. package/dist/commands/development.js +132 -0
  40. package/dist/commands/device.d.ts +3 -0
  41. package/dist/commands/device.d.ts.map +1 -0
  42. package/dist/commands/device.js +86 -0
  43. package/dist/commands/doctor.d.ts +18 -0
  44. package/dist/commands/doctor.d.ts.map +1 -0
  45. package/dist/commands/doctor.js +320 -0
  46. package/dist/commands/help.d.ts +2 -0
  47. package/dist/commands/help.d.ts.map +1 -0
  48. package/dist/commands/help.js +118 -0
  49. package/dist/commands/i18n.d.ts +14 -0
  50. package/dist/commands/i18n.d.ts.map +1 -0
  51. package/dist/commands/i18n.js +88 -0
  52. package/dist/commands/logs.d.ts +3 -0
  53. package/dist/commands/logs.d.ts.map +1 -0
  54. package/dist/commands/logs.js +51 -0
  55. package/dist/commands/metadata.d.ts +3 -0
  56. package/dist/commands/metadata.d.ts.map +1 -0
  57. package/dist/commands/metadata.js +45 -0
  58. package/dist/commands/ota.d.ts +28 -0
  59. package/dist/commands/ota.d.ts.map +1 -0
  60. package/dist/commands/ota.js +203 -0
  61. package/dist/commands/project.d.ts +14 -0
  62. package/dist/commands/project.d.ts.map +1 -0
  63. package/dist/commands/project.js +122 -0
  64. package/dist/commands/remote-build.d.ts +35 -0
  65. package/dist/commands/remote-build.d.ts.map +1 -0
  66. package/dist/commands/remote-build.js +73 -0
  67. package/dist/commands/submit.d.ts +27 -0
  68. package/dist/commands/submit.d.ts.map +1 -0
  69. package/dist/commands/submit.js +92 -0
  70. package/dist/ecosystem.d.ts +9 -0
  71. package/dist/ecosystem.d.ts.map +1 -0
  72. package/dist/ecosystem.js +95 -0
  73. package/dist/frameworks.d.ts.map +1 -1
  74. package/dist/frameworks.js +5 -1
  75. package/dist/guidance/catalog.d.ts +3 -0
  76. package/dist/guidance/catalog.d.ts.map +1 -0
  77. package/dist/guidance/catalog.js +504 -0
  78. package/dist/guidance/types.d.ts +10 -0
  79. package/dist/guidance/types.d.ts.map +1 -0
  80. package/dist/guidance/types.js +1 -0
  81. package/dist/guidance.d.ts +2 -9
  82. package/dist/guidance.d.ts.map +1 -1
  83. package/dist/guidance.js +1 -502
  84. package/dist/i18n/discovery.d.ts +14 -0
  85. package/dist/i18n/discovery.d.ts.map +1 -0
  86. package/dist/i18n/discovery.js +106 -0
  87. package/dist/i18n/plan.d.ts +12 -0
  88. package/dist/i18n/plan.d.ts.map +1 -0
  89. package/dist/i18n/plan.js +95 -0
  90. package/dist/i18n/setup.d.ts +11 -0
  91. package/dist/i18n/setup.d.ts.map +1 -0
  92. package/dist/i18n/setup.js +47 -0
  93. package/dist/i18n/types.d.ts +17 -0
  94. package/dist/i18n/types.d.ts.map +1 -0
  95. package/dist/i18n/types.js +1 -0
  96. package/dist/index.d.ts +1 -1
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +4 -2069
  99. package/dist/ios/assets.d.ts +19 -0
  100. package/dist/ios/assets.d.ts.map +1 -0
  101. package/dist/ios/assets.js +128 -0
  102. package/dist/ios/production-build.d.ts +6 -0
  103. package/dist/ios/production-build.d.ts.map +1 -0
  104. package/dist/ios/production-build.js +200 -0
  105. package/dist/ios/project.d.ts +4 -0
  106. package/dist/ios/project.d.ts.map +1 -0
  107. package/dist/ios/project.js +43 -0
  108. package/dist/ios/simulator-build.d.ts +8 -0
  109. package/dist/ios/simulator-build.d.ts.map +1 -0
  110. package/dist/ios/simulator-build.js +188 -0
  111. package/dist/ios/simulator.d.ts +5 -0
  112. package/dist/ios/simulator.d.ts.map +1 -0
  113. package/dist/ios/simulator.js +60 -0
  114. package/dist/ios/types.d.ts +14 -0
  115. package/dist/ios/types.d.ts.map +1 -0
  116. package/dist/ios/types.js +1 -0
  117. package/dist/ios-build.d.ts +4 -37
  118. package/dist/ios-build.d.ts.map +1 -1
  119. package/dist/ios-build.js +3 -575
  120. package/dist/ios-host.d.ts.map +1 -1
  121. package/dist/ios-toolchain/inspection.d.ts +4 -0
  122. package/dist/ios-toolchain/inspection.d.ts.map +1 -0
  123. package/dist/ios-toolchain/inspection.js +211 -0
  124. package/dist/ios-toolchain/probes.d.ts +24 -0
  125. package/dist/ios-toolchain/probes.d.ts.map +1 -0
  126. package/dist/ios-toolchain/probes.js +127 -0
  127. package/dist/ios-toolchain/types.d.ts +17 -0
  128. package/dist/ios-toolchain/types.d.ts.map +1 -0
  129. package/dist/ios-toolchain/types.js +1 -0
  130. package/dist/ios-toolchain.d.ts +3 -18
  131. package/dist/ios-toolchain.d.ts.map +1 -1
  132. package/dist/ios-toolchain.js +1 -333
  133. package/dist/plugins/contracts.d.ts +28 -0
  134. package/dist/plugins/contracts.d.ts.map +1 -0
  135. package/dist/plugins/contracts.js +1 -0
  136. package/dist/plugins/discovery.d.ts +19 -0
  137. package/dist/plugins/discovery.d.ts.map +1 -0
  138. package/dist/plugins/discovery.js +250 -0
  139. package/dist/plugins/native-operations.d.ts +28 -0
  140. package/dist/plugins/native-operations.d.ts.map +1 -0
  141. package/dist/plugins/native-operations.js +217 -0
  142. package/dist/plugins/operations.d.ts +9 -0
  143. package/dist/plugins/operations.d.ts.map +1 -0
  144. package/dist/plugins/operations.js +76 -0
  145. package/dist/plugins/validation.d.ts +9 -0
  146. package/dist/plugins/validation.d.ts.map +1 -0
  147. package/dist/plugins/validation.js +52 -0
  148. package/dist/plugins.d.ts +3 -34
  149. package/dist/plugins.d.ts.map +1 -1
  150. package/dist/plugins.js +2 -595
  151. package/dist/process-runner.d.ts +4 -0
  152. package/dist/process-runner.d.ts.map +1 -1
  153. package/dist/process-runner.js +14 -0
  154. package/dist/remote.d.ts +22 -1
  155. package/dist/remote.d.ts.map +1 -1
  156. package/dist/remote.js +141 -2
  157. package/dist/rspeedy-app-config.d.ts +4 -0
  158. package/dist/rspeedy-app-config.d.ts.map +1 -0
  159. package/dist/rspeedy-app-config.js +32 -0
  160. package/dist/runtime/args.d.ts +3 -0
  161. package/dist/runtime/args.d.ts.map +1 -0
  162. package/dist/runtime/args.js +11 -0
  163. package/dist/runtime/build-commands.d.ts +3 -0
  164. package/dist/runtime/build-commands.d.ts.map +1 -0
  165. package/dist/runtime/build-commands.js +282 -0
  166. package/dist/runtime/context.d.ts +63 -0
  167. package/dist/runtime/context.d.ts.map +1 -0
  168. package/dist/runtime/context.js +179 -0
  169. package/dist/runtime/early-commands.d.ts +4 -0
  170. package/dist/runtime/early-commands.d.ts.map +1 -0
  171. package/dist/runtime/early-commands.js +284 -0
  172. package/dist/runtime/project.d.ts +8 -0
  173. package/dist/runtime/project.d.ts.map +1 -0
  174. package/dist/runtime/project.js +38 -0
  175. package/dist/runtime/state.d.ts +47 -0
  176. package/dist/runtime/state.d.ts.map +1 -0
  177. package/dist/runtime/state.js +33 -0
  178. package/dist/secure-store/backends.d.ts +20 -0
  179. package/dist/secure-store/backends.d.ts.map +1 -0
  180. package/dist/secure-store/backends.js +248 -0
  181. package/dist/secure-store/types.d.ts +27 -0
  182. package/dist/secure-store/types.d.ts.map +1 -0
  183. package/dist/secure-store/types.js +1 -0
  184. package/dist/secure-store.d.ts +2 -26
  185. package/dist/secure-store.d.ts.map +1 -1
  186. package/dist/secure-store.js +3 -245
  187. package/dist/ui/components.d.ts.map +1 -1
  188. package/dist/ui/components.js +2 -1
  189. package/package.json +7 -4
  190. package/templates/android-host/app/build.gradle +1 -0
  191. package/templates/android-host/app/src/main/java/template/MainActivity.java +98 -3
  192. package/templates/ios-host/__IOS_TARGET_NAME__/DemoLynxProvider.swift +26 -16
  193. package/templates/ios-host/__IOS_TARGET_NAME__/ViewController.swift +107 -19
@@ -0,0 +1,122 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { basename, join } from "node:path";
4
+ import { assert } from "@lynxship/contracts";
5
+ import { detectLynxFramework } from "../frameworks.js";
6
+ import { hasAndroidHost, isSupportedAndroidPlatform, } from "../android-build.js";
7
+ import { initializeAndroidHost, suggestedAndroidApplicationId, } from "../android-host.js";
8
+ import { initializeIosHost, suggestedIosBundleIdentifier, } from "../ios-host.js";
9
+ import { hasIosHost } from "../ios-build.js";
10
+ import { DEFAULT_CONFIG, resolveProfile, } from "../config.js";
11
+ import { hasHarmonyHost } from "../harmony-build.js";
12
+ import { hasWebConfiguration } from "../web-build.js";
13
+ import { hasDesktopHost } from "../desktop-build.js";
14
+ import { exists } from "../runtime/project.js";
15
+ import { loadAppConfig } from "../app-config.js";
16
+ export async function looksLikeLynxProject(context) {
17
+ const framework = await detectLynxFramework(context.root);
18
+ if (framework.framework !== "unknown")
19
+ return true;
20
+ const configFiles = [
21
+ "lynx.config.ts",
22
+ "lynx.config.js",
23
+ "lynx.config.mjs",
24
+ "lynx.config.cjs",
25
+ "app.config.ts",
26
+ "app.config.js",
27
+ "app.config.mjs",
28
+ "app.config.cjs",
29
+ ];
30
+ if (await Promise.any(configFiles.map((file) => exists(join(context.root, file)))))
31
+ return true;
32
+ try {
33
+ const packageJson = JSON.parse(await readFile(join(context.root, "package.json"), "utf8"));
34
+ const dependencies = {
35
+ ...packageJson.dependencies,
36
+ ...packageJson.devDependencies,
37
+ };
38
+ return (Object.keys(dependencies).some((name) => name.startsWith("@lynx-js/") || name === "vue-lynx") ||
39
+ Object.values(packageJson.scripts ?? {}).some((script) => script.includes("rspeedy")));
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ export async function initializeProject(context) {
46
+ const file = join(context.root, "lynxship.json");
47
+ if (await exists(file))
48
+ return file;
49
+ await mkdir(join(context.root, ".lynxship"), { recursive: true });
50
+ await writeFile(file, `${JSON.stringify({
51
+ ...DEFAULT_CONFIG,
52
+ projectId: context.flag("--project-id") ?? randomUUID(),
53
+ }, null, 2)}\n`);
54
+ return file;
55
+ }
56
+ export async function initializeBuildProject(context) {
57
+ if (await exists(join(context.root, "lynxship.json")))
58
+ return;
59
+ assert(await looksLikeLynxProject(context), "CLI_PROJECT_REQUIRED", "No LynxJS project was detected. Run this command from the project directory or provide `--project-dir`.");
60
+ context.ui.info("No lynxship.json found. Running lynxship init automatically…");
61
+ await initializeProject(context);
62
+ context.ui.success("Created lynxship.json");
63
+ }
64
+ export async function ensureNativeHostForBuild(context, platform, profile, config) {
65
+ if (platform === "android") {
66
+ assert(isSupportedAndroidPlatform(), "ANDROID_PLATFORM_UNSUPPORTED", "Android builds are supported on Windows, macOS, and Linux.");
67
+ if (await hasAndroidHost(context.root))
68
+ return;
69
+ assert(!(await exists(join(context.root, "android"))), "ANDROID_HOST_EXISTS", "An android/ directory exists but does not contain a usable Gradle host. LynxShip will not overwrite it; repair it or remove it deliberately, then rerun the build.");
70
+ const appConfig = await loadAppConfig(context.root);
71
+ const configuredApplicationId = appConfig?.config.platform?.android?.packageName;
72
+ const suggestedId = suggestedAndroidApplicationId(context.root);
73
+ const applicationId = context.flag("--application-id") ??
74
+ configuredApplicationId ??
75
+ (context.ui.interactive
76
+ ? await context.prompt("Android application ID", suggestedId)
77
+ : "");
78
+ assert(applicationId, "ANDROID_HOST_REQUIRED", `No Android Gradle host exists. Run \`lynxship android host init --application-id ${suggestedId}\` or pass --application-id <id> to build in non-interactive mode.`);
79
+ context.ui.info("No Android host found. Creating the official LynxShip host before the build…");
80
+ const result = await initializeAndroidHost(context.root, {
81
+ applicationId,
82
+ appName: appConfig?.config.appName ?? basename(context.root),
83
+ });
84
+ context.ui.success(`Android host created: ${result.directory}`);
85
+ return;
86
+ }
87
+ if (platform === "web") {
88
+ const resolvedProfile = resolveProfile(config, profile);
89
+ assert(hasWebConfiguration(context.root) || Boolean(resolvedProfile.web?.script), "WEB_CONFIGURATION_REQUIRED", "No Lynx Web configuration was detected. Add environments.web to lynx.config.* or configure build.<profile>.web.script.");
90
+ return;
91
+ }
92
+ if (platform === "harmony") {
93
+ assert(hasHarmonyHost(context.root), "HARMONY_HOST_REQUIRED", "No complete HarmonyOS host was found. Add an official Lynx Harmony host under harmony/ before building.");
94
+ return;
95
+ }
96
+ if (platform === "desktop") {
97
+ const resolvedProfile = resolveProfile(config, profile);
98
+ assert(await hasDesktopHost(context.root, resolvedProfile), "DESKTOP_HOST_REQUIRED", "No Lynxtron desktop host was found. Use the official Lynxtron template or configure a pack script before building.");
99
+ return;
100
+ }
101
+ assert(process.platform === "darwin", "IOS_MACOS_REQUIRED", "iOS hosts and IPA builds require macOS with Xcode. Run this build on macOS or a macOS CI worker.");
102
+ const resolvedProfile = resolveProfile(config, profile);
103
+ if (hasIosHost(context.root, resolvedProfile))
104
+ return;
105
+ assert(!(await exists(join(context.root, "ios"))), "IOS_HOST_EXISTS", "An ios/ directory exists but does not contain a usable Xcode host. LynxShip will not overwrite it; repair it deliberately, then rerun the build.");
106
+ const suggestedId = suggestedIosBundleIdentifier(context.root);
107
+ const appConfig = await loadAppConfig(context.root);
108
+ const configuredBundleIdentifier = appConfig?.config.platform?.ios?.bundleIdentifier;
109
+ const bundleIdentifier = context.flag("--bundle-identifier") ??
110
+ configuredBundleIdentifier ??
111
+ (context.ui.interactive
112
+ ? await context.prompt("iOS bundle identifier", suggestedId)
113
+ : "");
114
+ assert(bundleIdentifier, "IOS_HOST_REQUIRED", `No iOS host exists. Run \`lynxship ios host init --bundle-identifier ${suggestedId}\` or pass --bundle-identifier <id> to build in non-interactive mode.`);
115
+ context.ui.info("No iOS host found. Creating the official LynxShip host before the build…");
116
+ const result = await initializeIosHost(context.root, {
117
+ bundleIdentifier,
118
+ appName: appConfig?.config.appName ?? basename(context.root),
119
+ appIcon: context.flag("--icon") ?? appConfig?.config.appIcon ?? undefined,
120
+ });
121
+ context.ui.success(`iOS host created: ${result.directory}`);
122
+ }
@@ -0,0 +1,35 @@
1
+ import type { BuildJob, Platform } from "@lynxship/contracts";
2
+ import type { BuildSourceReference } from "@lynxship/contracts";
3
+ import type { LynxShipConfig } from "../config.js";
4
+ import { type RemoteCliState } from "../remote.js";
5
+ import { type CliState } from "../runtime/state.js";
6
+ import type { LoadedCliState } from "../runtime/state.js";
7
+ import type { BoxRow } from "../ui/components.js";
8
+ export interface RemoteBuildOptions {
9
+ root: string;
10
+ config: LynxShipConfig;
11
+ state: CliState & RemoteCliState;
12
+ loaded: LoadedCliState;
13
+ platform: Platform;
14
+ profile: string;
15
+ wait: boolean;
16
+ source?: BuildSourceReference;
17
+ printValue: (value: unknown, view?: {
18
+ title: string;
19
+ rows: BoxRow[];
20
+ done: string;
21
+ }) => void;
22
+ ui: {
23
+ info(message: string): void;
24
+ progress(label: string): {
25
+ update(value?: number, label?: string): void;
26
+ event(message: string): void;
27
+ stop(): void;
28
+ };
29
+ };
30
+ }
31
+ export declare function executeRemoteBuild(options: RemoteBuildOptions): Promise<BuildJob>;
32
+ export declare function prepareRemoteSource(root: string, config: LynxShipConfig, state: RemoteCliState, progress?: {
33
+ update(value?: number, label?: string): void;
34
+ }): Promise<BuildSourceReference>;
35
+ //# sourceMappingURL=remote-build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-build.d.ts","sourceRoot":"","sources":["../../src/commands/remote-build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAIlD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,QAAQ,GAAG,cAAc,CAAC;IACjC,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,UAAU,EAAE,CACV,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KACnD,IAAI,CAAC;IACV,EAAE,EAAE;QACF,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG;YACvB,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YAC7C,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;YAC7B,IAAI,IAAI,IAAI,CAAC;SACd,CAAC;KACH,CAAC;CACH;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,QAAQ,CAAC,CAkDnB;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,cAAc,EACrB,QAAQ,CAAC,EAAE;IAAE,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC1D,OAAO,CAAC,oBAAoB,CAAC,CAS/B"}
@@ -0,0 +1,73 @@
1
+ import { createSourceSnapshot } from "@lynxship/build-orchestrator";
2
+ import { createRemoteBuild, uploadBuildSource, waitForRemoteBuild, } from "../remote.js";
3
+ import { saveState } from "../runtime/state.js";
4
+ const maxRemoteSourceBytes = 72 * 1024 * 1024;
5
+ export async function executeRemoteBuild(options) {
6
+ const progress = options.ui.progress("Remote LynxShip build");
7
+ try {
8
+ const source = options.source ??
9
+ (await prepareRemoteSource(options.root, options.config, options.state, progress));
10
+ progress.update(undefined, "Queueing the remote build…");
11
+ const created = await createRemoteBuild(options.config, options.state, {
12
+ platform: options.platform,
13
+ profile: options.profile,
14
+ source,
15
+ });
16
+ rememberRemoteJob(options.loaded, created);
17
+ await saveState(options.state, options.loaded.repository, options.loaded.builds, options.loaded.submissions);
18
+ if (!options.wait) {
19
+ progress.update(100, "Remote build queued");
20
+ printRemoteBuild(options, created, source);
21
+ return created;
22
+ }
23
+ progress.update(undefined, `Waiting for remote build ${created.id}…`);
24
+ const result = await waitForRemoteBuild(options.config, created.id, {
25
+ pollMs: 2_000,
26
+ });
27
+ rememberRemoteJob(options.loaded, result);
28
+ await saveState(options.state, options.loaded.repository, options.loaded.builds, options.loaded.submissions);
29
+ progress.update(100, `Remote build ${result.state}`);
30
+ printRemoteBuild(options, result, source);
31
+ if (result.state === "failed" || result.state === "timed_out")
32
+ process.exitCode = 5;
33
+ return result;
34
+ }
35
+ finally {
36
+ progress.stop();
37
+ }
38
+ }
39
+ export async function prepareRemoteSource(root, config, state, progress) {
40
+ progress?.update(undefined, "Creating a reproducible source snapshot…");
41
+ const snapshot = await createSourceSnapshot(root);
42
+ if (snapshot.bytes.length > maxRemoteSourceBytes)
43
+ throw new Error(`Remote source snapshot is ${(snapshot.bytes.length / 1024 / 1024).toFixed(1)} MiB; the current JSON upload limit is ${maxRemoteSourceBytes / 1024 / 1024} MiB. Remove generated or unnecessary files and retry.`);
44
+ progress?.update(undefined, "Uploading the verified source snapshot…");
45
+ return uploadBuildSource(config, state, snapshot.bytes);
46
+ }
47
+ function rememberRemoteJob(loaded, job) {
48
+ loaded.builds.restore([
49
+ ...loaded.builds.list().filter((candidate) => candidate.id !== job.id),
50
+ job,
51
+ ]);
52
+ }
53
+ function printRemoteBuild(options, job, source) {
54
+ options.ui.info(`Remote build ${job.id}: ${job.state} · source ${source.hash.slice(0, 12)}… (${source.fileCount} files)`);
55
+ options.printValue({ ...job, source }, {
56
+ title: "Remote build result",
57
+ rows: [
58
+ { label: "Build ID", value: job.id, valueColor: "purple" },
59
+ { label: "Platform", value: job.platform, valueColor: "blue" },
60
+ { label: "Profile", value: job.profile, valueColor: "text" },
61
+ {
62
+ label: "Status",
63
+ value: job.state,
64
+ valueColor: job.state === "success" ? "green" : "yellow",
65
+ },
66
+ ],
67
+ done: job.state === "success"
68
+ ? "Remote build complete. Run lynxship submit --latest to publish it."
69
+ : job.state === "created" || job.state === "queued"
70
+ ? "Remote build queued. Run lynxship build status <id> to check it."
71
+ : "Remote build did not complete successfully. Review the worker logs and retry it.",
72
+ });
73
+ }
@@ -0,0 +1,27 @@
1
+ import { type Platform } from "@lynxship/contracts";
2
+ import { SubmissionService } from "@lynxship/submit";
3
+ import { type LynxShipConfig } from "../config.js";
4
+ import { type CliState } from "../runtime/state.js";
5
+ import type { BuildOrchestrator } from "@lynxship/build-orchestrator";
6
+ import type { JsonRepository } from "@lynxship/db";
7
+ import type { BoxRow, CliUi } from "../ui/index.js";
8
+ export interface SubmitCommandContext {
9
+ root: string;
10
+ args: string[];
11
+ ui: CliUi;
12
+ flag: (name: string, fallback?: string | null) => string | null;
13
+ printValue: (value: unknown, view?: {
14
+ title: string;
15
+ rows: BoxRow[];
16
+ done: string;
17
+ }) => void;
18
+ mobilePlatformValue: (value: string) => "android" | "ios";
19
+ requireOperationalConfiguration: (platform: Platform) => Promise<void>;
20
+ configuredProjectId: (config: LynxShipConfig) => string;
21
+ state: CliState;
22
+ repository: JsonRepository<CliState>;
23
+ builds: BuildOrchestrator;
24
+ submissions: SubmissionService;
25
+ }
26
+ export declare function runSubmit(context: SubmitCommandContext): Promise<void>;
27
+ //# sourceMappingURL=submit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/commands/submit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAGL,iBAAiB,EAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEpD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC;IAChE,UAAU,EAAE,CACV,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,KACnD,IAAI,CAAC;IACV,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,SAAS,GAAG,KAAK,CAAC;IAC1D,+BAA+B,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,mBAAmB,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,MAAM,CAAC;IACxD,KAAK,EAAE,QAAQ,CAAC;IAChB,UAAU,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,WAAW,EAAE,iBAAiB,CAAC;CAChC;AAED,wBAAsB,SAAS,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsH5E"}
@@ -0,0 +1,92 @@
1
+ import { assert } from "@lynxship/contracts";
2
+ import { AppStoreConnectApiProvider, GooglePlayApiProvider, } from "@lynxship/submit";
3
+ import { loadCredentials } from "../secure-store.js";
4
+ import { loadConfig } from "../config.js";
5
+ import { submitRealArtifact } from "../remote.js";
6
+ import { saveState } from "../runtime/state.js";
7
+ export async function runSubmit(context) {
8
+ const { root, args, ui, flag, printValue, requireOperationalConfiguration, configuredProjectId, mobilePlatformValue, state, repository, builds, submissions, } = context;
9
+ const config = await loadConfig(root);
10
+ const platform = mobilePlatformValue(flag("--platform", "android"));
11
+ await requireOperationalConfiguration(platform);
12
+ const credentials = await loadCredentials(root);
13
+ const localMode = args.includes("--local") || process.env.LYNXSHIP_SUBMIT_MODE === "mock";
14
+ const storeConfigured = platform === "android"
15
+ ? Boolean(credentials.googlePlay)
16
+ : Boolean(credentials.appStoreConnect);
17
+ assert(localMode || storeConfigured, "STORE_SUBMISSION_REQUIRED", platform === "android"
18
+ ? "Google Play is not configured. Run store configure --platform android."
19
+ : "App Store Connect is not configured. Run store configure --platform ios.");
20
+ const candidate = builds
21
+ .list()
22
+ .filter((job) => job.platform === platform && job.state === "success")
23
+ .at(-1);
24
+ assert(candidate, "BUILD_REQUIRED", "A successful build is required");
25
+ assert(localMode || candidate.artifact?.path, "STORE_ARTIFACT_REQUIRED", "A local signed artifact path is required for store submission");
26
+ const latest = args.includes("--latest");
27
+ const spinner = ui.spinner("Submitting artifact…");
28
+ try {
29
+ const controlPlaneSubmission = candidate.artifact?.path
30
+ ? await submitRealArtifact(config, state, candidate, latest)
31
+ : await submissions.submit({
32
+ projectId: configuredProjectId(config),
33
+ organizationId: "local_org",
34
+ platform,
35
+ artifact: candidate.artifact ?? { hash: `local-${candidate.id}` },
36
+ latest,
37
+ buildId: latest ? null : candidate.id,
38
+ });
39
+ const storeResult = !localMode && candidate.artifact?.path
40
+ ? platform === "android"
41
+ ? await new GooglePlayApiProvider(credentials.googlePlay).submit({
42
+ platform,
43
+ path: candidate.artifact.path,
44
+ hash: candidate.artifact.hash,
45
+ })
46
+ : await new AppStoreConnectApiProvider(credentials.appStoreConnect).submit({
47
+ platform,
48
+ path: candidate.artifact.path,
49
+ hash: candidate.artifact.hash,
50
+ })
51
+ : undefined;
52
+ const submission = storeResult
53
+ ? {
54
+ ...controlPlaneSubmission,
55
+ store: storeResult,
56
+ }
57
+ : controlPlaneSubmission;
58
+ const result = submission;
59
+ spinner.succeed(storeResult
60
+ ? "Artifact submitted to the configured app store"
61
+ : "Local submission job accepted");
62
+ await saveState(state, repository, builds, submissions);
63
+ printValue(submission, {
64
+ title: "Submission result",
65
+ rows: [
66
+ {
67
+ label: "Submission ID",
68
+ value: result.id ?? "remote",
69
+ valueColor: "purple",
70
+ },
71
+ {
72
+ label: "Platform",
73
+ value: result.platform ?? platform,
74
+ valueColor: "blue",
75
+ },
76
+ {
77
+ label: "Status",
78
+ value: result.status ?? "accepted",
79
+ valueColor: "green",
80
+ },
81
+ ],
82
+ done: "App submitted to the configured provider.",
83
+ });
84
+ if (result.downloadUrl)
85
+ ui.downloadArtifact(result.downloadUrl, result.downloadExpiresAt);
86
+ }
87
+ catch (error) {
88
+ spinner.fail(error instanceof Error ? error.message : "Submission failed");
89
+ throw error;
90
+ }
91
+ return;
92
+ }
@@ -0,0 +1,9 @@
1
+ export interface EcosystemPackage {
2
+ readonly name: string;
3
+ readonly category: "tool" | "runtime" | "adapter";
4
+ readonly purpose: string;
5
+ readonly installed: boolean;
6
+ readonly version?: string;
7
+ }
8
+ export declare function inspectEcosystem(root: string): Promise<readonly EcosystemPackage[]>;
9
+ //# sourceMappingURL=ecosystem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ecosystem.d.ts","sourceRoot":"","sources":["../src/ecosystem.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AA0FD,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,SAAS,gBAAgB,EAAE,CAAC,CAYtC"}
@@ -0,0 +1,95 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ const CATALOG = [
4
+ [
5
+ "@lynxship/lynx-library-tools",
6
+ "tool",
7
+ "Validate Lynx library manifests and plan official Autolink codegen.",
8
+ ],
9
+ [
10
+ "@lynxship/asset-pipeline",
11
+ "tool",
12
+ "Discover, hash, and verify build assets.",
13
+ ],
14
+ [
15
+ "@lynxship/test-kit",
16
+ "tool",
17
+ "Plan declared tests without pretending to emulate native hosts.",
18
+ ],
19
+ [
20
+ "@lynxship/permissions",
21
+ "runtime",
22
+ "Request permissions through an explicit native host adapter.",
23
+ ],
24
+ [
25
+ "@lynxship/router",
26
+ "runtime",
27
+ "Resolve routes, history, and deep-link paths.",
28
+ ],
29
+ [
30
+ "@lynxship/framework",
31
+ "runtime",
32
+ "Coordinate host lifecycle, bundle mounting, capabilities, and first-screen readiness.",
33
+ ],
34
+ [
35
+ "@lynxship/navigation",
36
+ "runtime",
37
+ "Validate navigation targets and delegate transitions to an injected host adapter.",
38
+ ],
39
+ [
40
+ "@lynxship/bridge",
41
+ "runtime",
42
+ "Expose allow-listed, bounded JavaScript-to-native calls through an injected transport.",
43
+ ],
44
+ [
45
+ "@lynxship/performance",
46
+ "runtime",
47
+ "Collect bounded Lynx performance entries and export them through an explicit sink.",
48
+ ],
49
+ [
50
+ "@lynxship/device-storage",
51
+ "runtime",
52
+ "Use an async device-storage adapter with typed JSON values.",
53
+ ],
54
+ [
55
+ "@lynxship/i18n",
56
+ "runtime",
57
+ "Resolve locales and translations without global state.",
58
+ ],
59
+ [
60
+ "@lynxship/media",
61
+ "runtime",
62
+ "Expose declared camera, microphone, and picker capabilities.",
63
+ ],
64
+ [
65
+ "@lynxship/observability",
66
+ "runtime",
67
+ "Buffer bounded, redacted events into an explicit sink.",
68
+ ],
69
+ [
70
+ "@lynxship/lynxtron",
71
+ "adapter",
72
+ "Verify Desktop/Lynxtron artifacts before host loading.",
73
+ ],
74
+ [
75
+ "@lynxship/tailwind-lynx",
76
+ "tool",
77
+ "Validate and plan the official Tailwind ReactLynx preset.",
78
+ ],
79
+ [
80
+ "@lynxship/ui-tokens",
81
+ "tool",
82
+ "Validate and emit deterministic design-token CSS.",
83
+ ],
84
+ ];
85
+ export async function inspectEcosystem(root) {
86
+ const manifest = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
87
+ const installed = { ...manifest.dependencies, ...manifest.devDependencies };
88
+ return CATALOG.map(([name, category, purpose]) => ({
89
+ name,
90
+ category,
91
+ purpose,
92
+ installed: Boolean(installed[name]),
93
+ ...(installed[name] ? { version: installed[name] } : {}),
94
+ }));
95
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"frameworks.d.ts","sourceRoot":"","sources":["../src/frameworks.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,KAAK,GACL,QAAQ,GACR,MAAM,GACN,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,aAAa,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;IAChD,YAAY,EAAE,OAAO,CAAC;CACvB;AAiCD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,kBAAkB,CAAC,CA+F7B"}
1
+ {"version":3,"file":"frameworks.d.ts","sourceRoot":"","sources":["../src/frameworks.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,KAAK,GACL,QAAQ,GACR,MAAM,GACN,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,aAAa,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;IAChD,YAAY,EAAE,OAAO,CAAC;CACvB;AAiCD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,kBAAkB,CAAC,CAmG7B"}
@@ -30,6 +30,10 @@ export async function detectLynxFramework(root) {
30
30
  "lynx.config.js",
31
31
  "lynx.config.mjs",
32
32
  "lynx.config.cjs",
33
+ "app.config.ts",
34
+ "app.config.js",
35
+ "app.config.mjs",
36
+ "app.config.cjs",
33
37
  "octane.config.ts",
34
38
  "octane.config.js",
35
39
  ];
@@ -85,7 +89,7 @@ export async function detectLynxFramework(root) {
85
89
  };
86
90
  }
87
91
  if (names.has("@lynx-js/rspeedy") ||
88
- /rspeedy|environments\\s*:/i.test(config + scripts)) {
92
+ /rspeedy|lynxConfig\s*:|environments\s*:/i.test(config + scripts)) {
89
93
  return {
90
94
  framework: "vanilla",
91
95
  label: "Vanilla Lynx",
@@ -0,0 +1,3 @@
1
+ import type { CliGuidance } from "./types.js";
2
+ export declare const guidance: Record<string, CliGuidance>;
3
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/guidance/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAqfhD,CAAC"}