@lynxship/cli 0.1.20 → 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 (191) 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/package.json +7 -4
  188. package/templates/android-host/app/build.gradle +1 -0
  189. package/templates/android-host/app/src/main/java/template/MainActivity.java +98 -3
  190. package/templates/ios-host/__IOS_TARGET_NAME__/DemoLynxProvider.swift +26 -16
  191. package/templates/ios-host/__IOS_TARGET_NAME__/ViewController.swift +107 -19
package/dist/plugins.js CHANGED
@@ -1,595 +1,2 @@
1
- import { createRequire } from "node:module";
2
- import { existsSync, readFileSync } from "node:fs";
3
- import { mkdir, readFile, rm, writeFile, } from "node:fs/promises";
4
- import { dirname, isAbsolute, join, relative, resolve } from "node:path";
5
- import { pathToFileURL } from "node:url";
6
- import { LYNXSHIP_PLUGIN_API_VERSION, } from "@lynxship/plugin-api";
7
- function pluginReference(reference) {
8
- if (typeof reference === "string")
9
- return { name: reference, options: {} };
10
- return { name: reference[0], options: reference[1] };
11
- }
12
- function packageDirectory(entry) {
13
- let current = dirname(entry);
14
- while (true) {
15
- if (existsSync(join(current, "package.json")))
16
- return current;
17
- const parent = dirname(current);
18
- if (parent === current)
19
- return dirname(entry);
20
- current = parent;
21
- }
22
- }
23
- function parsePackageJson(file) {
24
- try {
25
- return JSON.parse(readFileSync(file, "utf8"));
26
- }
27
- catch {
28
- return {};
29
- }
30
- }
31
- function packageJsonFromEntry(entry) {
32
- return join(packageDirectory(entry), "package.json");
33
- }
34
- function findInstalledPackageJson(root, name) {
35
- let current = root;
36
- while (true) {
37
- const candidate = join(current, "node_modules", ...name.split("/"), "package.json");
38
- if (existsSync(candidate))
39
- return candidate;
40
- const parent = dirname(current);
41
- if (parent === current)
42
- return undefined;
43
- current = parent;
44
- }
45
- }
46
- function capabilities(value) {
47
- if (!Array.isArray(value))
48
- return [];
49
- return value.filter((candidate) => ["config", "build", "native", "autolink", "template", "cloud"].includes(candidate));
50
- }
51
- const KNOWN_CAPABILITIES = [
52
- "config",
53
- "build",
54
- "native",
55
- "autolink",
56
- "template",
57
- "cloud",
58
- ];
59
- const KNOWN_PERMISSIONS = [
60
- "config:write",
61
- "build:metadata",
62
- "native:write",
63
- "autolink:metadata",
64
- "template:register",
65
- "cloud:provider",
66
- ];
67
- function isKnownList(value, allowed) {
68
- return (Array.isArray(value) &&
69
- value.every((candidate) => typeof candidate === "string" && allowed.includes(candidate)));
70
- }
71
- function permissions(value) {
72
- if (!Array.isArray(value))
73
- return [];
74
- return value.filter((candidate) => [
75
- "config:write",
76
- "build:metadata",
77
- "native:write",
78
- "autolink:metadata",
79
- "template:register",
80
- "cloud:provider",
81
- ].includes(candidate));
82
- }
83
- function validPluginDefinition(value) {
84
- if (!value || typeof value !== "object")
85
- return false;
86
- const definition = value;
87
- return (definition.apiVersion === LYNXSHIP_PLUGIN_API_VERSION &&
88
- typeof definition.name === "string" &&
89
- definition.name.length > 0 &&
90
- isKnownList(definition.capabilities, KNOWN_CAPABILITIES) &&
91
- isKnownList(definition.permissions, KNOWN_PERMISSIONS) &&
92
- (definition.platforms === undefined ||
93
- isKnownList(definition.platforms, [
94
- "all",
95
- "android",
96
- "ios",
97
- "harmonyos",
98
- "web",
99
- "desktop",
100
- ])) &&
101
- typeof definition.apply === "function");
102
- }
103
- function resolvePackageEntry(root, name) {
104
- try {
105
- const requireFromProject = createRequire(join(root, "package.json"));
106
- let entry;
107
- let packagePath;
108
- try {
109
- entry = requireFromProject.resolve(name);
110
- packagePath = packageJsonFromEntry(entry);
111
- }
112
- catch {
113
- packagePath = findInstalledPackageJson(root, name) ?? "";
114
- if (!packagePath)
115
- throw new Error("Cannot find module '" + name + "'");
116
- entry = packagePath;
117
- }
118
- const packageJson = parsePackageJson(packagePath);
119
- const plugin = packageJson.lynxship?.plugin;
120
- if (typeof plugin !== "string" || !plugin)
121
- return {
122
- packagePath,
123
- reason: `${name} does not declare package.json#lynxship.plugin`,
124
- };
125
- const packageRoot = dirname(packagePath);
126
- const resolved = resolve(packageRoot, plugin);
127
- const outside = relative(packageRoot, resolved).startsWith("..");
128
- if (outside)
129
- return {
130
- packagePath,
131
- reason: `${name} points its plugin entry outside the package`,
132
- };
133
- if (!existsSync(resolved))
134
- return {
135
- packagePath,
136
- reason: `${name} plugin entry does not exist: ${plugin}`,
137
- };
138
- return { packagePath, entry: resolved };
139
- }
140
- catch (error) {
141
- return {
142
- reason: error instanceof Error
143
- ? `Cannot resolve ${name}: ${error.message}`
144
- : `Cannot resolve ${name}`,
145
- };
146
- }
147
- }
148
- async function resolvePlugin(root, reference, load = true) {
149
- const requested = pluginReference(reference);
150
- const resolved = resolvePackageEntry(root, requested.name);
151
- if (!resolved.packagePath || !resolved.entry) {
152
- return {
153
- info: {
154
- name: requested.name,
155
- capabilities: [],
156
- permissions: [],
157
- status: "missing",
158
- reason: resolved.reason ?? "Plugin package was not found",
159
- },
160
- };
161
- }
162
- const packageJson = parsePackageJson(resolved.packagePath);
163
- const metadata = packageJson.lynxship;
164
- const apiVersion = typeof metadata?.apiVersion === "number" ? metadata.apiVersion : undefined;
165
- const packageCapabilities = capabilities(metadata?.capabilities);
166
- const packagePermissions = permissions(metadata?.permissions);
167
- if (!isKnownList(metadata?.capabilities, KNOWN_CAPABILITIES) ||
168
- !isKnownList(metadata?.permissions, KNOWN_PERMISSIONS)) {
169
- return {
170
- info: {
171
- name: requested.name,
172
- version: typeof packageJson.version === "string"
173
- ? packageJson.version
174
- : undefined,
175
- packagePath: resolved.packagePath,
176
- entry: resolved.entry,
177
- apiVersion,
178
- capabilities: packageCapabilities,
179
- permissions: packagePermissions,
180
- status: "invalid",
181
- reason: "Plugin package capabilities and permissions must be arrays of known values",
182
- },
183
- };
184
- }
185
- if (apiVersion !== LYNXSHIP_PLUGIN_API_VERSION) {
186
- return {
187
- info: {
188
- name: requested.name,
189
- version: typeof packageJson.version === "string"
190
- ? packageJson.version
191
- : undefined,
192
- packagePath: resolved.packagePath,
193
- entry: resolved.entry,
194
- apiVersion,
195
- capabilities: packageCapabilities,
196
- permissions: packagePermissions,
197
- status: "invalid",
198
- reason: `Plugin API ${String(apiVersion ?? "missing")} is not supported; expected ${LYNXSHIP_PLUGIN_API_VERSION}`,
199
- },
200
- };
201
- }
202
- const info = {
203
- name: requested.name,
204
- version: typeof packageJson.version === "string" ? packageJson.version : undefined,
205
- packagePath: resolved.packagePath,
206
- entry: resolved.entry,
207
- apiVersion,
208
- capabilities: packageCapabilities,
209
- permissions: packagePermissions,
210
- status: "ready",
211
- reason: "Plugin manifest is valid",
212
- };
213
- if (!load)
214
- return { info };
215
- try {
216
- const module = (await import(pathToFileURL(resolved.entry).href));
217
- const definition = module.default ?? module.plugin;
218
- if (!validPluginDefinition(definition)) {
219
- return {
220
- info: {
221
- ...info,
222
- status: "invalid",
223
- reason: "Plugin entry must export a LynxShipPluginDefinition",
224
- },
225
- };
226
- }
227
- if (capabilities(definition.capabilities).join(",") !==
228
- packageCapabilities.join(",") ||
229
- permissions(definition.permissions).join(",") !==
230
- packagePermissions.join(",")) {
231
- return {
232
- info: {
233
- ...info,
234
- status: "invalid",
235
- reason: "Plugin code capabilities/permissions do not match package.json",
236
- },
237
- };
238
- }
239
- if (definition.name !== requested.name &&
240
- definition.name !== packageJson.name) {
241
- return {
242
- info: {
243
- ...info,
244
- status: "invalid",
245
- reason: `Plugin entry name '${definition.name}' does not match its package`,
246
- },
247
- };
248
- }
249
- return { info, definition };
250
- }
251
- catch (error) {
252
- return {
253
- info: {
254
- ...info,
255
- status: "invalid",
256
- reason: error instanceof Error
257
- ? `Plugin entry failed to load: ${error.message}`
258
- : "Plugin entry failed to load",
259
- },
260
- };
261
- }
262
- }
263
- function pluginReferences(config) {
264
- const value = config.plugins;
265
- if (!Array.isArray(value))
266
- return [];
267
- return value;
268
- }
269
- export async function inspectProjectPlugins(root, config) {
270
- const references = pluginReferences(config);
271
- const plugins = await Promise.all(references.map(async (reference) => (await resolvePlugin(root, reference, false)).info));
272
- return { configured: references.length, plugins };
273
- }
274
- function appliesToPlatform(platforms, platform) {
275
- return (!platforms ||
276
- platforms.length === 0 ||
277
- platforms.includes("all") ||
278
- platforms.includes(platform));
279
- }
280
- function mergeJson(left, right) {
281
- const result = { ...left };
282
- for (const [key, value] of Object.entries(right)) {
283
- const current = result[key];
284
- if (current &&
285
- typeof current === "object" &&
286
- !Array.isArray(current) &&
287
- value &&
288
- typeof value === "object" &&
289
- !Array.isArray(value)) {
290
- result[key] = mergeJson(current, value);
291
- }
292
- else {
293
- result[key] = value;
294
- }
295
- }
296
- return result;
297
- }
298
- function safeProjectFile(root, file) {
299
- if (isAbsolute(file))
300
- throw new Error(`Plugin native file must be relative: ${file}`);
301
- const target = resolve(root, file);
302
- const projectRelative = relative(root, target);
303
- if (!projectRelative ||
304
- projectRelative.startsWith("..") ||
305
- isAbsolute(projectRelative))
306
- throw new Error(`Plugin native file escapes the project: ${file}`);
307
- return target;
308
- }
309
- function permissionForContribution(contribution) {
310
- const required = [];
311
- if (contribution.config)
312
- required.push("config:write");
313
- if (contribution.build)
314
- required.push("build:metadata");
315
- if (contribution.native?.length)
316
- required.push("native:write");
317
- if (contribution.autolink)
318
- required.push("autolink:metadata");
319
- if (contribution.templates?.length)
320
- required.push("template:register");
321
- if (contribution.cloud?.length)
322
- required.push("cloud:provider");
323
- return required;
324
- }
325
- function capabilityForPermission(permission) {
326
- return permission.split(":")[0];
327
- }
328
- function isJsonObject(value) {
329
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
330
- }
331
- function assertPluginContribution(plugin, contribution) {
332
- if (!isJsonObject(contribution))
333
- throw new Error(`Plugin '${plugin.name}' returned an invalid contribution object`);
334
- if (contribution.config !== undefined && !isJsonObject(contribution.config))
335
- throw new Error(`Plugin '${plugin.name}' returned an invalid config contribution`);
336
- if (contribution.native !== undefined && !Array.isArray(contribution.native))
337
- throw new Error(`Plugin '${plugin.name}' returned an invalid native contribution`);
338
- for (const operation of contribution.native ?? []) {
339
- if (!isJsonObject(operation))
340
- throw new Error(`Plugin '${plugin.name}' returned an invalid native operation`);
341
- if (!["all", "android", "ios", "harmonyos", "web", "desktop"].includes(String(operation.platform)) ||
342
- typeof operation.file !== "string" ||
343
- operation.file.length === 0 ||
344
- !["ensure-text", "append-text", "replace-text", "json-merge"].includes(String(operation.operation)))
345
- throw new Error(`Plugin '${plugin.name}' returned an invalid native operation`);
346
- if ((operation.operation === "ensure-text" ||
347
- operation.operation === "append-text") &&
348
- typeof operation.text !== "string")
349
- throw new Error(`Plugin '${plugin.name}' returned an invalid text operation`);
350
- if (operation.operation === "replace-text" &&
351
- (typeof operation.from !== "string" || typeof operation.to !== "string"))
352
- throw new Error(`Plugin '${plugin.name}' returned an invalid replacement operation`);
353
- if (operation.operation === "json-merge" && !isJsonObject(operation.value))
354
- throw new Error(`Plugin '${plugin.name}' returned an invalid JSON merge operation`);
355
- }
356
- if (contribution.autolink !== undefined) {
357
- if (!isJsonObject(contribution.autolink))
358
- throw new Error(`Plugin '${plugin.name}' returned an invalid Autolink contribution`);
359
- for (const key of ["packageNames", "capabilities"]) {
360
- const value = contribution.autolink[key];
361
- if (value !== undefined &&
362
- (!Array.isArray(value) ||
363
- !value.every((item) => typeof item === "string")))
364
- throw new Error(`Plugin '${plugin.name}' returned invalid Autolink metadata`);
365
- }
366
- }
367
- if (contribution.build !== undefined) {
368
- if (!isJsonObject(contribution.build))
369
- throw new Error(`Plugin '${plugin.name}' returned an invalid build contribution`);
370
- for (const key of [
371
- "requiredTools",
372
- "artifactExtensions",
373
- "notes",
374
- ]) {
375
- const value = contribution.build[key];
376
- if (value !== undefined &&
377
- (!Array.isArray(value) ||
378
- !value.every((item) => typeof item === "string")))
379
- throw new Error(`Plugin '${plugin.name}' returned invalid build metadata`);
380
- }
381
- }
382
- for (const template of Array.isArray(contribution.templates)
383
- ? contribution.templates
384
- : []) {
385
- if (!isJsonObject(template) ||
386
- typeof template.id !== "string" ||
387
- typeof template.displayName !== "string" ||
388
- typeof template.source !== "string")
389
- throw new Error(`Plugin '${plugin.name}' returned an invalid template contribution`);
390
- }
391
- for (const integration of Array.isArray(contribution.cloud)
392
- ? contribution.cloud
393
- : []) {
394
- if (!isJsonObject(integration) ||
395
- typeof integration.id !== "string" ||
396
- typeof integration.displayName !== "string" ||
397
- !Array.isArray(integration.capabilities) ||
398
- !integration.capabilities.every((item) => ["build", "artifacts", "updates", "submit"].includes(String(item))))
399
- throw new Error(`Plugin '${plugin.name}' returned an invalid cloud contribution`);
400
- }
401
- }
402
- function assertPluginPermissions(plugin, contribution) {
403
- const missing = permissionForContribution(contribution).filter((permission) => !plugin.permissions.includes(permission));
404
- const missingCapabilities = permissionForContribution(contribution)
405
- .map(capabilityForPermission)
406
- .filter((capability) => !plugin.capabilities.includes(capability));
407
- if (missing.length)
408
- throw new Error(`Plugin '${plugin.name}' returned contributions without declaring permission(s): ${missing.join(", ")}`);
409
- if (missingCapabilities.length)
410
- throw new Error(`Plugin '${plugin.name}' returned contributions without declaring capability(ies): ${[...new Set(missingCapabilities)].join(", ")}`);
411
- }
412
- async function mergeJsonFile(file, value) {
413
- const current = JSON.parse(await readFile(file, "utf8"));
414
- await writeFile(file, `${JSON.stringify(mergeJson(current, value), null, 2)}\n`);
415
- }
416
- async function inspectNativeOperation(root, owned, platform) {
417
- const operation = owned.operation;
418
- if (!appliesToPlatform([operation.platform], platform))
419
- return undefined;
420
- const file = safeProjectFile(root, operation.file);
421
- const current = existsSync(file) ? await readFile(file, "utf8") : "";
422
- let changed = false;
423
- if (operation.operation === "json-merge") {
424
- if (!existsSync(file))
425
- throw new Error(`Plugin JSON target does not exist: ${operation.file}`);
426
- const merged = `${JSON.stringify(mergeJson(JSON.parse(current), operation.value), null, 2)}\n`;
427
- changed = merged !== current;
428
- }
429
- else if (operation.operation === "ensure-text") {
430
- changed = !current.includes(operation.text);
431
- }
432
- else if (operation.operation === "append-text") {
433
- changed = !current.includes(operation.text);
434
- }
435
- else if (operation.operation === "replace-text") {
436
- if (!current.includes(operation.from))
437
- throw new Error(`Plugin replacement target was not found in ${operation.file}`);
438
- changed = current.replace(operation.from, operation.to) !== current;
439
- }
440
- return {
441
- plugin: owned.plugin,
442
- platform,
443
- file: operation.file,
444
- operation: operation.operation,
445
- changed,
446
- };
447
- }
448
- async function applyNativeOperation(root, operation, platform) {
449
- if (!appliesToPlatform([operation.platform], platform))
450
- return;
451
- const file = safeProjectFile(root, operation.file);
452
- await mkdir(dirname(file), { recursive: true });
453
- if (operation.operation === "json-merge") {
454
- if (!existsSync(file))
455
- throw new Error(`Plugin JSON target does not exist: ${operation.file}`);
456
- await mergeJsonFile(file, operation.value);
457
- return;
458
- }
459
- const current = existsSync(file) ? await readFile(file, "utf8") : "";
460
- if (operation.operation === "ensure-text") {
461
- if (!current.includes(operation.text))
462
- await writeFile(file, `${current}${current && !current.endsWith("\n") ? "\n" : ""}${operation.text}\n`);
463
- return;
464
- }
465
- if (operation.operation === "append-text") {
466
- if (current.includes(operation.text))
467
- return;
468
- await writeFile(file, `${current}${current && !current.endsWith("\n") ? "\n" : ""}${operation.text}\n`);
469
- return;
470
- }
471
- if (operation.operation !== "replace-text")
472
- return;
473
- if (!current.includes(operation.from))
474
- throw new Error(`Plugin replacement target was not found in ${operation.file}`);
475
- await writeFile(file, current.replace(operation.from, operation.to));
476
- }
477
- function assertNativeConflicts(root, operations) {
478
- const seen = new Map();
479
- for (const owned of operations) {
480
- const file = safeProjectFile(root, owned.operation.file);
481
- const previous = seen.get(file);
482
- if (!previous) {
483
- seen.set(file, owned);
484
- continue;
485
- }
486
- const currentOperation = owned.operation;
487
- const previousOperation = previous.operation;
488
- if (currentOperation.operation === "replace-text" &&
489
- previousOperation.operation === "replace-text" &&
490
- currentOperation.from === previousOperation.from)
491
- throw new Error(`Conflicting or duplicate LynxShip plugins '${previous.plugin}' and '${owned.plugin}' both replace '${currentOperation.from}' in ${currentOperation.file}`);
492
- }
493
- }
494
- async function applyNativeOperationsAtomically(root, operations, platform) {
495
- assertNativeConflicts(root, operations);
496
- const backups = new Map();
497
- for (const owned of operations) {
498
- if (!appliesToPlatform([owned.operation.platform], platform))
499
- continue;
500
- const file = safeProjectFile(root, owned.operation.file);
501
- if (!backups.has(file))
502
- backups.set(file, existsSync(file) ? await readFile(file, "utf8") : undefined);
503
- }
504
- try {
505
- const changes = (await Promise.all(operations.map((operation) => inspectNativeOperation(root, operation, platform)))).filter((change) => Boolean(change));
506
- for (const owned of operations)
507
- await applyNativeOperation(root, owned.operation, platform);
508
- return changes;
509
- }
510
- catch (error) {
511
- for (const [file, content] of backups) {
512
- if (content === undefined)
513
- await rm(file, { force: true });
514
- else {
515
- await mkdir(dirname(file), { recursive: true });
516
- await writeFile(file, content);
517
- }
518
- }
519
- throw new Error(`${error instanceof Error ? error.message : String(error)}; native plugin changes were rolled back`);
520
- }
521
- }
522
- export async function applyProjectPlugins(root, config, target) {
523
- const references = pluginReferences(config);
524
- const resolved = [];
525
- for (const reference of references)
526
- resolved.push(await resolvePlugin(root, reference));
527
- const report = {
528
- configured: references.length,
529
- plugins: resolved.map((plugin) => plugin.info),
530
- };
531
- const invalid = report.plugins.find((plugin) => plugin.status !== "ready");
532
- if (invalid)
533
- throw new Error(`LynxShip plugin '${invalid.name}' is invalid: ${invalid.reason}`);
534
- let effectiveConfig = JSON.parse(JSON.stringify(config));
535
- const applied = [];
536
- const templates = [];
537
- const cloud = [];
538
- const build = [];
539
- const autolink = [];
540
- const operations = [];
541
- for (let index = 0; index < resolved.length; index += 1) {
542
- const plugin = resolved[index];
543
- const reference = references[index];
544
- if (!plugin?.definition || !reference)
545
- continue;
546
- if (!appliesToPlatform(plugin.definition.platforms, target.platform))
547
- continue;
548
- const options = pluginReference(reference).options;
549
- const context = {
550
- rootDir: root,
551
- platform: target.platform,
552
- profile: target.profile,
553
- mode: target.mode ?? "apply",
554
- projectId: config.projectId,
555
- config: effectiveConfig,
556
- options,
557
- };
558
- const contribution = await plugin.definition.apply(context);
559
- if (!contribution) {
560
- applied.push(plugin.info.name);
561
- continue;
562
- }
563
- assertPluginContribution(plugin.definition, contribution);
564
- assertPluginPermissions(plugin.definition, contribution);
565
- if (contribution.config)
566
- effectiveConfig = mergeJson(effectiveConfig, contribution.config);
567
- for (const operation of contribution.native ?? [])
568
- operations.push({ plugin: plugin.info.name, operation });
569
- if (contribution.autolink)
570
- autolink.push(contribution.autolink);
571
- templates.push(...(contribution.templates ?? []));
572
- cloud.push(...(contribution.cloud ?? []));
573
- if (contribution.build)
574
- build.push(contribution.build);
575
- applied.push(plugin.info.name);
576
- }
577
- let changes;
578
- if (target.mode === "plan") {
579
- assertNativeConflicts(root, operations);
580
- changes = (await Promise.all(operations.map((operation) => inspectNativeOperation(root, operation, target.platform)))).filter((change) => Boolean(change));
581
- }
582
- else {
583
- changes = await applyNativeOperationsAtomically(root, operations, target.platform);
584
- }
585
- return {
586
- config: effectiveConfig,
587
- report,
588
- applied,
589
- templates,
590
- cloud,
591
- build,
592
- autolink,
593
- changes,
594
- };
595
- }
1
+ export { inspectProjectPlugins } from "./plugins/discovery.js";
2
+ export { applyProjectPlugins } from "./plugins/operations.js";
@@ -18,6 +18,10 @@ export declare function packageManagerScriptCommand(root: string, script: string
18
18
  command: string;
19
19
  args: string[];
20
20
  };
