vxrn 2.15.0 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  import { detectPackageManager } from "@vxrn/utils";
2
+ import { existsSync, lstatSync, readFileSync, readdirSync, renameSync, rmSync } from "node:fs";
2
3
  import { readFile, writeFile } from "node:fs/promises";
3
4
  import path from "node:path";
4
5
  import { fillOptions } from "../config/getOptionsFilled.mjs";
@@ -29,6 +30,14 @@ const prebuild = async ({ root, platform, "no-install": noInstall = false, app,
29
30
  } catch (error) {
30
31
  throw new Error("package.json checks are failing:\n" + error);
31
32
  }
33
+ const ios = path.join(root, "ios");
34
+ const previousIos = `${ios}.previous`;
35
+ rmSync(previousIos, {
36
+ recursive: true,
37
+ force: true
38
+ });
39
+ const reusesIos = (platform == "ios" || !platform) && existsSync(ios);
40
+ if (reusesIos) renameSync(ios, previousIos);
32
41
  if (platform == "ios" || !platform) {
33
42
  await generateForPlatform(root, "ios", app);
34
43
  }
@@ -36,6 +45,7 @@ const prebuild = async ({ root, platform, "no-install": noInstall = false, app,
36
45
  await generateForPlatform(root, "android", app);
37
46
  }
38
47
  await beforeInstall?.();
48
+ if (reusesIos) reuseUnchangedIosProject(previousIos, ios);
39
49
  const inventory = await getNativeDependencyInventory(root);
40
50
  console.info(`[vxrn] native dependencies discovered through community autolinking: ${inventory.map((entry) => entry.name).join(", ") || "(none)"}`);
41
51
  if (platform == "android" || !platform) {
@@ -78,6 +88,33 @@ Android:
78
88
  `);
79
89
  }
80
90
  };
91
+ function reuseUnchangedIosProject(previous, next) {
92
+ for (const entry of readdirSync(next, {
93
+ recursive: true,
94
+ withFileTypes: true
95
+ })) {
96
+ if (!entry.isFile()) continue;
97
+ const file = path.join(entry.parentPath, entry.name);
98
+ const old = path.join(previous, path.relative(next, file));
99
+ if (!existsSync(old) || !lstatSync(old).isFile()) continue;
100
+ if (lstatSync(old).size !== lstatSync(file).size) continue;
101
+ if (!readFileSync(old).equals(readFileSync(file))) continue;
102
+ renameSync(old, file);
103
+ }
104
+ for (const name of [
105
+ "Pods",
106
+ "Podfile.lock",
107
+ "build"
108
+ ]) {
109
+ const from = path.join(previous, name);
110
+ const to = path.join(next, name);
111
+ if (existsSync(from) && !existsSync(to)) renameSync(from, to);
112
+ }
113
+ rmSync(previous, {
114
+ recursive: true,
115
+ force: true
116
+ });
117
+ }
81
118
  async function replaceInUTF8File(filePath, findThis, replaceWith) {
82
119
  const fileContent = await readFile(filePath, "utf8");
83
120
  const replacedFileContent = fileContent.replace(findThis, replaceWith);
@@ -1 +1 @@
1
- {"version":3,"file":"prebuild.js","names":[],"sources":["exports/prebuild.js"],"sourcesContent":["import { detectPackageManager } from \"@vxrn/utils\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fillOptions } from \"../config/getOptionsFilled\";\nimport { applyBuiltInPatches } from \"../utils/patches\";\nimport {\n applyAndroidDependencyPatches,\n generateForPlatform,\n getNativeDependencyInventory,\n installNativeDependencies,\n validatePrebuildApp\n} from \"./prebuildWithoutExpo\";\nconst prebuild = async ({\n root,\n platform,\n \"no-install\": noInstall = false,\n app,\n beforeInstall\n}) => {\n validatePrebuildApp(app, platform);\n const options = await fillOptions({ root });\n await applyBuiltInPatches(options);\n try {\n const packageJsonPath = path.join(root, \"package.json\");\n const packageJsonContents = await readFile(packageJsonPath, \"utf8\");\n const { devDependencies } = JSON.parse(packageJsonContents);\n if (!devDependencies?.[\"@react-native-community/template\"]) {\n const installCommand = await (async () => {\n const found = await detectPackageManager();\n switch (true) {\n case found.bun:\n return `bun add -D @react-native-community/template`;\n case found.pnpm:\n return `pnpm install -D @react-native-community/template`;\n case found.yarn:\n return `yarn add -D @react-native-community/template`;\n default:\n return `npm install -D @react-native-community/template`;\n }\n })();\n throw new Error(\n `\"@react-native-community/template\" is not found in package.json, please install \"@react-native-community/template\" as dev dependency:\n\\`${installCommand}\\``\n );\n }\n } catch (error) {\n throw new Error(\"package.json checks are failing:\\n\" + error);\n }\n if (platform == \"ios\" || !platform) {\n await generateForPlatform(root, \"ios\", app);\n }\n if (platform == \"android\" || !platform) {\n await generateForPlatform(root, \"android\", app);\n }\n await beforeInstall?.();\n const inventory = await getNativeDependencyInventory(root);\n console.info(\n `[vxrn] native dependencies discovered through community autolinking: ${inventory.map((entry) => entry.name).join(\", \") || \"(none)\"}`\n );\n if (platform == \"android\" || !platform) {\n applyAndroidDependencyPatches({ root, app, inventory });\n }\n if (!noInstall) {\n installNativeDependencies({ root, platform });\n } else if (!platform || platform === \"ios\") {\n console.info(`Run cd ios && pod install`);\n console.info(\n \"Then run `open *.xcworkspace` in your terminal to open the prebuilt iOS project, then you can either run it via Xcode or archive it for distribution.\"\n );\n }\n if (!platform || platform === \"ios\") {\n console.info(\n `\niOS:\n\n Run \\`open ios/*.xcworkspace\\` in your terminal to open the prebuilt iOS project.\n Then you can either run it via Xcode or archive it for distribution.\n\n See https://onestack.dev/docs/guides-ios-native for more information.\n\n---\n`\n );\n }\n if (!platform || platform === \"android\") {\n console.info(\n `\nAndroid:\n\n \\`cd android\\` and run \\`./gradlew generateCodegenArtifactsFromSchema\\`, then \\`./gradlew assembleRelease\\` or \\`./gradlew assembleDebug\\` to build the Android project.\n\n Afterwards, you can find the built APK at \\`android/app/build/outputs/apk/release/app-release.apk\\` or\n \\`android/app/build/outputs/apk/debug/app-debug.apk\\`.\n\n`\n );\n }\n};\nasync function replaceInUTF8File(filePath, findThis, replaceWith) {\n const fileContent = await readFile(filePath, \"utf8\");\n const replacedFileContent = fileContent.replace(findThis, replaceWith);\n if (replacedFileContent !== fileContent) {\n await writeFile(filePath, replacedFileContent, \"utf8\");\n }\n}\nexport {\n prebuild,\n replaceInUTF8File\n};\n//# sourceMappingURL=prebuild.js.map\n"],"mappings":";;;;;;;;AAYA,MAAM,WAAW,OAAO,EACtB,MACA,UACA,cAAc,YAAY,OAC1B,KACA,oBACI;CACJ,oBAAoB,KAAK,QAAQ;CACjC,MAAM,UAAU,MAAM,YAAY,EAAE,KAAK,CAAC;CAC1C,MAAM,oBAAoB,OAAO;CACjC,IAAI;EACF,MAAM,kBAAkB,KAAK,KAAK,MAAM,cAAc;EACtD,MAAM,sBAAsB,MAAM,SAAS,iBAAiB,MAAM;EAClE,MAAM,EAAE,oBAAoB,KAAK,MAAM,mBAAmB;EAC1D,IAAI,CAAC,kBAAkB,qCAAqC;GAC1D,MAAM,iBAAiB,OAAO,YAAY;IACxC,MAAM,QAAQ,MAAM,qBAAqB;IACzC,QAAQ,MAAR;KACE,KAAK,MAAM,KACT,OAAO;KACT,KAAK,MAAM,MACT,OAAO;KACT,KAAK,MAAM,MACT,OAAO;KACT,SACE,OAAO;IACX;GACF,EAAC,CAAE;GACH,MAAM,IAAI,MACR;IACJ,eAAe,GACb;EACF;CACF,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,uCAAuC,KAAK;CAC9D;CACA,IAAI,YAAY,SAAS,CAAC,UAAU;EAClC,MAAM,oBAAoB,MAAM,OAAO,GAAG;CAC5C;CACA,IAAI,YAAY,aAAa,CAAC,UAAU;EACtC,MAAM,oBAAoB,MAAM,WAAW,GAAG;CAChD;CACA,MAAM,gBAAgB;CACtB,MAAM,YAAY,MAAM,6BAA6B,IAAI;CACzD,QAAQ,KACN,wEAAwE,UAAU,KAAK,UAAU,MAAM,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,UAC7H;CACA,IAAI,YAAY,aAAa,CAAC,UAAU;EACtC,8BAA8B;GAAE;GAAM;GAAK;EAAU,CAAC;CACxD;CACA,IAAI,CAAC,WAAW;EACd,0BAA0B;GAAE;GAAM;EAAS,CAAC;CAC9C,OAAO,IAAI,CAAC,YAAY,aAAa,OAAO;EAC1C,QAAQ,KAAK,2BAA2B;EACxC,QAAQ,KACN,uJACF;CACF;CACA,IAAI,CAAC,YAAY,aAAa,OAAO;EACnC,QAAQ,KACN;;;;;;;;;CAUF;CACF;CACA,IAAI,CAAC,YAAY,aAAa,WAAW;EACvC,QAAQ,KACN;;;;;;;;CASF;CACF;AACF;AACA,eAAe,kBAAkB,UAAU,UAAU,aAAa;CAChE,MAAM,cAAc,MAAM,SAAS,UAAU,MAAM;CACnD,MAAM,sBAAsB,YAAY,QAAQ,UAAU,WAAW;CACrE,IAAI,wBAAwB,aAAa;EACvC,MAAM,UAAU,UAAU,qBAAqB,MAAM;CACvD;AACF"}
1
+ {"version":3,"file":"prebuild.js","names":[],"sources":["exports/prebuild.js"],"sourcesContent":["import { detectPackageManager } from \"@vxrn/utils\";\nimport { existsSync, lstatSync, readdirSync, readFileSync, renameSync, rmSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fillOptions } from \"../config/getOptionsFilled\";\nimport { applyBuiltInPatches } from \"../utils/patches\";\nimport {\n applyAndroidDependencyPatches,\n generateForPlatform,\n getNativeDependencyInventory,\n installNativeDependencies,\n validatePrebuildApp\n} from \"./prebuildWithoutExpo\";\nconst prebuild = async ({\n root,\n platform,\n \"no-install\": noInstall = false,\n app,\n beforeInstall\n}) => {\n validatePrebuildApp(app, platform);\n const options = await fillOptions({ root });\n await applyBuiltInPatches(options);\n try {\n const packageJsonPath = path.join(root, \"package.json\");\n const packageJsonContents = await readFile(packageJsonPath, \"utf8\");\n const { devDependencies } = JSON.parse(packageJsonContents);\n if (!devDependencies?.[\"@react-native-community/template\"]) {\n const installCommand = await (async () => {\n const found = await detectPackageManager();\n switch (true) {\n case found.bun:\n return `bun add -D @react-native-community/template`;\n case found.pnpm:\n return `pnpm install -D @react-native-community/template`;\n case found.yarn:\n return `yarn add -D @react-native-community/template`;\n default:\n return `npm install -D @react-native-community/template`;\n }\n })();\n throw new Error(\n `\"@react-native-community/template\" is not found in package.json, please install \"@react-native-community/template\" as dev dependency:\n\\`${installCommand}\\``\n );\n }\n } catch (error) {\n throw new Error(\"package.json checks are failing:\\n\" + error);\n }\n const ios = path.join(root, \"ios\");\n const previousIos = `${ios}.previous`;\n rmSync(previousIos, { recursive: true, force: true });\n const reusesIos = (platform == \"ios\" || !platform) && existsSync(ios);\n if (reusesIos) renameSync(ios, previousIos);\n if (platform == \"ios\" || !platform) {\n await generateForPlatform(root, \"ios\", app);\n }\n if (platform == \"android\" || !platform) {\n await generateForPlatform(root, \"android\", app);\n }\n await beforeInstall?.();\n if (reusesIos) reuseUnchangedIosProject(previousIos, ios);\n const inventory = await getNativeDependencyInventory(root);\n console.info(\n `[vxrn] native dependencies discovered through community autolinking: ${inventory.map((entry) => entry.name).join(\", \") || \"(none)\"}`\n );\n if (platform == \"android\" || !platform) {\n applyAndroidDependencyPatches({ root, app, inventory });\n }\n if (!noInstall) {\n installNativeDependencies({ root, platform });\n } else if (!platform || platform === \"ios\") {\n console.info(`Run cd ios && pod install`);\n console.info(\n \"Then run `open *.xcworkspace` in your terminal to open the prebuilt iOS project, then you can either run it via Xcode or archive it for distribution.\"\n );\n }\n if (!platform || platform === \"ios\") {\n console.info(\n `\niOS:\n\n Run \\`open ios/*.xcworkspace\\` in your terminal to open the prebuilt iOS project.\n Then you can either run it via Xcode or archive it for distribution.\n\n See https://onestack.dev/docs/guides-ios-native for more information.\n\n---\n`\n );\n }\n if (!platform || platform === \"android\") {\n console.info(\n `\nAndroid:\n\n \\`cd android\\` and run \\`./gradlew generateCodegenArtifactsFromSchema\\`, then \\`./gradlew assembleRelease\\` or \\`./gradlew assembleDebug\\` to build the Android project.\n\n Afterwards, you can find the built APK at \\`android/app/build/outputs/apk/release/app-release.apk\\` or\n \\`android/app/build/outputs/apk/debug/app-debug.apk\\`.\n\n`\n );\n }\n};\nfunction reuseUnchangedIosProject(previous, next) {\n for (const entry of readdirSync(next, { recursive: true, withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const file = path.join(entry.parentPath, entry.name);\n const old = path.join(previous, path.relative(next, file));\n if (!existsSync(old) || !lstatSync(old).isFile()) continue;\n if (lstatSync(old).size !== lstatSync(file).size) continue;\n if (!readFileSync(old).equals(readFileSync(file))) continue;\n renameSync(old, file);\n }\n for (const name of [\"Pods\", \"Podfile.lock\", \"build\"]) {\n const from = path.join(previous, name);\n const to = path.join(next, name);\n if (existsSync(from) && !existsSync(to)) renameSync(from, to);\n }\n rmSync(previous, { recursive: true, force: true });\n}\nasync function replaceInUTF8File(filePath, findThis, replaceWith) {\n const fileContent = await readFile(filePath, \"utf8\");\n const replacedFileContent = fileContent.replace(findThis, replaceWith);\n if (replacedFileContent !== fileContent) {\n await writeFile(filePath, replacedFileContent, \"utf8\");\n }\n}\nexport {\n prebuild,\n replaceInUTF8File\n};\n//# sourceMappingURL=prebuild.js.map\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { detectPackageManager } from "@vxrn/utils";
2
+ import { existsSync, lstatSync, readFileSync, readdirSync, renameSync, rmSync } from "fs";
2
3
  import { readFile, writeFile } from "fs/promises";
3
4
  import path from "path";
4
5
  import { fillOptions } from "../config/getOptionsFilled.native.js";
@@ -30,6 +31,14 @@ var prebuild = async function prebuild2(param) {
30
31
  } catch (error) {
31
32
  throw new Error("package.json checks are failing:\n" + error);
32
33
  }
34
+ var ios = path.join(root, "ios");
35
+ var previousIos = `${ios}.previous`;
36
+ rmSync(previousIos, {
37
+ recursive: true,
38
+ force: true
39
+ });
40
+ var reusesIos = (platform == "ios" || !platform) && existsSync(ios);
41
+ if (reusesIos) renameSync(ios, previousIos);
33
42
  if (platform == "ios" || !platform) {
34
43
  await generateForPlatform(root, "ios", app);
35
44
  }
@@ -37,6 +46,7 @@ var prebuild = async function prebuild2(param) {
37
46
  await generateForPlatform(root, "android", app);
38
47
  }
39
48
  await (beforeInstall === null || beforeInstall === void 0 ? void 0 : beforeInstall());
49
+ if (reusesIos) reuseUnchangedIosProject(previousIos, ios);
40
50
  var inventory = await getNativeDependencyInventory(root);
41
51
  console.info(`[vxrn] native dependencies discovered through community autolinking: ${inventory.map(function(entry) {
42
52
  return entry.name;
@@ -81,6 +91,51 @@ Android:
81
91
  `);
82
92
  }
83
93
  };
94
+ function reuseUnchangedIosProject(previous, next) {
95
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
96
+ try {
97
+ for (var _iterator = readdirSync(next, {
98
+ recursive: true,
99
+ withFileTypes: true
100
+ })[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
101
+ var entry = _step.value;
102
+ if (!entry.isFile()) continue;
103
+ var file = path.join(entry.parentPath, entry.name);
104
+ var old = path.join(previous, path.relative(next, file));
105
+ if (!existsSync(old) || !lstatSync(old).isFile()) continue;
106
+ if (lstatSync(old).size !== lstatSync(file).size) continue;
107
+ if (!readFileSync(old).equals(readFileSync(file))) continue;
108
+ renameSync(old, file);
109
+ }
110
+ } catch (err) {
111
+ _didIteratorError = true;
112
+ _iteratorError = err;
113
+ } finally {
114
+ try {
115
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
116
+ _iterator.return();
117
+ }
118
+ } finally {
119
+ if (_didIteratorError) {
120
+ throw _iteratorError;
121
+ }
122
+ }
123
+ }
124
+ for (var _i = 0, _iter = [
125
+ "Pods",
126
+ "Podfile.lock",
127
+ "build"
128
+ ]; _i < _iter.length; _i++) {
129
+ var name = _iter[_i];
130
+ var from = path.join(previous, name);
131
+ var to = path.join(next, name);
132
+ if (existsSync(from) && !existsSync(to)) renameSync(from, to);
133
+ }
134
+ rmSync(previous, {
135
+ recursive: true,
136
+ force: true
137
+ });
138
+ }
84
139
  async function replaceInUTF8File(filePath, findThis, replaceWith) {
85
140
  var fileContent = await readFile(filePath, "utf8");
86
141
  var replacedFileContent = fileContent.replace(findThis, replaceWith);
@@ -1 +1 @@
1
- {"version":3,"file":"prebuild.native.js","names":[],"sources":["exports/prebuild.native.js"],"sourcesContent":["import { detectPackageManager } from \"@vxrn/utils\";\nimport { readFile, writeFile } from \"fs/promises\";\nimport path from \"path\";\nimport { fillOptions } from \"../config/getOptionsFilled\";\nimport { applyBuiltInPatches } from \"../utils/patches\";\nimport { applyAndroidDependencyPatches, generateForPlatform, getNativeDependencyInventory, installNativeDependencies, validatePrebuildApp } from \"./prebuildWithoutExpo\";\nvar prebuild = async function prebuild2(param) {\n var { root, platform, \"no-install\": noInstall = false, app, beforeInstall } = param;\n validatePrebuildApp(app, platform);\n var options = await fillOptions({\n root\n });\n await applyBuiltInPatches(options);\n try {\n var packageJsonPath = path.join(root, \"package.json\");\n var packageJsonContents = await readFile(packageJsonPath, \"utf8\");\n var { devDependencies } = JSON.parse(packageJsonContents);\n if (!(devDependencies === null || devDependencies === void 0 ? void 0 : devDependencies[\"@react-native-community/template\"])) {\n var installCommand = await (async function() {\n var found = await detectPackageManager();\n switch (true) {\n case found.bun:\n return `bun add -D @react-native-community/template`;\n case found.pnpm:\n return `pnpm install -D @react-native-community/template`;\n case found.yarn:\n return `yarn add -D @react-native-community/template`;\n default:\n return `npm install -D @react-native-community/template`;\n }\n })();\n throw new Error(`\"@react-native-community/template\" is not found in package.json, please install \"@react-native-community/template\" as dev dependency:\n\\`${installCommand}\\``);\n }\n } catch (error) {\n throw new Error(\"package.json checks are failing:\\n\" + error);\n }\n if (platform == \"ios\" || !platform) {\n await generateForPlatform(root, \"ios\", app);\n }\n if (platform == \"android\" || !platform) {\n await generateForPlatform(root, \"android\", app);\n }\n await (beforeInstall === null || beforeInstall === void 0 ? void 0 : beforeInstall());\n var inventory = await getNativeDependencyInventory(root);\n console.info(`[vxrn] native dependencies discovered through community autolinking: ${inventory.map(function(entry) {\n return entry.name;\n }).join(\", \") || \"(none)\"}`);\n if (platform == \"android\" || !platform) {\n applyAndroidDependencyPatches({\n root,\n app,\n inventory\n });\n }\n if (!noInstall) {\n installNativeDependencies({\n root,\n platform\n });\n } else if (!platform || platform === \"ios\") {\n console.info(`Run cd ios && pod install`);\n console.info(\"Then run `open *.xcworkspace` in your terminal to open the prebuilt iOS project, then you can either run it via Xcode or archive it for distribution.\");\n }\n if (!platform || platform === \"ios\") {\n console.info(`\niOS:\n\n Run \\`open ios/*.xcworkspace\\` in your terminal to open the prebuilt iOS project.\n Then you can either run it via Xcode or archive it for distribution.\n\n See https://onestack.dev/docs/guides-ios-native for more information.\n\n---\n`);\n }\n if (!platform || platform === \"android\") {\n console.info(`\nAndroid:\n\n \\`cd android\\` and run \\`./gradlew generateCodegenArtifactsFromSchema\\`, then \\`./gradlew assembleRelease\\` or \\`./gradlew assembleDebug\\` to build the Android project.\n\n Afterwards, you can find the built APK at \\`android/app/build/outputs/apk/release/app-release.apk\\` or\n \\`android/app/build/outputs/apk/debug/app-debug.apk\\`.\n\n`);\n }\n};\nasync function replaceInUTF8File(filePath, findThis, replaceWith) {\n var fileContent = await readFile(filePath, \"utf8\");\n var replacedFileContent = fileContent.replace(findThis, replaceWith);\n if (replacedFileContent !== fileContent) {\n await writeFile(filePath, replacedFileContent, \"utf8\");\n }\n}\nexport {\n prebuild,\n replaceInUTF8File\n};\n//# sourceMappingURL=prebuild.js.map\n"],"mappings":";;;;;;;;AAMA,IAAI,WAAW,eAAe,UAAU,OAAO;CAC7C,IAAI,EAAE,MAAM,UAAU,cAAc,YAAY,OAAO,KAAK,kBAAkB;CAC9E,oBAAoB,KAAK,QAAQ;CACjC,IAAI,UAAU,MAAM,YAAY,EAC9B,KACF,CAAC;CACD,MAAM,oBAAoB,OAAO;CACjC,IAAI;EACF,IAAI,kBAAkB,KAAK,KAAK,MAAM,cAAc;EACpD,IAAI,sBAAsB,MAAM,SAAS,iBAAiB,MAAM;EAChE,IAAI,EAAE,oBAAoB,KAAK,MAAM,mBAAmB;EACxD,IAAI,EAAE,oBAAoB,QAAQ,oBAAoB,KAAK,IAAI,KAAK,IAAI,gBAAgB,sCAAsC;GAC5H,IAAI,iBAAiB,OAAO,iBAAiB;IAC3C,IAAI,QAAQ,MAAM,qBAAqB;IACvC,QAAQ,MAAR;KACE,KAAK,MAAM,KACT,OAAO;KACT,KAAK,MAAM,MACT,OAAO;KACT,KAAK,MAAM,MACT,OAAO;KACT,SACE,OAAO;IACX;GACF,EAAC,CAAE;GACH,MAAM,IAAI,MAAM;IAClB,eAAe,GAAG;EAClB;CACF,SAAS,OAAO;EACd,MAAM,IAAI,MAAM,uCAAuC,KAAK;CAC9D;CACA,IAAI,YAAY,SAAS,CAAC,UAAU;EAClC,MAAM,oBAAoB,MAAM,OAAO,GAAG;CAC5C;CACA,IAAI,YAAY,aAAa,CAAC,UAAU;EACtC,MAAM,oBAAoB,MAAM,WAAW,GAAG;CAChD;CACA,OAAO,kBAAkB,QAAQ,kBAAkB,KAAK,IAAI,KAAK,IAAI,cAAc;CACnF,IAAI,YAAY,MAAM,6BAA6B,IAAI;CACvD,QAAQ,KAAK,wEAAwE,UAAU,IAAI,SAAS,OAAO;EACjH,OAAO,MAAM;CACf,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,UAAU;CAC3B,IAAI,YAAY,aAAa,CAAC,UAAU;EACtC,8BAA8B;GAC5B;GACA;GACA;EACF,CAAC;CACH;CACA,IAAI,CAAC,WAAW;EACd,0BAA0B;GACxB;GACA;EACF,CAAC;CACH,OAAO,IAAI,CAAC,YAAY,aAAa,OAAO;EAC1C,QAAQ,KAAK,2BAA2B;EACxC,QAAQ,KAAK,uJAAuJ;CACtK;CACA,IAAI,CAAC,YAAY,aAAa,OAAO;EACnC,QAAQ,KAAK;;;;;;;;;CAShB;CACC;CACA,IAAI,CAAC,YAAY,aAAa,WAAW;EACvC,QAAQ,KAAK;;;;;;;;CAQhB;CACC;AACF;AACA,eAAe,kBAAkB,UAAU,UAAU,aAAa;CAChE,IAAI,cAAc,MAAM,SAAS,UAAU,MAAM;CACjD,IAAI,sBAAsB,YAAY,QAAQ,UAAU,WAAW;CACnE,IAAI,wBAAwB,aAAa;EACvC,MAAM,UAAU,UAAU,qBAAqB,MAAM;CACvD;AACF"}
1
+ {"version":3,"file":"prebuild.native.js","names":[],"sources":["exports/prebuild.native.js"],"sourcesContent":["import { detectPackageManager } from \"@vxrn/utils\";\nimport { existsSync, lstatSync, readdirSync, readFileSync, renameSync, rmSync } from \"fs\";\nimport { readFile, writeFile } from \"fs/promises\";\nimport path from \"path\";\nimport { fillOptions } from \"../config/getOptionsFilled\";\nimport { applyBuiltInPatches } from \"../utils/patches\";\nimport { applyAndroidDependencyPatches, generateForPlatform, getNativeDependencyInventory, installNativeDependencies, validatePrebuildApp } from \"./prebuildWithoutExpo\";\nvar prebuild = async function prebuild2(param) {\n var { root, platform, \"no-install\": noInstall = false, app, beforeInstall } = param;\n validatePrebuildApp(app, platform);\n var options = await fillOptions({\n root\n });\n await applyBuiltInPatches(options);\n try {\n var packageJsonPath = path.join(root, \"package.json\");\n var packageJsonContents = await readFile(packageJsonPath, \"utf8\");\n var { devDependencies } = JSON.parse(packageJsonContents);\n if (!(devDependencies === null || devDependencies === void 0 ? void 0 : devDependencies[\"@react-native-community/template\"])) {\n var installCommand = await (async function() {\n var found = await detectPackageManager();\n switch (true) {\n case found.bun:\n return `bun add -D @react-native-community/template`;\n case found.pnpm:\n return `pnpm install -D @react-native-community/template`;\n case found.yarn:\n return `yarn add -D @react-native-community/template`;\n default:\n return `npm install -D @react-native-community/template`;\n }\n })();\n throw new Error(`\"@react-native-community/template\" is not found in package.json, please install \"@react-native-community/template\" as dev dependency:\n\\`${installCommand}\\``);\n }\n } catch (error) {\n throw new Error(\"package.json checks are failing:\\n\" + error);\n }\n var ios = path.join(root, \"ios\");\n var previousIos = `${ios}.previous`;\n rmSync(previousIos, {\n recursive: true,\n force: true\n });\n var reusesIos = (platform == \"ios\" || !platform) && existsSync(ios);\n if (reusesIos) renameSync(ios, previousIos);\n if (platform == \"ios\" || !platform) {\n await generateForPlatform(root, \"ios\", app);\n }\n if (platform == \"android\" || !platform) {\n await generateForPlatform(root, \"android\", app);\n }\n await (beforeInstall === null || beforeInstall === void 0 ? void 0 : beforeInstall());\n if (reusesIos) reuseUnchangedIosProject(previousIos, ios);\n var inventory = await getNativeDependencyInventory(root);\n console.info(`[vxrn] native dependencies discovered through community autolinking: ${inventory.map(function(entry) {\n return entry.name;\n }).join(\", \") || \"(none)\"}`);\n if (platform == \"android\" || !platform) {\n applyAndroidDependencyPatches({\n root,\n app,\n inventory\n });\n }\n if (!noInstall) {\n installNativeDependencies({\n root,\n platform\n });\n } else if (!platform || platform === \"ios\") {\n console.info(`Run cd ios && pod install`);\n console.info(\"Then run `open *.xcworkspace` in your terminal to open the prebuilt iOS project, then you can either run it via Xcode or archive it for distribution.\");\n }\n if (!platform || platform === \"ios\") {\n console.info(`\niOS:\n\n Run \\`open ios/*.xcworkspace\\` in your terminal to open the prebuilt iOS project.\n Then you can either run it via Xcode or archive it for distribution.\n\n See https://onestack.dev/docs/guides-ios-native for more information.\n\n---\n`);\n }\n if (!platform || platform === \"android\") {\n console.info(`\nAndroid:\n\n \\`cd android\\` and run \\`./gradlew generateCodegenArtifactsFromSchema\\`, then \\`./gradlew assembleRelease\\` or \\`./gradlew assembleDebug\\` to build the Android project.\n\n Afterwards, you can find the built APK at \\`android/app/build/outputs/apk/release/app-release.apk\\` or\n \\`android/app/build/outputs/apk/debug/app-debug.apk\\`.\n\n`);\n }\n};\nfunction reuseUnchangedIosProject(previous, next) {\n var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;\n try {\n for (var _iterator = readdirSync(next, {\n recursive: true,\n withFileTypes: true\n })[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {\n var entry = _step.value;\n if (!entry.isFile()) continue;\n var file = path.join(entry.parentPath, entry.name);\n var old = path.join(previous, path.relative(next, file));\n if (!existsSync(old) || !lstatSync(old).isFile()) continue;\n if (lstatSync(old).size !== lstatSync(file).size) continue;\n if (!readFileSync(old).equals(readFileSync(file))) continue;\n renameSync(old, file);\n }\n } catch (err) {\n _didIteratorError = true;\n _iteratorError = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion && _iterator.return != null) {\n _iterator.return();\n }\n } finally {\n if (_didIteratorError) {\n throw _iteratorError;\n }\n }\n }\n for (var _i = 0, _iter = [\n \"Pods\",\n \"Podfile.lock\",\n \"build\"\n ]; _i < _iter.length; _i++) {\n var name = _iter[_i];\n var from = path.join(previous, name);\n var to = path.join(next, name);\n if (existsSync(from) && !existsSync(to)) renameSync(from, to);\n }\n rmSync(previous, {\n recursive: true,\n force: true\n });\n}\nasync function replaceInUTF8File(filePath, findThis, replaceWith) {\n var fileContent = await readFile(filePath, \"utf8\");\n var replacedFileContent = fileContent.replace(findThis, replaceWith);\n if (replacedFileContent !== fileContent) {\n await writeFile(filePath, replacedFileContent, \"utf8\");\n }\n}\nexport {\n prebuild,\n replaceInUTF8File\n};\n//# sourceMappingURL=prebuild.js.map\n"],"mappings":"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"}
@@ -228,6 +228,9 @@ function swiftShortcutPhrase(value) {
228
228
  function renderIosAppIntentsSwift(actions) {
229
229
  const types = actions.map((action, index) => {
230
230
  const summaryTitle = swiftLiteral(action.title).slice(1, -1);
231
+ const description = action.description === void 0 ? "" : `
232
+ static let description = IntentDescription(${swiftLiteral(action.description)})`;
233
+ const openAppWhenRun = action.openAppWhenRun === true ? "\n static let openAppWhenRun: Bool = true" : "";
231
234
  const text = action.textParameterTitle === void 0 ? "" : `
232
235
  @Parameter(title: ${swiftLiteral(action.textParameterTitle)}) var text: String
233
236
 
@@ -236,20 +239,23 @@ function renderIosAppIntentsSwift(actions) {
236
239
  }
237
240
  `;
238
241
  return `struct OneAppIntent${index}: AppIntent {
239
- static let title: LocalizedStringResource = ${swiftLiteral(action.title)}
242
+ static let title: LocalizedStringResource = ${swiftLiteral(action.title)}${description}${openAppWhenRun}
240
243
  ${text}
241
- func perform() async throws -> some IntentResult & ReturnsValue<String> {
244
+ func perform() async throws -> some IntentResult & ReturnsValue<String> & ProvidesDialog {
242
245
  let result = try await oneAppIntentsRun(${swiftLiteral(action.id)}, ${text ? "text" : "nil"})
243
- return .result(value: result)
246
+ return .result(value: result, dialog: IntentDialog(stringLiteral: result))
244
247
  }
245
248
  }`;
246
249
  });
247
- const shortcuts = actions.map((action, index) => ` AppShortcut(
250
+ const shortcuts = actions.map((action, index) => {
251
+ const phrases = Array.from(/* @__PURE__ */ new Set([action.shortcutPhrase, ...action.shortcutPhrases ?? []])).map(swiftShortcutPhrase);
252
+ return ` AppShortcut(
248
253
  intent: OneAppIntent${index}(),
249
- phrases: [${swiftShortcutPhrase(action.shortcutPhrase)}],
254
+ phrases: [${phrases.join(", ")}],
250
255
  shortTitle: ${swiftLiteral(action.title)},
251
- systemImageName: "bolt.fill"
252
- )`).join("\n");
256
+ systemImageName: ${swiftLiteral(action.systemImageName ?? "bolt.fill")}
257
+ )`;
258
+ }).join("\n");
253
259
  return `import AppIntents
254
260
  import Foundation
255
261
 
@@ -560,6 +566,7 @@ function generateIosWidgets(dest, app) {
560
566
  <key>NSExtension</key><dict><key>NSExtensionPointIdentifier</key><string>com.apple.widgetkit-extension</string></dict>
561
567
  </dict></plist>
562
568
  `);
569
+ const supportedFamilies = (widgets.families ?? ["systemSmall", "systemMedium"]).map((family) => `.${family}`).join(", ");
563
570
  writeFileSync(path.join(appDir, "OneWidgetContract.swift"), `import Foundation
564
571
  import ActivityKit
565
572
 
@@ -567,6 +574,7 @@ enum OneWidgetContract {
567
574
  static let appGroup = ${JSON.stringify(widgets.appGroup)}
568
575
  static let kind = ${JSON.stringify(widgets.kind)}
569
576
  static let dataKey = "one.widget.data"
577
+ static let actionKeyPrefix = "one.widget.action."
570
578
 
571
579
  struct Data: Codable {
572
580
  let title: String
@@ -575,6 +583,13 @@ enum OneWidgetContract {
575
583
  let layout: String?
576
584
  }
577
585
 
586
+ struct Action: Codable {
587
+ let id: String
588
+ let action: String
589
+ let value: String?
590
+ let timestampMs: Double
591
+ }
592
+
578
593
  struct Attributes: ActivityAttributes {
579
594
  struct ContentState: Codable, Hashable {
580
595
  let status: String
@@ -588,6 +603,7 @@ enum OneWidgetContract {
588
603
  writeFileSync(path.join(extensionDir, "OneWidget.swift"), `import SwiftUI
589
604
  import WidgetKit
590
605
  import ActivityKit
606
+ import AppIntents
591
607
 
592
608
  struct OneWidgetNode: Decodable {
593
609
  let type: String
@@ -595,11 +611,36 @@ struct OneWidgetNode: Decodable {
595
611
  let style: Style?
596
612
  let children: [OneWidgetNode]?
597
613
  let systemName: String?
598
- let value: Double?
614
+ let value: Value?
599
615
  let total: Double?
600
616
  let fill: String?
601
617
  let cornerRadius: Double?
602
618
  let url: String?
619
+ let action: String?
620
+
621
+ enum Value: Decodable {
622
+ case number(Double)
623
+ case string(String)
624
+
625
+ var number: Double? {
626
+ if case .number(let value) = self { return value }
627
+ return nil
628
+ }
629
+
630
+ var string: String? {
631
+ if case .string(let value) = self { return value }
632
+ return nil
633
+ }
634
+
635
+ init(from decoder: Decoder) throws {
636
+ let container = try decoder.singleValueContainer()
637
+ if let number = try? container.decode(Double.self) {
638
+ self = .number(number)
639
+ } else {
640
+ self = .string(try container.decode(String.self))
641
+ }
642
+ }
643
+ }
603
644
 
604
645
  struct Style: Decodable {
605
646
  let color: String?
@@ -618,6 +659,43 @@ struct OneWidgetNode: Decodable {
618
659
  }
619
660
  }
620
661
 
662
+ struct OneWidgetButtonIntent: AppIntent {
663
+ static var title: LocalizedStringResource = "Widget Action"
664
+
665
+ @Parameter(title: "Action") var action: String
666
+ @Parameter(title: "Value") var value: String?
667
+
668
+ init() {}
669
+
670
+ init(action: String, value: String?) {
671
+ self.action = action
672
+ self.value = value
673
+ }
674
+
675
+ func perform() async throws -> some IntentResult {
676
+ if let defaults = UserDefaults(suiteName: OneWidgetContract.appGroup) {
677
+ let item = OneWidgetContract.Action(
678
+ id: UUID().uuidString,
679
+ action: action,
680
+ value: value,
681
+ timestampMs: Date().timeIntervalSince1970 * 1000
682
+ )
683
+ if let encoded = try? JSONEncoder().encode(item) {
684
+ defaults.set(encoded, forKey: OneWidgetContract.actionKeyPrefix + item.id)
685
+ }
686
+ CFNotificationCenterPostNotification(
687
+ CFNotificationCenterGetDarwinNotifyCenter(),
688
+ CFNotificationName("dev.onejs.widget.action" as CFString),
689
+ nil,
690
+ nil,
691
+ true
692
+ )
693
+ }
694
+ WidgetCenter.shared.reloadTimelines(ofKind: OneWidgetContract.kind)
695
+ return .result()
696
+ }
697
+ }
698
+
621
699
  struct OneActivityView: Decodable {
622
700
  let lockScreen: OneWidgetNode
623
701
  let compactLeading: OneWidgetNode?
@@ -710,10 +788,10 @@ struct OneWidgetRendered: View {
710
788
  .font(.system(size: CGFloat(node.style?.fontSize ?? 20), weight: weight))
711
789
  }
712
790
  case "progress":
713
- ProgressView(value: node.value ?? 0, total: node.total ?? 1)
791
+ ProgressView(value: node.value?.number ?? 0, total: node.total ?? 1)
714
792
  .tint(oneColor(node.style?.color))
715
793
  case "gauge":
716
- Gauge(value: node.value ?? 0, in: 0...(node.total ?? 1)) { EmptyView() }
794
+ Gauge(value: node.value?.number ?? 0, in: 0...(node.total ?? 1)) { EmptyView() }
717
795
  .gaugeStyle(.accessoryCircular)
718
796
  .tint(oneColor(node.style?.color))
719
797
  case "circle":
@@ -731,6 +809,15 @@ struct OneWidgetRendered: View {
731
809
  }
732
810
  }
733
811
  }
812
+ case "button":
813
+ if let action = node.action {
814
+ Button(intent: OneWidgetButtonIntent(action: action, value: node.value?.string)) {
815
+ ForEach(Array((node.children ?? []).enumerated()), id: \\.offset) { _, child in
816
+ OneWidgetRendered(node: child)
817
+ }
818
+ }
819
+ .buttonStyle(.plain)
820
+ }
734
821
  default: EmptyView()
735
822
  }
736
823
  }
@@ -791,7 +878,7 @@ struct OneWidget: Widget {
791
878
  }
792
879
  .configurationDisplayName(${JSON.stringify(widgets.displayName)})
793
880
  .description(${JSON.stringify(widgets.description)})
794
- .supportedFamilies([.systemSmall, .systemMedium])
881
+ .supportedFamilies([${supportedFamilies}])
795
882
  }
796
883
  }
797
884
 
@@ -885,28 +972,117 @@ RCT_EXTERN_METHOD(update:(NSString *)identifier status:(NSString *)status value:
885
972
  RCT_EXTERN_METHOD(updateView:(NSString *)identifier layout:(NSString *)layout resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
886
973
  RCT_EXTERN_METHOD(end:(NSString *)identifier resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
887
974
  RCT_EXTERN_METHOD(pushToken:(NSString *)identifier resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
975
+ RCT_EXTERN_METHOD(claimActions:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
888
976
  @end
889
977
  `);
890
978
  writeFileSync(path.join(appDir, "OneWidgetsBridge.swift"), `import Foundation
979
+ import UIKit
891
980
  import React
892
981
  import WidgetKit
893
982
  import ActivityKit
894
983
 
984
+ private func oneWidgetsDarwinCallback(
985
+ _ center: CFNotificationCenter?,
986
+ _ observer: UnsafeMutableRawPointer?,
987
+ _ name: CFNotificationName?,
988
+ _ object: UnsafeRawPointer?,
989
+ _ userInfo: CFDictionary?
990
+ ) {
991
+ guard let observer else { return }
992
+ let bridge = Unmanaged<OneWidgetsBridge>.fromOpaque(observer).takeUnretainedValue()
993
+ bridge.flushObservedActions()
994
+ }
995
+
895
996
  @objc(OneWidgetsBridge)
896
997
  class OneWidgetsBridge: RCTEventEmitter {
897
998
  private var tokenTasks: [String: Task<Void, Never>] = [:]
999
+ private var isObservingEvents = false
1000
+ private var foregroundObserver: NSObjectProtocol?
1001
+ private let actionLock = NSLock()
898
1002
 
899
- override func supportedEvents() -> [String]! { ["oneLiveActivityPushToken"] }
1003
+ override func supportedEvents() -> [String]! { ["oneLiveActivityPushToken", "oneWidgetAction"] }
900
1004
 
901
1005
  override func startObserving() {
1006
+ isObservingEvents = true
902
1007
  for activity in Activity<OneWidgetContract.Attributes>.activities {
903
1008
  observeToken(activity)
904
1009
  }
1010
+ CFNotificationCenterAddObserver(
1011
+ CFNotificationCenterGetDarwinNotifyCenter(),
1012
+ Unmanaged.passUnretained(self).toOpaque(),
1013
+ oneWidgetsDarwinCallback,
1014
+ "dev.onejs.widget.action" as CFString,
1015
+ nil,
1016
+ .deliverImmediately
1017
+ )
1018
+ foregroundObserver = NotificationCenter.default.addObserver(
1019
+ forName: UIApplication.didBecomeActiveNotification,
1020
+ object: nil,
1021
+ queue: .main
1022
+ ) { [weak self] _ in
1023
+ self?.flushObservedActions()
1024
+ }
1025
+ flushObservedActions()
905
1026
  }
906
1027
 
907
1028
  override func stopObserving() {
1029
+ isObservingEvents = false
908
1030
  for task in tokenTasks.values { task.cancel() }
909
1031
  tokenTasks.removeAll()
1032
+ CFNotificationCenterRemoveObserver(
1033
+ CFNotificationCenterGetDarwinNotifyCenter(),
1034
+ Unmanaged.passUnretained(self).toOpaque(),
1035
+ CFNotificationName("dev.onejs.widget.action" as CFString),
1036
+ nil
1037
+ )
1038
+ if let foregroundObserver {
1039
+ NotificationCenter.default.removeObserver(foregroundObserver)
1040
+ self.foregroundObserver = nil
1041
+ }
1042
+ }
1043
+
1044
+ deinit {
1045
+ CFNotificationCenterRemoveObserver(
1046
+ CFNotificationCenterGetDarwinNotifyCenter(),
1047
+ Unmanaged.passUnretained(self).toOpaque(),
1048
+ CFNotificationName("dev.onejs.widget.action" as CFString),
1049
+ nil
1050
+ )
1051
+ if let foregroundObserver {
1052
+ NotificationCenter.default.removeObserver(foregroundObserver)
1053
+ }
1054
+ }
1055
+
1056
+ fileprivate func flushObservedActions() {
1057
+ guard isObservingEvents else { return }
1058
+ for item in drainStoredActions() {
1059
+ sendEvent(withName: "oneWidgetAction", body: item)
1060
+ }
1061
+ }
1062
+
1063
+ private func drainStoredActions() -> [[String: Any]] {
1064
+ actionLock.lock()
1065
+ defer { actionLock.unlock() }
1066
+ guard let defaults = UserDefaults(suiteName: OneWidgetContract.appGroup) else {
1067
+ return []
1068
+ }
1069
+ var actions: [OneWidgetContract.Action] = []
1070
+ for key in defaults.dictionaryRepresentation().keys where key.hasPrefix(OneWidgetContract.actionKeyPrefix) {
1071
+ guard let data = defaults.data(forKey: key) else { continue }
1072
+ defaults.removeObject(forKey: key)
1073
+ if let action = try? JSONDecoder().decode(OneWidgetContract.Action.self, from: data) {
1074
+ actions.append(action)
1075
+ }
1076
+ }
1077
+ actions.sort { $0.timestampMs < $1.timestampMs }
1078
+ return actions.map { action in
1079
+ [
1080
+ "id": action.id,
1081
+ "action": action.action,
1082
+ "value": action.value ?? NSNull(),
1083
+ "timestampMs": action.timestampMs,
1084
+ ]
1085
+ }
910
1086
  }
911
1087
 
912
1088
  private func observeToken(_ activity: Activity<OneWidgetContract.Attributes>) {
@@ -1048,6 +1224,15 @@ class OneWidgetsBridge: RCTEventEmitter {
1048
1224
  resolve(NSNull())
1049
1225
  }
1050
1226
  }
1227
+
1228
+ @objc(claimActions:rejecter:)
1229
+ func claimActions(_ resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
1230
+ guard UserDefaults(suiteName: OneWidgetContract.appGroup) != nil else {
1231
+ reject("app_group", "Cannot open the configured App Group", nil)
1232
+ return
1233
+ }
1234
+ resolve(drainStoredActions())
1235
+ }
1051
1236
  }
1052
1237
  `);
1053
1238
  }