21
+ export declare function packageManagerInstallCommand(root: string, packages: readonly string[]): {
22
+ command: string;
23
+ args: string[];
24
+ };
21
25
  export declare function runProcess(command: string, args: string[], options: ProcessOptions): Promise<void>;
22
26
  /**
23
27
  * Run a small probe without printing it as a build event. Non-zero exit codes
@@ -1 +1 @@
1
- {"version":3,"file":"process-runner.d.ts","sourceRoot":"","sources":["../src/process-runner.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAcA;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,MAAM,EAAO,GAClB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAGrC;AAsBD,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CA4Df;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,KAAK,CAAC,GAC3C,OAAO,CAAC,qBAAqB,CAAC,CAkChC;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,GACnC,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CA4BtD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUtD"}
1
+ {"version":3,"file":"process-runner.d.ts","sourceRoot":"","sources":["../src/process-runner.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAcA;AAED,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,MAAM,EAAO,GAClB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAGrC;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAcrC;AAsBD,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CA4Df;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,KAAK,CAAC,GAC3C,OAAO,CAAC,qBAAqB,CAAC,CAkChC;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,GACnC,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CA4BtD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUtD"}
@@ -18,6 +18,20 @@ export function packageManagerScriptCommand(root, script, args = []) {
18
18
  const manager = packageManagerCommand(root);
19
19
  return { command: manager.command, args: ["run", script, ...args] };
20
20
  }
21
+ export function packageManagerInstallCommand(root, packages) {
22
+ const manager = packageManagerCommand(root);
23
+ const normalized = manager.command
24
+ .split(/[\\/]/)
25
+ .at(-1)
26
+ ?.toLowerCase()
27
+ .replace(/\.(?:cmd|bat|exe)$/i, "");
28
+ const subcommand = normalized === "yarn" || normalized === "pnpm" ? "add" : "install";
29
+ const exactFlag = normalized === "yarn" ? "--exact" : "--save-exact";
30
+ return {
31
+ command: manager.command,
32
+ args: [subcommand, exactFlag, ...packages],
33
+ };
34
+ }
21
35
  function detectPackageManager(root) {
22
36
  try {
23
37
  const packageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
package/dist/remote.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { BuildJob, Platform } from "@lynxship/contracts";
1
+ import type { BuildJob, BuildSourceReference, Platform } from "@lynxship/contracts";
2
2
  import type { LynxShipConfig } from "./config.js";
3
3
  export interface RemoteCliState {
4
4
  remoteOrganizationId?: string;
@@ -27,10 +27,31 @@ export interface OtaRollbackRequest {
27
27
  releaseId: string;
28
28
  reason: string;
29
29
  }
30
+ export declare class RemoteApiError extends Error {
31
+ readonly status: number;
32
+ readonly code?: string | undefined;
33
+ constructor(status: number, message: string, code?: string | undefined);
34
+ }
35
+ export interface RemoteBuildInput {
36
+ platform: Platform;
37
+ profile: string;
38
+ source: BuildSourceReference;
39
+ idempotencyKey?: string;
40
+ }
30
41
  export declare function ensureRemoteTarget(config: LynxShipConfig, state: RemoteCliState): Promise<{
31
42
  organizationId: string;
32
43
  projectId: string;
33
44
  }>;
45
+ export declare function uploadBuildSource(config: LynxShipConfig, state: RemoteCliState, bytes: Buffer): Promise<BuildSourceReference>;
46
+ export declare function createRemoteBuild(config: LynxShipConfig, state: RemoteCliState, input: RemoteBuildInput): Promise<BuildJob>;
47
+ export declare function getRemoteBuild(config: LynxShipConfig, id: string): Promise<BuildJob>;
48
+ export declare function listRemoteBuilds(config: LynxShipConfig, state: RemoteCliState): Promise<BuildJob[]>;
49
+ export declare function cancelRemoteBuild(config: LynxShipConfig, id: string): Promise<BuildJob>;
50
+ export declare function retryRemoteBuild(config: LynxShipConfig, id: string): Promise<BuildJob>;
51
+ export declare function waitForRemoteBuild(config: LynxShipConfig, id: string, options?: {
52
+ timeoutMs?: number;
53
+ pollMs?: number;
54
+ }): Promise<BuildJob>;
34
55
  export declare function submitRealArtifact(config: LynxShipConfig, state: RemoteCliState, job: BuildJob, latest: boolean): Promise<unknown>;
35
56
  export declare function publishOtaRelease(config: LynxShipConfig, state: RemoteCliState, input: OtaPublishRequest): Promise<unknown>;
36
57
  export declare function rollbackOtaRelease(config: LynxShipConfig, state: RemoteCliState, input: OtaRollbackRequest): Promise<unknown>;