@akanjs/cli 2.3.11-rc.7 → 2.3.11-rc.9
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.
|
@@ -666,6 +666,7 @@ import {
|
|
|
666
666
|
import { readFileSync as readFileSync3 } from "fs";
|
|
667
667
|
import { copyFile, mkdir as mkdir2, readdir as readDirEntries, stat as stat2 } from "fs/promises";
|
|
668
668
|
import path7 from "path";
|
|
669
|
+
import { pathToFileURL } from "url";
|
|
669
670
|
import {
|
|
670
671
|
capitalize,
|
|
671
672
|
isRouteSourceFile,
|
|
@@ -1107,6 +1108,63 @@ var decreaseBuildNum = async (app) => {
|
|
|
1107
1108
|
const akanConfigContent = akanConfig.replace(`buildNum: ${appConfig.mobile.buildNum}`, `buildNum: ${appConfig.mobile.buildNum - 1}`);
|
|
1108
1109
|
fs.writeFileSync(akanConfigPath, akanConfigContent);
|
|
1109
1110
|
};
|
|
1111
|
+
// pkgs/@akanjs/devkit/firebaseMessagingSw.ts
|
|
1112
|
+
var FIREBASE_WEB_SDK_VERSION = "12.13.0";
|
|
1113
|
+
function normalizeFirebaseClientConfig(config) {
|
|
1114
|
+
if (!config || typeof config !== "object")
|
|
1115
|
+
return null;
|
|
1116
|
+
const value = config;
|
|
1117
|
+
if (typeof value.apiKey !== "string" || typeof value.projectId !== "string" || typeof value.messagingSenderId !== "string" || typeof value.appId !== "string") {
|
|
1118
|
+
return null;
|
|
1119
|
+
}
|
|
1120
|
+
return {
|
|
1121
|
+
apiKey: value.apiKey,
|
|
1122
|
+
...typeof value.authDomain === "string" ? { authDomain: value.authDomain } : {},
|
|
1123
|
+
projectId: value.projectId,
|
|
1124
|
+
...typeof value.storageBucket === "string" ? { storageBucket: value.storageBucket } : {},
|
|
1125
|
+
messagingSenderId: value.messagingSenderId,
|
|
1126
|
+
appId: value.appId
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
function createFirebaseMessagingServiceWorker(config) {
|
|
1130
|
+
const configJson = JSON.stringify(config);
|
|
1131
|
+
return `/* Generated by Akan.js. Do not edit. */
|
|
1132
|
+
const firebaseConfig = ${configJson};
|
|
1133
|
+
|
|
1134
|
+
if (firebaseConfig) {
|
|
1135
|
+
importScripts("https://www.gstatic.com/firebasejs/${FIREBASE_WEB_SDK_VERSION}/firebase-app-compat.js");
|
|
1136
|
+
importScripts("https://www.gstatic.com/firebasejs/${FIREBASE_WEB_SDK_VERSION}/firebase-messaging-compat.js");
|
|
1137
|
+
|
|
1138
|
+
firebase.initializeApp(firebaseConfig);
|
|
1139
|
+
const messaging = firebase.messaging();
|
|
1140
|
+
|
|
1141
|
+
const notificationUrl = (payload) =>
|
|
1142
|
+
payload?.data?.url || payload?.fcmOptions?.link || payload?.notification?.click_action;
|
|
1143
|
+
|
|
1144
|
+
messaging.onBackgroundMessage((payload) => {
|
|
1145
|
+
const title = payload?.notification?.title || "";
|
|
1146
|
+
const options = {
|
|
1147
|
+
body: payload?.notification?.body,
|
|
1148
|
+
icon: payload?.notification?.icon,
|
|
1149
|
+
image: payload?.notification?.image,
|
|
1150
|
+
data: {
|
|
1151
|
+
url: notificationUrl(payload),
|
|
1152
|
+
FCM_MSG: payload,
|
|
1153
|
+
},
|
|
1154
|
+
};
|
|
1155
|
+
self.registration.showNotification(title, options);
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
self.addEventListener("notificationclick", (event) => {
|
|
1160
|
+
const url = event.notification?.data?.url || event.notification?.data?.FCM_MSG?.data?.url;
|
|
1161
|
+
event.notification?.close();
|
|
1162
|
+
if (!url) return;
|
|
1163
|
+
event.waitUntil(clients.openWindow(url));
|
|
1164
|
+
});
|
|
1165
|
+
`;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1110
1168
|
// pkgs/@akanjs/devkit/getDirname.ts
|
|
1111
1169
|
import path2 from "path";
|
|
1112
1170
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -1392,6 +1450,7 @@ ${errorText}, ${warningText} found`];
|
|
|
1392
1450
|
|
|
1393
1451
|
// pkgs/@akanjs/devkit/scanInfo.ts
|
|
1394
1452
|
import path5 from "path";
|
|
1453
|
+
import { rm } from "fs/promises";
|
|
1395
1454
|
|
|
1396
1455
|
// pkgs/@akanjs/devkit/dependencyScanner.ts
|
|
1397
1456
|
import { builtinModules } from "module";
|
|
@@ -1713,6 +1772,7 @@ var appRootAllowedFiles = new Set([
|
|
|
1713
1772
|
"tsconfig.json",
|
|
1714
1773
|
"tsconfig.tsbuildinfo"
|
|
1715
1774
|
]);
|
|
1775
|
+
var generatedRootCapacitorConfigFiles = ["capacitor.config.js", "capacitor.config.json"];
|
|
1716
1776
|
var appRootAllowedDirs = new Set([
|
|
1717
1777
|
".akan",
|
|
1718
1778
|
"android",
|
|
@@ -1756,11 +1816,17 @@ var rootSignalTestFilePattern = /^[A-Za-z][A-Za-z0-9_-]*\.signal\.(test|spec)\.(
|
|
|
1756
1816
|
var isAllowedTestFile = (filename) => testFilePattern.test(filename);
|
|
1757
1817
|
var isAllowedLibRootFile = (filename) => libRootAllowedFiles.has(filename) || rootSignalTestFilePattern.test(filename);
|
|
1758
1818
|
var getScanPath = (exec, relativePath) => path5.posix.join(`${exec.type}s`, exec.name, relativePath.split(path5.sep).join("/"));
|
|
1819
|
+
async function clearGeneratedRootCapacitorConfigs(exec) {
|
|
1820
|
+
if (exec.type !== "app")
|
|
1821
|
+
return;
|
|
1822
|
+
await Promise.all(generatedRootCapacitorConfigFiles.map((filename) => rm(exec.getPath(filename), { force: true })));
|
|
1823
|
+
}
|
|
1759
1824
|
var getModuleNameFromPath = (kind, modulePath) => {
|
|
1760
1825
|
const dirname = path5.basename(modulePath);
|
|
1761
1826
|
return kind === "service" ? dirname.replace(/^_+/, "") : dirname;
|
|
1762
1827
|
};
|
|
1763
1828
|
async function assertScanConvention(exec, libRoot) {
|
|
1829
|
+
await clearGeneratedRootCapacitorConfigs(exec);
|
|
1764
1830
|
const violations = [];
|
|
1765
1831
|
const addViolation = (relativePath, reason) => {
|
|
1766
1832
|
violations.push(`${getScanPath(exec, relativePath)}: ${reason}`);
|
|
@@ -3689,8 +3755,30 @@ class AppExecutor extends SysExecutor {
|
|
|
3689
3755
|
});
|
|
3690
3756
|
if (write)
|
|
3691
3757
|
await this.syncAssets(scanInfo.getScanResult().libDeps);
|
|
3758
|
+
if (write)
|
|
3759
|
+
await this.#syncFirebaseMessagingSw();
|
|
3692
3760
|
return scanInfo;
|
|
3693
3761
|
}
|
|
3762
|
+
async#syncFirebaseMessagingSw() {
|
|
3763
|
+
const swRelPath = "public/firebase-messaging-sw.js";
|
|
3764
|
+
if (await FileSys.fileExists(this.getPath(swRelPath)))
|
|
3765
|
+
return;
|
|
3766
|
+
const envClientPath = path7.join(this.cwdPath, "env", "env.client.ts");
|
|
3767
|
+
if (!await FileSys.fileExists(envClientPath))
|
|
3768
|
+
return;
|
|
3769
|
+
let firebaseConfig = null;
|
|
3770
|
+
try {
|
|
3771
|
+
const envUrl = pathToFileURL(envClientPath);
|
|
3772
|
+
envUrl.searchParams.set("t", String(Date.now()));
|
|
3773
|
+
const envModule = await import(envUrl.href);
|
|
3774
|
+
firebaseConfig = normalizeFirebaseClientConfig(envModule.env?.firebase);
|
|
3775
|
+
} catch {
|
|
3776
|
+
return;
|
|
3777
|
+
}
|
|
3778
|
+
if (!firebaseConfig)
|
|
3779
|
+
return;
|
|
3780
|
+
await this.writeFile(swRelPath, createFirebaseMessagingServiceWorker(firebaseConfig), { overwrite: false });
|
|
3781
|
+
}
|
|
3694
3782
|
async increaseBuildNum() {
|
|
3695
3783
|
await increaseBuildNum(this);
|
|
3696
3784
|
}
|
|
@@ -8719,7 +8807,7 @@ Caused by: ${ApplicationBuildReporter.formatError(error.cause)}` : "";
|
|
|
8719
8807
|
}
|
|
8720
8808
|
}
|
|
8721
8809
|
// pkgs/@akanjs/devkit/applicationBuildRunner.ts
|
|
8722
|
-
import { mkdir as mkdir8, rm as
|
|
8810
|
+
import { mkdir as mkdir8, rm as rm4 } from "fs/promises";
|
|
8723
8811
|
import path37 from "path";
|
|
8724
8812
|
|
|
8725
8813
|
// pkgs/@akanjs/devkit/frontendBuild/allRoutesBuilder.ts
|
|
@@ -10477,7 +10565,7 @@ class AllRoutesBuilder {
|
|
|
10477
10565
|
}
|
|
10478
10566
|
}
|
|
10479
10567
|
// pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
|
|
10480
|
-
import { mkdir as mkdir5, rm, unlink } from "fs/promises";
|
|
10568
|
+
import { mkdir as mkdir5, rm as rm2, unlink } from "fs/promises";
|
|
10481
10569
|
import path24 from "path";
|
|
10482
10570
|
|
|
10483
10571
|
// pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
|
|
@@ -10607,7 +10695,7 @@ class CsrArtifactBuilder {
|
|
|
10607
10695
|
const artifact = await this.#loadCsrArtifact();
|
|
10608
10696
|
const csrBasePaths = [...akanConfig2.basePaths];
|
|
10609
10697
|
const htmlEntries = csrBasePaths.length > 0 ? csrBasePaths : ["index"];
|
|
10610
|
-
await
|
|
10698
|
+
await rm2(this.#outputDir, { recursive: true, force: true });
|
|
10611
10699
|
await mkdir5(path24.join(this.#app.cwdPath, ".akan/generated/csr"), { recursive: true });
|
|
10612
10700
|
const generatedHtmlFiles = Object.fromEntries(htmlEntries.map((basePath2) => this.#createHtmlFile(basePath2)));
|
|
10613
10701
|
const result = await Bun.build({
|
|
@@ -11341,7 +11429,7 @@ class DevChangePlanner {
|
|
|
11341
11429
|
}
|
|
11342
11430
|
var uniqueResolved = (files) => [...new Set(files.map((file) => path27.resolve(file)))].sort();
|
|
11343
11431
|
// pkgs/@akanjs/devkit/frontendBuild/devGeneratedIndexSync.ts
|
|
11344
|
-
import { mkdir as mkdir6, readdir as readdir2, readFile, rm as
|
|
11432
|
+
import { mkdir as mkdir6, readdir as readdir2, readFile, rm as rm3, stat as stat3, writeFile } from "fs/promises";
|
|
11345
11433
|
import path28 from "path";
|
|
11346
11434
|
var BARREL_FACETS2 = new Set(["common", "srvkit", "ui", "webkit"]);
|
|
11347
11435
|
var FACET_SOURCE_FILE_RE = /\.(ts|tsx)$/;
|
|
@@ -11424,7 +11512,7 @@ class DevGeneratedIndexSync {
|
|
|
11424
11512
|
if (content === null) {
|
|
11425
11513
|
if (!await exists(indexPath))
|
|
11426
11514
|
return false;
|
|
11427
|
-
await
|
|
11515
|
+
await rm3(indexPath, { force: true });
|
|
11428
11516
|
return true;
|
|
11429
11517
|
}
|
|
11430
11518
|
const current = await readFile(indexPath, "utf8").catch(() => null);
|
|
@@ -12571,7 +12659,7 @@ class ApplicationBuildRunner {
|
|
|
12571
12659
|
await this.#app.getPageKeys({ refresh: true });
|
|
12572
12660
|
const { typecheckDir, tsconfigPath } = await this.#writeTypecheckTsconfig({ incremental });
|
|
12573
12661
|
if (clean)
|
|
12574
|
-
await
|
|
12662
|
+
await rm4(path37.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
|
|
12575
12663
|
await this.#checkProjectInChildProcess(tsconfigPath);
|
|
12576
12664
|
}
|
|
12577
12665
|
async#runPhase(id, label, task, summarize, options = {}) {
|
|
@@ -12771,7 +12859,7 @@ void run().catch((error) => {
|
|
|
12771
12859
|
}
|
|
12772
12860
|
}
|
|
12773
12861
|
// pkgs/@akanjs/devkit/applicationReleasePackager.ts
|
|
12774
|
-
import { cp, mkdir as mkdir9, rm as
|
|
12862
|
+
import { cp, mkdir as mkdir9, rm as rm5 } from "fs/promises";
|
|
12775
12863
|
import path38 from "path";
|
|
12776
12864
|
|
|
12777
12865
|
// pkgs/@akanjs/devkit/uploadRelease.ts
|
|
@@ -12878,7 +12966,7 @@ class ApplicationReleasePackager {
|
|
|
12878
12966
|
const platformVersion = akanConfig2.mobile.version;
|
|
12879
12967
|
const buildRoot = `${this.#app.workspace.workspaceRoot}/releases/builds/${this.#app.name}`;
|
|
12880
12968
|
if (await FileSys.dirExists(buildRoot))
|
|
12881
|
-
await
|
|
12969
|
+
await rm5(buildRoot, { recursive: true, force: true });
|
|
12882
12970
|
await mkdir9(buildRoot, { recursive: true });
|
|
12883
12971
|
if (rebuild || !await FileSys.dirExists(`${this.#app.dist.cwdPath}/backend`))
|
|
12884
12972
|
await this.#build();
|
|
@@ -12887,7 +12975,7 @@ class ApplicationReleasePackager {
|
|
|
12887
12975
|
await mkdir9(buildPath, { recursive: true });
|
|
12888
12976
|
await cp(`${this.#app.dist.cwdPath}/backend`, `${buildPath}/backend`, { recursive: true });
|
|
12889
12977
|
await cp(this.#app.dist.cwdPath, buildRoot, { recursive: true });
|
|
12890
|
-
await
|
|
12978
|
+
await rm5(`${buildRoot}/frontend/.next`, { recursive: true, force: true });
|
|
12891
12979
|
const releaseRoot = this.#app.workspace.workspaceRoot;
|
|
12892
12980
|
const releaseArchivePath = path38.relative(releaseRoot, `${releaseRoot}/releases/builds/${this.#app.name}-release.tar.gz`).split(path38.sep).join("/");
|
|
12893
12981
|
await this.#app.workspace.spawn("tar", ["-zcf", releaseArchivePath, "-C", buildRoot, "./"], { cwd: releaseRoot });
|
|
@@ -12903,7 +12991,7 @@ class ApplicationReleasePackager {
|
|
|
12903
12991
|
`${this.#app.workspace.workspaceRoot}/releases/builds/${this.#app.name}-appBuild.zip`,
|
|
12904
12992
|
"./csr"
|
|
12905
12993
|
]);
|
|
12906
|
-
await
|
|
12994
|
+
await rm5("./csr", { recursive: true, force: true });
|
|
12907
12995
|
}
|
|
12908
12996
|
async#writeSourceArchive({ readme }) {
|
|
12909
12997
|
const sourceRoot = `${this.#app.workspace.workspaceRoot}/releases/sources/${this.#app.name}`;
|
|
@@ -12914,7 +13002,7 @@ class ApplicationReleasePackager {
|
|
|
12914
13002
|
await Promise.all([".next", "ios", "android", "public/libs"].map(async (path39) => {
|
|
12915
13003
|
const targetPath = `${sourceRoot}/apps/${this.#app.name}/${path39}`;
|
|
12916
13004
|
if (await FileSys.dirExists(targetPath))
|
|
12917
|
-
await
|
|
13005
|
+
await rm5(targetPath, { recursive: true, force: true });
|
|
12918
13006
|
}));
|
|
12919
13007
|
const syncPaths = [".husky", ".gitignore", "package.json"];
|
|
12920
13008
|
await Promise.all(syncPaths.map((path39) => cp(`${this.#app.workspace.cwdPath}/${path39}`, `${sourceRoot}/${path39}`, { recursive: true })));
|
|
@@ -12929,7 +13017,7 @@ class ApplicationReleasePackager {
|
|
|
12929
13017
|
const maxRetry = 3;
|
|
12930
13018
|
for (let i = 0;i < maxRetry; i++) {
|
|
12931
13019
|
try {
|
|
12932
|
-
await
|
|
13020
|
+
await rm5(sourceRoot, { recursive: true, force: true });
|
|
12933
13021
|
} catch {}
|
|
12934
13022
|
}
|
|
12935
13023
|
}
|
|
@@ -13162,7 +13250,7 @@ class Builder {
|
|
|
13162
13250
|
}
|
|
13163
13251
|
}
|
|
13164
13252
|
// pkgs/@akanjs/devkit/capacitorApp.ts
|
|
13165
|
-
import { cp as cp2, mkdir as mkdir11, readFile as readFile2, rm as
|
|
13253
|
+
import { cp as cp2, mkdir as mkdir11, readFile as readFile2, rm as rm6, writeFile as writeFile2 } from "fs/promises";
|
|
13166
13254
|
import os from "os";
|
|
13167
13255
|
import path41 from "path";
|
|
13168
13256
|
import { select as select2 } from "@inquirer/prompts";
|
|
@@ -13373,7 +13461,7 @@ var rootCapacitorConfigFilenames = [
|
|
|
13373
13461
|
];
|
|
13374
13462
|
var rootCapacitorConfigPaths = (appRoot) => rootCapacitorConfigFilenames.map((file) => path41.join(appRoot, file));
|
|
13375
13463
|
async function clearRootCapacitorConfigs(appRoot) {
|
|
13376
|
-
await Promise.all(rootCapacitorConfigPaths(appRoot).map((file) =>
|
|
13464
|
+
await Promise.all(rootCapacitorConfigPaths(appRoot).map((file) => rm6(file, { force: true })));
|
|
13377
13465
|
}
|
|
13378
13466
|
async function writeRootCapacitorConfig(appRoot, content) {
|
|
13379
13467
|
await clearRootCapacitorConfigs(appRoot);
|
|
@@ -13394,6 +13482,7 @@ var getLocalIP = () => {
|
|
|
13394
13482
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13395
13483
|
var asString = (value) => typeof value === "string" ? value : undefined;
|
|
13396
13484
|
var firstString = (...values) => values.find((value) => typeof value === "string");
|
|
13485
|
+
var resolveIosApnsEnvironment = ({ operation }) => operation === "release" ? "production" : "development";
|
|
13397
13486
|
var scoreIosDeviceTarget = (target) => {
|
|
13398
13487
|
const state = target.state?.toLowerCase() ?? "";
|
|
13399
13488
|
return (state.includes("available") ? 4 : 0) + (state.includes("wired") ? 2 : 0) + (state.includes("paired") ? 1 : 0);
|
|
@@ -13699,6 +13788,8 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
|
|
|
13699
13788
|
const experimentalConfig = isRecord2(experimental) ? experimental : undefined;
|
|
13700
13789
|
const pluginsConfig = isRecord2(plugins) ? plugins : {};
|
|
13701
13790
|
const keyboardPluginConfig = isRecord2(pluginsConfig.Keyboard) ? pluginsConfig.Keyboard : {};
|
|
13791
|
+
const pushNotificationsPluginConfig = isRecord2(pluginsConfig.PushNotifications) ? pluginsConfig.PushNotifications : {};
|
|
13792
|
+
const usesPushNotifications = target.permissions?.includes("push") ?? false;
|
|
13702
13793
|
const config = {
|
|
13703
13794
|
...capacitorConfig,
|
|
13704
13795
|
appId,
|
|
@@ -13707,6 +13798,12 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
|
|
|
13707
13798
|
plugins: {
|
|
13708
13799
|
CapacitorCookies: { enabled: true },
|
|
13709
13800
|
...pluginsConfig,
|
|
13801
|
+
...usesPushNotifications || isRecord2(pluginsConfig.PushNotifications) ? {
|
|
13802
|
+
PushNotifications: {
|
|
13803
|
+
...usesPushNotifications ? { presentationOptions: ["badge", "sound", "alert"] } : {},
|
|
13804
|
+
...pushNotificationsPluginConfig
|
|
13805
|
+
}
|
|
13806
|
+
} : {},
|
|
13710
13807
|
Keyboard: {
|
|
13711
13808
|
resize: "none",
|
|
13712
13809
|
...keyboardPluginConfig
|
|
@@ -13778,9 +13875,9 @@ class CapacitorApp {
|
|
|
13778
13875
|
await mkdir11(this.targetRoot, { recursive: true });
|
|
13779
13876
|
if (regenerate) {
|
|
13780
13877
|
if (!platform || platform === "ios")
|
|
13781
|
-
await
|
|
13878
|
+
await rm6(path41.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
|
|
13782
13879
|
if (!platform || platform === "android")
|
|
13783
|
-
await
|
|
13880
|
+
await rm6(path41.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
|
|
13784
13881
|
}
|
|
13785
13882
|
const project = this.project;
|
|
13786
13883
|
await this.project.load();
|
|
@@ -13802,7 +13899,7 @@ class CapacitorApp {
|
|
|
13802
13899
|
await this.#prepareTargetAssets();
|
|
13803
13900
|
await this.#prepareExternalFiles("ios");
|
|
13804
13901
|
await this.#applyIosMetadata();
|
|
13805
|
-
await this.#applyPermissions();
|
|
13902
|
+
await this.#applyPermissions({ operation, env });
|
|
13806
13903
|
await this.#applyDeepLinks("ios", { operation, env });
|
|
13807
13904
|
await this.project.commit();
|
|
13808
13905
|
await this.#generateAssets({ operation, env });
|
|
@@ -13945,7 +14042,7 @@ ${error.message}`;
|
|
|
13945
14042
|
await this.#prepareTargetAssets();
|
|
13946
14043
|
await this.#prepareExternalFiles("android");
|
|
13947
14044
|
await this.#applyAndroidMetadata();
|
|
13948
|
-
await this.#applyPermissions();
|
|
14045
|
+
await this.#applyPermissions({ operation, env });
|
|
13949
14046
|
await this.#applyDeepLinks("android", { operation, env });
|
|
13950
14047
|
await this.project.commit();
|
|
13951
14048
|
await this.#generateAssets({ operation, env });
|
|
@@ -14079,7 +14176,7 @@ ${error.message}`;
|
|
|
14079
14176
|
const htmlSource = path41.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
|
|
14080
14177
|
if (!await Bun.file(htmlSource).exists())
|
|
14081
14178
|
throw new Error(`CSR html for mobile target '${this.target.name}' not found: ${htmlSource}`);
|
|
14082
|
-
await
|
|
14179
|
+
await rm6(this.targetWebRoot, { recursive: true, force: true });
|
|
14083
14180
|
await mkdir11(this.targetWebRoot, { recursive: true });
|
|
14084
14181
|
await Bun.write(path41.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
|
|
14085
14182
|
}
|
|
@@ -14160,7 +14257,7 @@ ${error.message}`;
|
|
|
14160
14257
|
await this.project.android.setVersionCode(this.target.buildNum);
|
|
14161
14258
|
await this.project.android.setAppName(this.target.appName);
|
|
14162
14259
|
}
|
|
14163
|
-
async#applyPermissions() {
|
|
14260
|
+
async#applyPermissions({ operation, env }) {
|
|
14164
14261
|
for (const permission of this.target.permissions ?? []) {
|
|
14165
14262
|
if (permission === "camera")
|
|
14166
14263
|
await this.addCamera();
|
|
@@ -14169,7 +14266,7 @@ ${error.message}`;
|
|
|
14169
14266
|
else if (permission === "location")
|
|
14170
14267
|
await this.addLocation();
|
|
14171
14268
|
else if (permission === "push")
|
|
14172
|
-
await this.addPush();
|
|
14269
|
+
await this.addPush({ operation, env });
|
|
14173
14270
|
}
|
|
14174
14271
|
}
|
|
14175
14272
|
async#applyDeepLinks(platform, { operation, env }) {
|
|
@@ -14188,7 +14285,7 @@ ${error.message}`;
|
|
|
14188
14285
|
await this.#setUrlSchemesInIos(schemes);
|
|
14189
14286
|
}
|
|
14190
14287
|
if (domains.length > 0)
|
|
14191
|
-
await this.#setAssociatedDomainsInIos(domains);
|
|
14288
|
+
await this.#setAssociatedDomainsInIos(domains, { operation, env });
|
|
14192
14289
|
return;
|
|
14193
14290
|
}
|
|
14194
14291
|
if (platform === "android") {
|
|
@@ -14282,12 +14379,64 @@ ${error.message}`;
|
|
|
14282
14379
|
this.#setPermissionsInAndroid(["ACCESS_COARSE_LOCATION", "ACCESS_FINE_LOCATION"]);
|
|
14283
14380
|
this.#setFeaturesInAndroid(["android.hardware.location.gps"]);
|
|
14284
14381
|
}
|
|
14285
|
-
async addPush() {
|
|
14382
|
+
async addPush({ operation, env }) {
|
|
14286
14383
|
await this.#setPermissionInIos({
|
|
14287
14384
|
userNotificationsUsageDescription: "$(PRODUCT_NAME) uses notifications to keep you updated."
|
|
14288
14385
|
});
|
|
14386
|
+
await Promise.all([
|
|
14387
|
+
this.project.ios.updateInfoPlist(this.iosTargetName, "Debug", { UIBackgroundModes: ["remote-notification"] }),
|
|
14388
|
+
this.project.ios.updateInfoPlist(this.iosTargetName, "Release", { UIBackgroundModes: ["remote-notification"] }),
|
|
14389
|
+
this.#writeEntitlementsInIos(this.target.deepLinks?.domains ?? [], { operation, env }),
|
|
14390
|
+
this.#ensurePushAppDelegateInIos()
|
|
14391
|
+
]);
|
|
14289
14392
|
this.#setPermissionsInAndroid(["POST_NOTIFICATIONS"]);
|
|
14290
14393
|
}
|
|
14394
|
+
async#ensurePushAppDelegateInIos() {
|
|
14395
|
+
const appDelegatePath = path41.join(this.app.cwdPath, this.iosProjectPath, "App/AppDelegate.swift");
|
|
14396
|
+
if (!await Bun.file(appDelegatePath).exists())
|
|
14397
|
+
return;
|
|
14398
|
+
const editor = await FileEditor.create(appDelegatePath);
|
|
14399
|
+
let content = editor.getContent();
|
|
14400
|
+
if (!content.includes("import FirebaseCore")) {
|
|
14401
|
+
content = content.replace("import Capacitor", `import Capacitor
|
|
14402
|
+
import FirebaseCore`);
|
|
14403
|
+
}
|
|
14404
|
+
if (!content.includes("import FirebaseMessaging")) {
|
|
14405
|
+
content = content.replace("import FirebaseCore", `import FirebaseCore
|
|
14406
|
+
import FirebaseMessaging`);
|
|
14407
|
+
}
|
|
14408
|
+
if (!content.includes("FirebaseApp.configure()")) {
|
|
14409
|
+
content = content.replace(/\n(\s*)return true/, `
|
|
14410
|
+
$1FirebaseApp.configure()
|
|
14411
|
+
|
|
14412
|
+
$1return true`);
|
|
14413
|
+
}
|
|
14414
|
+
if (!content.includes("didRegisterForRemoteNotificationsWithDeviceToken")) {
|
|
14415
|
+
const delegateMethods = `
|
|
14416
|
+
func application(_ application: UIApplication,
|
|
14417
|
+
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
|
14418
|
+
Messaging.messaging().apnsToken = deviceToken
|
|
14419
|
+
NotificationCenter.default.post(
|
|
14420
|
+
name: .capacitorDidRegisterForRemoteNotifications,
|
|
14421
|
+
object: deviceToken
|
|
14422
|
+
)
|
|
14423
|
+
}
|
|
14424
|
+
|
|
14425
|
+
func application(_ application: UIApplication,
|
|
14426
|
+
didFailToRegisterForRemoteNotificationsWithError error: Error) {
|
|
14427
|
+
NotificationCenter.default.post(
|
|
14428
|
+
name: .capacitorDidFailToRegisterForRemoteNotifications,
|
|
14429
|
+
object: error
|
|
14430
|
+
)
|
|
14431
|
+
}
|
|
14432
|
+
`;
|
|
14433
|
+
content = content.replace(`
|
|
14434
|
+
func applicationWillResignActive`, `${delegateMethods}
|
|
14435
|
+
func applicationWillResignActive`);
|
|
14436
|
+
}
|
|
14437
|
+
if (content !== editor.getContent())
|
|
14438
|
+
await editor.setContent(content).save();
|
|
14439
|
+
}
|
|
14291
14440
|
async#setPermissionInIos(permissions) {
|
|
14292
14441
|
const updateNs = Object.fromEntries(Object.entries(permissions).map(([key, value]) => [`NS${capitalize5(key)}`, value]));
|
|
14293
14442
|
await Promise.all([
|
|
@@ -14305,25 +14454,35 @@ ${error.message}`;
|
|
|
14305
14454
|
this.project.ios.updateInfoPlist(this.iosTargetName, "Release", { CFBundleURLTypes: urlTypes })
|
|
14306
14455
|
]);
|
|
14307
14456
|
}
|
|
14308
|
-
async#setAssociatedDomainsInIos(domains) {
|
|
14457
|
+
async#setAssociatedDomainsInIos(domains, { operation, env }) {
|
|
14458
|
+
await this.#writeEntitlementsInIos(domains, { operation, env });
|
|
14459
|
+
}
|
|
14460
|
+
async#writeEntitlementsInIos(domains, runConfig) {
|
|
14309
14461
|
const entitlementsRelPath = "App/App.entitlements";
|
|
14310
14462
|
const entitlementsPath = path41.join(this.app.cwdPath, this.iosProjectPath, entitlementsRelPath);
|
|
14311
14463
|
const values = domains.map((domain) => `applinks:${domain}`);
|
|
14464
|
+
const usesPush = this.target.permissions?.includes("push") ?? false;
|
|
14465
|
+
const apsEnvironment = resolveIosApnsEnvironment(runConfig);
|
|
14312
14466
|
const body = [
|
|
14313
14467
|
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
14314
14468
|
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
|
|
14315
14469
|
'<plist version="1.0">',
|
|
14316
14470
|
"<dict>",
|
|
14317
|
-
" <key>
|
|
14318
|
-
|
|
14319
|
-
|
|
14320
|
-
|
|
14471
|
+
...usesPush ? [" <key>aps-environment</key>", ` <string>${apsEnvironment}</string>`] : [],
|
|
14472
|
+
...values.length > 0 ? [
|
|
14473
|
+
" <key>com.apple.developer.associated-domains</key>",
|
|
14474
|
+
" <array>",
|
|
14475
|
+
...values.map((value) => ` <string>${value}</string>`),
|
|
14476
|
+
" </array>"
|
|
14477
|
+
] : [],
|
|
14321
14478
|
"</dict>",
|
|
14322
14479
|
"</plist>",
|
|
14323
14480
|
""
|
|
14324
14481
|
].join(`
|
|
14325
14482
|
`);
|
|
14326
|
-
await
|
|
14483
|
+
const currentBody = await Bun.file(entitlementsPath).exists() ? await Bun.file(entitlementsPath).text() : undefined;
|
|
14484
|
+
if (currentBody !== body)
|
|
14485
|
+
await writeFile2(entitlementsPath, body);
|
|
14327
14486
|
await this.#setCodeSignEntitlementsInIos(entitlementsRelPath);
|
|
14328
14487
|
}
|
|
14329
14488
|
async#setCodeSignEntitlementsInIos(entitlementsRelPath) {
|
|
@@ -14427,7 +14586,7 @@ ${filter}$1`);
|
|
|
14427
14586
|
for (const permission of permissions) {
|
|
14428
14587
|
if (this.#hasPermissionInAndroid(permission)) {
|
|
14429
14588
|
this.app.logger.info(`${permission} already exists in android`);
|
|
14430
|
-
|
|
14589
|
+
continue;
|
|
14431
14590
|
}
|
|
14432
14591
|
this.app.logger.info(`Adding ${permission} to android`);
|
|
14433
14592
|
this.project.android.getAndroidManifest().injectFragment("manifest", `<uses-permission android:name="android.permission.${permission}" />`);
|
|
@@ -14443,7 +14602,7 @@ ${filter}$1`);
|
|
|
14443
14602
|
return Array.from(usesPermission).map((permission) => permission.getAttribute("android:name"));
|
|
14444
14603
|
}
|
|
14445
14604
|
#hasPermissionInAndroid(permission) {
|
|
14446
|
-
return this.#getPermissionsInAndroid().includes(permission);
|
|
14605
|
+
return this.#getPermissionsInAndroid().includes(`android.permission.${permission}`);
|
|
14447
14606
|
}
|
|
14448
14607
|
}
|
|
14449
14608
|
// pkgs/@akanjs/devkit/commandDecorators/targetMeta.ts
|
|
@@ -15547,6 +15706,7 @@ class AkanQualityScanner {
|
|
|
15547
15706
|
const warnings = [
|
|
15548
15707
|
...this.#scanGlobalQuality(sourceFiles),
|
|
15549
15708
|
...sourceFiles.flatMap((sourceFile2) => this.#scanSingleFileQuality(sourceFile2)),
|
|
15709
|
+
...sourceFiles.flatMap((sourceFile2) => this.#scanComponentQuality(sourceFile2)),
|
|
15550
15710
|
...sourceFiles.flatMap((sourceFile2) => this.#scanConventionQuality(sourceFile2)),
|
|
15551
15711
|
...sourceFiles.flatMap((sourceFile2) => this.#scanLayoutQuality(sourceFile2))
|
|
15552
15712
|
];
|
|
@@ -15675,6 +15835,28 @@ class AkanQualityScanner {
|
|
|
15675
15835
|
}
|
|
15676
15836
|
return warnings;
|
|
15677
15837
|
}
|
|
15838
|
+
#scanComponentQuality(sourceFile2) {
|
|
15839
|
+
if (!isComponentDeclarationFile(sourceFile2.file))
|
|
15840
|
+
return [];
|
|
15841
|
+
const exportedNames = getExportedDeclarationNames(sourceFile2.sourceFile);
|
|
15842
|
+
const allowedInternalInterfaces = new Set([...exportedNames].map((name) => `${name}Props`));
|
|
15843
|
+
const warnings = [];
|
|
15844
|
+
for (const declaration of getInternalTypeOrFunctionDeclarations(sourceFile2.sourceFile)) {
|
|
15845
|
+
if (exportedNames.has(declaration.name))
|
|
15846
|
+
continue;
|
|
15847
|
+
if (declaration.kind === "interface" && allowedInternalInterfaces.has(declaration.name))
|
|
15848
|
+
continue;
|
|
15849
|
+
warnings.push({
|
|
15850
|
+
rule: "akan.file.component-internal-declaration",
|
|
15851
|
+
scope: "file",
|
|
15852
|
+
severity: "warning",
|
|
15853
|
+
file: sourceFile2.file,
|
|
15854
|
+
line: declaration.line,
|
|
15855
|
+
message: `Component file should not declare non-exported ${declaration.kind} "${declaration.name}". Only a "<Component>Props" interface may stay internal; move other types or helpers to a separate file in ui/, webkit/, or common/ by purpose.`
|
|
15856
|
+
});
|
|
15857
|
+
}
|
|
15858
|
+
return warnings;
|
|
15859
|
+
}
|
|
15678
15860
|
#scanConventionQuality(sourceFile2) {
|
|
15679
15861
|
const suffix = CONVENTION_SUFFIXES.find((candidate) => sourceFile2.file.endsWith(candidate));
|
|
15680
15862
|
if (!suffix)
|
|
@@ -15758,7 +15940,7 @@ function formatQualityLocation(file, line) {
|
|
|
15758
15940
|
}
|
|
15759
15941
|
function getExportedFunctionLikes(sourceFile2) {
|
|
15760
15942
|
const declarations = [];
|
|
15761
|
-
const
|
|
15943
|
+
const nameExempt = isPageRouteFile(sourceFile2.file) || isUiComponentFile(sourceFile2.file);
|
|
15762
15944
|
for (const statement of sourceFile2.sourceFile.statements) {
|
|
15763
15945
|
if (ts11.isFunctionDeclaration(statement) && statement.name && isExported(statement)) {
|
|
15764
15946
|
declarations.push({
|
|
@@ -15767,7 +15949,7 @@ function getExportedFunctionLikes(sourceFile2) {
|
|
|
15767
15949
|
file: sourceFile2.file,
|
|
15768
15950
|
line: getLine(sourceFile2.sourceFile, statement),
|
|
15769
15951
|
bodyFingerprint: getBodyFingerprint(sourceFile2.sourceFile, statement.body),
|
|
15770
|
-
duplicateNameExempt:
|
|
15952
|
+
duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile2.file, false)
|
|
15771
15953
|
});
|
|
15772
15954
|
}
|
|
15773
15955
|
if (ts11.isClassDeclaration(statement) && statement.name && isExported(statement)) {
|
|
@@ -15777,7 +15959,7 @@ function getExportedFunctionLikes(sourceFile2) {
|
|
|
15777
15959
|
file: sourceFile2.file,
|
|
15778
15960
|
line: getLine(sourceFile2.sourceFile, statement),
|
|
15779
15961
|
bodyFingerprint: getBodyFingerprint(sourceFile2.sourceFile, statement),
|
|
15780
|
-
duplicateNameExempt:
|
|
15962
|
+
duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile2.file, isEnumClassStatement(sourceFile2.sourceFile, statement))
|
|
15781
15963
|
});
|
|
15782
15964
|
}
|
|
15783
15965
|
if (ts11.isVariableStatement(statement) && isExported(statement)) {
|
|
@@ -15790,7 +15972,7 @@ function getExportedFunctionLikes(sourceFile2) {
|
|
|
15790
15972
|
file: sourceFile2.file,
|
|
15791
15973
|
line: getLine(sourceFile2.sourceFile, declaration),
|
|
15792
15974
|
bodyFingerprint: getBodyFingerprint(sourceFile2.sourceFile, declaration.initializer),
|
|
15793
|
-
duplicateNameExempt:
|
|
15975
|
+
duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile2.file, false)
|
|
15794
15976
|
});
|
|
15795
15977
|
}
|
|
15796
15978
|
}
|
|
@@ -15801,6 +15983,10 @@ function isPageRouteFile(file) {
|
|
|
15801
15983
|
const segments = file.split("/");
|
|
15802
15984
|
return (segments[0] === "apps" || segments[0] === "libs") && segments[2] === "page";
|
|
15803
15985
|
}
|
|
15986
|
+
function isUiComponentFile(file) {
|
|
15987
|
+
const segments = file.split("/");
|
|
15988
|
+
return (segments[0] === "apps" || segments[0] === "libs") && segments[2] === "ui";
|
|
15989
|
+
}
|
|
15804
15990
|
function isConventionDuplicateNameExempt(file, isEnumClass) {
|
|
15805
15991
|
if (!isInLibModule(file))
|
|
15806
15992
|
return false;
|
|
@@ -15826,6 +16012,72 @@ function isEnumClassStatement(sourceFile2, statement) {
|
|
|
15826
16012
|
function getExportedClassNames(sourceFile2) {
|
|
15827
16013
|
return sourceFile2.statements.filter((statement) => ts11.isClassDeclaration(statement) && !!statement.name).filter((statement) => isExported(statement)).map((statement) => statement.name.text);
|
|
15828
16014
|
}
|
|
16015
|
+
function isComponentDeclarationFile(file) {
|
|
16016
|
+
if (!file.endsWith(".tsx"))
|
|
16017
|
+
return false;
|
|
16018
|
+
const segments = file.split("/");
|
|
16019
|
+
const [root, , area] = segments;
|
|
16020
|
+
if (root !== "apps" && root !== "libs")
|
|
16021
|
+
return false;
|
|
16022
|
+
if (area === "lib" || area === "ui")
|
|
16023
|
+
return true;
|
|
16024
|
+
return root === "apps" && area === "page";
|
|
16025
|
+
}
|
|
16026
|
+
function getExportedDeclarationNames(sourceFile2) {
|
|
16027
|
+
const names = new Set;
|
|
16028
|
+
for (const statement of sourceFile2.statements) {
|
|
16029
|
+
if (ts11.isExportDeclaration(statement) && statement.exportClause && ts11.isNamedExports(statement.exportClause)) {
|
|
16030
|
+
for (const element of statement.exportClause.elements) {
|
|
16031
|
+
names.add(element.name.text);
|
|
16032
|
+
if (element.propertyName)
|
|
16033
|
+
names.add(element.propertyName.text);
|
|
16034
|
+
}
|
|
16035
|
+
continue;
|
|
16036
|
+
}
|
|
16037
|
+
if (!isExported(statement))
|
|
16038
|
+
continue;
|
|
16039
|
+
for (const name of getStatementDeclarationNames(statement))
|
|
16040
|
+
names.add(name);
|
|
16041
|
+
}
|
|
16042
|
+
return names;
|
|
16043
|
+
}
|
|
16044
|
+
function getStatementDeclarationNames(statement) {
|
|
16045
|
+
if (ts11.isFunctionDeclaration(statement) && statement.name)
|
|
16046
|
+
return [statement.name.text];
|
|
16047
|
+
if (ts11.isClassDeclaration(statement) && statement.name)
|
|
16048
|
+
return [statement.name.text];
|
|
16049
|
+
if (ts11.isInterfaceDeclaration(statement))
|
|
16050
|
+
return [statement.name.text];
|
|
16051
|
+
if (ts11.isTypeAliasDeclaration(statement))
|
|
16052
|
+
return [statement.name.text];
|
|
16053
|
+
if (ts11.isEnumDeclaration(statement))
|
|
16054
|
+
return [statement.name.text];
|
|
16055
|
+
if (ts11.isVariableStatement(statement)) {
|
|
16056
|
+
return statement.declarationList.declarations.filter((declaration) => ts11.isIdentifier(declaration.name)).map((declaration) => declaration.name.text);
|
|
16057
|
+
}
|
|
16058
|
+
return [];
|
|
16059
|
+
}
|
|
16060
|
+
function getInternalTypeOrFunctionDeclarations(sourceFile2) {
|
|
16061
|
+
const declarations = [];
|
|
16062
|
+
for (const statement of sourceFile2.statements) {
|
|
16063
|
+
if (isExported(statement))
|
|
16064
|
+
continue;
|
|
16065
|
+
if (ts11.isInterfaceDeclaration(statement)) {
|
|
16066
|
+
declarations.push({ name: statement.name.text, kind: "interface", line: getLine(sourceFile2, statement) });
|
|
16067
|
+
} else if (ts11.isTypeAliasDeclaration(statement)) {
|
|
16068
|
+
declarations.push({ name: statement.name.text, kind: "type", line: getLine(sourceFile2, statement) });
|
|
16069
|
+
} else if (ts11.isFunctionDeclaration(statement) && statement.name) {
|
|
16070
|
+
declarations.push({ name: statement.name.text, kind: "function", line: getLine(sourceFile2, statement) });
|
|
16071
|
+
} else if (ts11.isVariableStatement(statement)) {
|
|
16072
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
16073
|
+
if (!ts11.isIdentifier(declaration.name) || !isFunctionLikeInitializer(declaration.initializer))
|
|
16074
|
+
continue;
|
|
16075
|
+
declarations.push({ name: declaration.name.text, kind: "function", line: getLine(sourceFile2, declaration) });
|
|
16076
|
+
}
|
|
16077
|
+
}
|
|
16078
|
+
}
|
|
16079
|
+
return declarations;
|
|
16080
|
+
}
|
|
15829
16081
|
function getPlaceholderExportWarnings(sourceFile2) {
|
|
15830
16082
|
if (!sourceFile2.file.endsWith("/index.ts") && !sourceFile2.file.endsWith("/index.tsx"))
|
|
15831
16083
|
return [];
|
package/index.js
CHANGED
|
@@ -664,6 +664,7 @@ import {
|
|
|
664
664
|
import { readFileSync as readFileSync3 } from "fs";
|
|
665
665
|
import { copyFile, mkdir as mkdir2, readdir as readDirEntries, stat as stat2 } from "fs/promises";
|
|
666
666
|
import path7 from "path";
|
|
667
|
+
import { pathToFileURL } from "url";
|
|
667
668
|
import {
|
|
668
669
|
capitalize,
|
|
669
670
|
isRouteSourceFile,
|
|
@@ -1105,6 +1106,63 @@ var decreaseBuildNum = async (app) => {
|
|
|
1105
1106
|
const akanConfigContent = akanConfig.replace(`buildNum: ${appConfig.mobile.buildNum}`, `buildNum: ${appConfig.mobile.buildNum - 1}`);
|
|
1106
1107
|
fs.writeFileSync(akanConfigPath, akanConfigContent);
|
|
1107
1108
|
};
|
|
1109
|
+
// pkgs/@akanjs/devkit/firebaseMessagingSw.ts
|
|
1110
|
+
var FIREBASE_WEB_SDK_VERSION = "12.13.0";
|
|
1111
|
+
function normalizeFirebaseClientConfig(config) {
|
|
1112
|
+
if (!config || typeof config !== "object")
|
|
1113
|
+
return null;
|
|
1114
|
+
const value = config;
|
|
1115
|
+
if (typeof value.apiKey !== "string" || typeof value.projectId !== "string" || typeof value.messagingSenderId !== "string" || typeof value.appId !== "string") {
|
|
1116
|
+
return null;
|
|
1117
|
+
}
|
|
1118
|
+
return {
|
|
1119
|
+
apiKey: value.apiKey,
|
|
1120
|
+
...typeof value.authDomain === "string" ? { authDomain: value.authDomain } : {},
|
|
1121
|
+
projectId: value.projectId,
|
|
1122
|
+
...typeof value.storageBucket === "string" ? { storageBucket: value.storageBucket } : {},
|
|
1123
|
+
messagingSenderId: value.messagingSenderId,
|
|
1124
|
+
appId: value.appId
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
function createFirebaseMessagingServiceWorker(config) {
|
|
1128
|
+
const configJson = JSON.stringify(config);
|
|
1129
|
+
return `/* Generated by Akan.js. Do not edit. */
|
|
1130
|
+
const firebaseConfig = ${configJson};
|
|
1131
|
+
|
|
1132
|
+
if (firebaseConfig) {
|
|
1133
|
+
importScripts("https://www.gstatic.com/firebasejs/${FIREBASE_WEB_SDK_VERSION}/firebase-app-compat.js");
|
|
1134
|
+
importScripts("https://www.gstatic.com/firebasejs/${FIREBASE_WEB_SDK_VERSION}/firebase-messaging-compat.js");
|
|
1135
|
+
|
|
1136
|
+
firebase.initializeApp(firebaseConfig);
|
|
1137
|
+
const messaging = firebase.messaging();
|
|
1138
|
+
|
|
1139
|
+
const notificationUrl = (payload) =>
|
|
1140
|
+
payload?.data?.url || payload?.fcmOptions?.link || payload?.notification?.click_action;
|
|
1141
|
+
|
|
1142
|
+
messaging.onBackgroundMessage((payload) => {
|
|
1143
|
+
const title = payload?.notification?.title || "";
|
|
1144
|
+
const options = {
|
|
1145
|
+
body: payload?.notification?.body,
|
|
1146
|
+
icon: payload?.notification?.icon,
|
|
1147
|
+
image: payload?.notification?.image,
|
|
1148
|
+
data: {
|
|
1149
|
+
url: notificationUrl(payload),
|
|
1150
|
+
FCM_MSG: payload,
|
|
1151
|
+
},
|
|
1152
|
+
};
|
|
1153
|
+
self.registration.showNotification(title, options);
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
self.addEventListener("notificationclick", (event) => {
|
|
1158
|
+
const url = event.notification?.data?.url || event.notification?.data?.FCM_MSG?.data?.url;
|
|
1159
|
+
event.notification?.close();
|
|
1160
|
+
if (!url) return;
|
|
1161
|
+
event.waitUntil(clients.openWindow(url));
|
|
1162
|
+
});
|
|
1163
|
+
`;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1108
1166
|
// pkgs/@akanjs/devkit/getDirname.ts
|
|
1109
1167
|
import path2 from "path";
|
|
1110
1168
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -1390,6 +1448,7 @@ ${errorText}, ${warningText} found`];
|
|
|
1390
1448
|
|
|
1391
1449
|
// pkgs/@akanjs/devkit/scanInfo.ts
|
|
1392
1450
|
import path5 from "path";
|
|
1451
|
+
import { rm } from "fs/promises";
|
|
1393
1452
|
|
|
1394
1453
|
// pkgs/@akanjs/devkit/dependencyScanner.ts
|
|
1395
1454
|
import { builtinModules } from "module";
|
|
@@ -1711,6 +1770,7 @@ var appRootAllowedFiles = new Set([
|
|
|
1711
1770
|
"tsconfig.json",
|
|
1712
1771
|
"tsconfig.tsbuildinfo"
|
|
1713
1772
|
]);
|
|
1773
|
+
var generatedRootCapacitorConfigFiles = ["capacitor.config.js", "capacitor.config.json"];
|
|
1714
1774
|
var appRootAllowedDirs = new Set([
|
|
1715
1775
|
".akan",
|
|
1716
1776
|
"android",
|
|
@@ -1754,11 +1814,17 @@ var rootSignalTestFilePattern = /^[A-Za-z][A-Za-z0-9_-]*\.signal\.(test|spec)\.(
|
|
|
1754
1814
|
var isAllowedTestFile = (filename) => testFilePattern.test(filename);
|
|
1755
1815
|
var isAllowedLibRootFile = (filename) => libRootAllowedFiles.has(filename) || rootSignalTestFilePattern.test(filename);
|
|
1756
1816
|
var getScanPath = (exec, relativePath) => path5.posix.join(`${exec.type}s`, exec.name, relativePath.split(path5.sep).join("/"));
|
|
1817
|
+
async function clearGeneratedRootCapacitorConfigs(exec) {
|
|
1818
|
+
if (exec.type !== "app")
|
|
1819
|
+
return;
|
|
1820
|
+
await Promise.all(generatedRootCapacitorConfigFiles.map((filename) => rm(exec.getPath(filename), { force: true })));
|
|
1821
|
+
}
|
|
1757
1822
|
var getModuleNameFromPath = (kind, modulePath) => {
|
|
1758
1823
|
const dirname = path5.basename(modulePath);
|
|
1759
1824
|
return kind === "service" ? dirname.replace(/^_+/, "") : dirname;
|
|
1760
1825
|
};
|
|
1761
1826
|
async function assertScanConvention(exec, libRoot) {
|
|
1827
|
+
await clearGeneratedRootCapacitorConfigs(exec);
|
|
1762
1828
|
const violations = [];
|
|
1763
1829
|
const addViolation = (relativePath, reason) => {
|
|
1764
1830
|
violations.push(`${getScanPath(exec, relativePath)}: ${reason}`);
|
|
@@ -3687,8 +3753,30 @@ class AppExecutor extends SysExecutor {
|
|
|
3687
3753
|
});
|
|
3688
3754
|
if (write)
|
|
3689
3755
|
await this.syncAssets(scanInfo.getScanResult().libDeps);
|
|
3756
|
+
if (write)
|
|
3757
|
+
await this.#syncFirebaseMessagingSw();
|
|
3690
3758
|
return scanInfo;
|
|
3691
3759
|
}
|
|
3760
|
+
async#syncFirebaseMessagingSw() {
|
|
3761
|
+
const swRelPath = "public/firebase-messaging-sw.js";
|
|
3762
|
+
if (await FileSys.fileExists(this.getPath(swRelPath)))
|
|
3763
|
+
return;
|
|
3764
|
+
const envClientPath = path7.join(this.cwdPath, "env", "env.client.ts");
|
|
3765
|
+
if (!await FileSys.fileExists(envClientPath))
|
|
3766
|
+
return;
|
|
3767
|
+
let firebaseConfig = null;
|
|
3768
|
+
try {
|
|
3769
|
+
const envUrl = pathToFileURL(envClientPath);
|
|
3770
|
+
envUrl.searchParams.set("t", String(Date.now()));
|
|
3771
|
+
const envModule = await import(envUrl.href);
|
|
3772
|
+
firebaseConfig = normalizeFirebaseClientConfig(envModule.env?.firebase);
|
|
3773
|
+
} catch {
|
|
3774
|
+
return;
|
|
3775
|
+
}
|
|
3776
|
+
if (!firebaseConfig)
|
|
3777
|
+
return;
|
|
3778
|
+
await this.writeFile(swRelPath, createFirebaseMessagingServiceWorker(firebaseConfig), { overwrite: false });
|
|
3779
|
+
}
|
|
3692
3780
|
async increaseBuildNum() {
|
|
3693
3781
|
await increaseBuildNum(this);
|
|
3694
3782
|
}
|
|
@@ -8717,7 +8805,7 @@ Caused by: ${ApplicationBuildReporter.formatError(error.cause)}` : "";
|
|
|
8717
8805
|
}
|
|
8718
8806
|
}
|
|
8719
8807
|
// pkgs/@akanjs/devkit/applicationBuildRunner.ts
|
|
8720
|
-
import { mkdir as mkdir8, rm as
|
|
8808
|
+
import { mkdir as mkdir8, rm as rm4 } from "fs/promises";
|
|
8721
8809
|
import path37 from "path";
|
|
8722
8810
|
|
|
8723
8811
|
// pkgs/@akanjs/devkit/frontendBuild/allRoutesBuilder.ts
|
|
@@ -10475,7 +10563,7 @@ class AllRoutesBuilder {
|
|
|
10475
10563
|
}
|
|
10476
10564
|
}
|
|
10477
10565
|
// pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
|
|
10478
|
-
import { mkdir as mkdir5, rm, unlink } from "fs/promises";
|
|
10566
|
+
import { mkdir as mkdir5, rm as rm2, unlink } from "fs/promises";
|
|
10479
10567
|
import path24 from "path";
|
|
10480
10568
|
|
|
10481
10569
|
// pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
|
|
@@ -10605,7 +10693,7 @@ class CsrArtifactBuilder {
|
|
|
10605
10693
|
const artifact = await this.#loadCsrArtifact();
|
|
10606
10694
|
const csrBasePaths = [...akanConfig2.basePaths];
|
|
10607
10695
|
const htmlEntries = csrBasePaths.length > 0 ? csrBasePaths : ["index"];
|
|
10608
|
-
await
|
|
10696
|
+
await rm2(this.#outputDir, { recursive: true, force: true });
|
|
10609
10697
|
await mkdir5(path24.join(this.#app.cwdPath, ".akan/generated/csr"), { recursive: true });
|
|
10610
10698
|
const generatedHtmlFiles = Object.fromEntries(htmlEntries.map((basePath2) => this.#createHtmlFile(basePath2)));
|
|
10611
10699
|
const result = await Bun.build({
|
|
@@ -11339,7 +11427,7 @@ class DevChangePlanner {
|
|
|
11339
11427
|
}
|
|
11340
11428
|
var uniqueResolved = (files) => [...new Set(files.map((file) => path27.resolve(file)))].sort();
|
|
11341
11429
|
// pkgs/@akanjs/devkit/frontendBuild/devGeneratedIndexSync.ts
|
|
11342
|
-
import { mkdir as mkdir6, readdir as readdir2, readFile, rm as
|
|
11430
|
+
import { mkdir as mkdir6, readdir as readdir2, readFile, rm as rm3, stat as stat3, writeFile } from "fs/promises";
|
|
11343
11431
|
import path28 from "path";
|
|
11344
11432
|
var BARREL_FACETS2 = new Set(["common", "srvkit", "ui", "webkit"]);
|
|
11345
11433
|
var FACET_SOURCE_FILE_RE = /\.(ts|tsx)$/;
|
|
@@ -11422,7 +11510,7 @@ class DevGeneratedIndexSync {
|
|
|
11422
11510
|
if (content === null) {
|
|
11423
11511
|
if (!await exists(indexPath))
|
|
11424
11512
|
return false;
|
|
11425
|
-
await
|
|
11513
|
+
await rm3(indexPath, { force: true });
|
|
11426
11514
|
return true;
|
|
11427
11515
|
}
|
|
11428
11516
|
const current = await readFile(indexPath, "utf8").catch(() => null);
|
|
@@ -12569,7 +12657,7 @@ class ApplicationBuildRunner {
|
|
|
12569
12657
|
await this.#app.getPageKeys({ refresh: true });
|
|
12570
12658
|
const { typecheckDir, tsconfigPath } = await this.#writeTypecheckTsconfig({ incremental });
|
|
12571
12659
|
if (clean)
|
|
12572
|
-
await
|
|
12660
|
+
await rm4(path37.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
|
|
12573
12661
|
await this.#checkProjectInChildProcess(tsconfigPath);
|
|
12574
12662
|
}
|
|
12575
12663
|
async#runPhase(id, label, task, summarize, options = {}) {
|
|
@@ -12769,7 +12857,7 @@ void run().catch((error) => {
|
|
|
12769
12857
|
}
|
|
12770
12858
|
}
|
|
12771
12859
|
// pkgs/@akanjs/devkit/applicationReleasePackager.ts
|
|
12772
|
-
import { cp, mkdir as mkdir9, rm as
|
|
12860
|
+
import { cp, mkdir as mkdir9, rm as rm5 } from "fs/promises";
|
|
12773
12861
|
import path38 from "path";
|
|
12774
12862
|
|
|
12775
12863
|
// pkgs/@akanjs/devkit/uploadRelease.ts
|
|
@@ -12876,7 +12964,7 @@ class ApplicationReleasePackager {
|
|
|
12876
12964
|
const platformVersion = akanConfig2.mobile.version;
|
|
12877
12965
|
const buildRoot = `${this.#app.workspace.workspaceRoot}/releases/builds/${this.#app.name}`;
|
|
12878
12966
|
if (await FileSys.dirExists(buildRoot))
|
|
12879
|
-
await
|
|
12967
|
+
await rm5(buildRoot, { recursive: true, force: true });
|
|
12880
12968
|
await mkdir9(buildRoot, { recursive: true });
|
|
12881
12969
|
if (rebuild || !await FileSys.dirExists(`${this.#app.dist.cwdPath}/backend`))
|
|
12882
12970
|
await this.#build();
|
|
@@ -12885,7 +12973,7 @@ class ApplicationReleasePackager {
|
|
|
12885
12973
|
await mkdir9(buildPath, { recursive: true });
|
|
12886
12974
|
await cp(`${this.#app.dist.cwdPath}/backend`, `${buildPath}/backend`, { recursive: true });
|
|
12887
12975
|
await cp(this.#app.dist.cwdPath, buildRoot, { recursive: true });
|
|
12888
|
-
await
|
|
12976
|
+
await rm5(`${buildRoot}/frontend/.next`, { recursive: true, force: true });
|
|
12889
12977
|
const releaseRoot = this.#app.workspace.workspaceRoot;
|
|
12890
12978
|
const releaseArchivePath = path38.relative(releaseRoot, `${releaseRoot}/releases/builds/${this.#app.name}-release.tar.gz`).split(path38.sep).join("/");
|
|
12891
12979
|
await this.#app.workspace.spawn("tar", ["-zcf", releaseArchivePath, "-C", buildRoot, "./"], { cwd: releaseRoot });
|
|
@@ -12901,7 +12989,7 @@ class ApplicationReleasePackager {
|
|
|
12901
12989
|
`${this.#app.workspace.workspaceRoot}/releases/builds/${this.#app.name}-appBuild.zip`,
|
|
12902
12990
|
"./csr"
|
|
12903
12991
|
]);
|
|
12904
|
-
await
|
|
12992
|
+
await rm5("./csr", { recursive: true, force: true });
|
|
12905
12993
|
}
|
|
12906
12994
|
async#writeSourceArchive({ readme }) {
|
|
12907
12995
|
const sourceRoot = `${this.#app.workspace.workspaceRoot}/releases/sources/${this.#app.name}`;
|
|
@@ -12912,7 +13000,7 @@ class ApplicationReleasePackager {
|
|
|
12912
13000
|
await Promise.all([".next", "ios", "android", "public/libs"].map(async (path39) => {
|
|
12913
13001
|
const targetPath = `${sourceRoot}/apps/${this.#app.name}/${path39}`;
|
|
12914
13002
|
if (await FileSys.dirExists(targetPath))
|
|
12915
|
-
await
|
|
13003
|
+
await rm5(targetPath, { recursive: true, force: true });
|
|
12916
13004
|
}));
|
|
12917
13005
|
const syncPaths = [".husky", ".gitignore", "package.json"];
|
|
12918
13006
|
await Promise.all(syncPaths.map((path39) => cp(`${this.#app.workspace.cwdPath}/${path39}`, `${sourceRoot}/${path39}`, { recursive: true })));
|
|
@@ -12927,7 +13015,7 @@ class ApplicationReleasePackager {
|
|
|
12927
13015
|
const maxRetry = 3;
|
|
12928
13016
|
for (let i = 0;i < maxRetry; i++) {
|
|
12929
13017
|
try {
|
|
12930
|
-
await
|
|
13018
|
+
await rm5(sourceRoot, { recursive: true, force: true });
|
|
12931
13019
|
} catch {}
|
|
12932
13020
|
}
|
|
12933
13021
|
}
|
|
@@ -13160,7 +13248,7 @@ class Builder {
|
|
|
13160
13248
|
}
|
|
13161
13249
|
}
|
|
13162
13250
|
// pkgs/@akanjs/devkit/capacitorApp.ts
|
|
13163
|
-
import { cp as cp2, mkdir as mkdir11, readFile as readFile2, rm as
|
|
13251
|
+
import { cp as cp2, mkdir as mkdir11, readFile as readFile2, rm as rm6, writeFile as writeFile2 } from "fs/promises";
|
|
13164
13252
|
import os from "os";
|
|
13165
13253
|
import path41 from "path";
|
|
13166
13254
|
import { select as select2 } from "@inquirer/prompts";
|
|
@@ -13371,7 +13459,7 @@ var rootCapacitorConfigFilenames = [
|
|
|
13371
13459
|
];
|
|
13372
13460
|
var rootCapacitorConfigPaths = (appRoot) => rootCapacitorConfigFilenames.map((file) => path41.join(appRoot, file));
|
|
13373
13461
|
async function clearRootCapacitorConfigs(appRoot) {
|
|
13374
|
-
await Promise.all(rootCapacitorConfigPaths(appRoot).map((file) =>
|
|
13462
|
+
await Promise.all(rootCapacitorConfigPaths(appRoot).map((file) => rm6(file, { force: true })));
|
|
13375
13463
|
}
|
|
13376
13464
|
async function writeRootCapacitorConfig(appRoot, content) {
|
|
13377
13465
|
await clearRootCapacitorConfigs(appRoot);
|
|
@@ -13392,6 +13480,7 @@ var getLocalIP = () => {
|
|
|
13392
13480
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13393
13481
|
var asString = (value) => typeof value === "string" ? value : undefined;
|
|
13394
13482
|
var firstString = (...values) => values.find((value) => typeof value === "string");
|
|
13483
|
+
var resolveIosApnsEnvironment = ({ operation }) => operation === "release" ? "production" : "development";
|
|
13395
13484
|
var scoreIosDeviceTarget = (target) => {
|
|
13396
13485
|
const state = target.state?.toLowerCase() ?? "";
|
|
13397
13486
|
return (state.includes("available") ? 4 : 0) + (state.includes("wired") ? 2 : 0) + (state.includes("paired") ? 1 : 0);
|
|
@@ -13697,6 +13786,8 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
|
|
|
13697
13786
|
const experimentalConfig = isRecord2(experimental) ? experimental : undefined;
|
|
13698
13787
|
const pluginsConfig = isRecord2(plugins) ? plugins : {};
|
|
13699
13788
|
const keyboardPluginConfig = isRecord2(pluginsConfig.Keyboard) ? pluginsConfig.Keyboard : {};
|
|
13789
|
+
const pushNotificationsPluginConfig = isRecord2(pluginsConfig.PushNotifications) ? pluginsConfig.PushNotifications : {};
|
|
13790
|
+
const usesPushNotifications = target.permissions?.includes("push") ?? false;
|
|
13700
13791
|
const config = {
|
|
13701
13792
|
...capacitorConfig,
|
|
13702
13793
|
appId,
|
|
@@ -13705,6 +13796,12 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
|
|
|
13705
13796
|
plugins: {
|
|
13706
13797
|
CapacitorCookies: { enabled: true },
|
|
13707
13798
|
...pluginsConfig,
|
|
13799
|
+
...usesPushNotifications || isRecord2(pluginsConfig.PushNotifications) ? {
|
|
13800
|
+
PushNotifications: {
|
|
13801
|
+
...usesPushNotifications ? { presentationOptions: ["badge", "sound", "alert"] } : {},
|
|
13802
|
+
...pushNotificationsPluginConfig
|
|
13803
|
+
}
|
|
13804
|
+
} : {},
|
|
13708
13805
|
Keyboard: {
|
|
13709
13806
|
resize: "none",
|
|
13710
13807
|
...keyboardPluginConfig
|
|
@@ -13776,9 +13873,9 @@ class CapacitorApp {
|
|
|
13776
13873
|
await mkdir11(this.targetRoot, { recursive: true });
|
|
13777
13874
|
if (regenerate) {
|
|
13778
13875
|
if (!platform || platform === "ios")
|
|
13779
|
-
await
|
|
13876
|
+
await rm6(path41.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
|
|
13780
13877
|
if (!platform || platform === "android")
|
|
13781
|
-
await
|
|
13878
|
+
await rm6(path41.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
|
|
13782
13879
|
}
|
|
13783
13880
|
const project = this.project;
|
|
13784
13881
|
await this.project.load();
|
|
@@ -13800,7 +13897,7 @@ class CapacitorApp {
|
|
|
13800
13897
|
await this.#prepareTargetAssets();
|
|
13801
13898
|
await this.#prepareExternalFiles("ios");
|
|
13802
13899
|
await this.#applyIosMetadata();
|
|
13803
|
-
await this.#applyPermissions();
|
|
13900
|
+
await this.#applyPermissions({ operation, env });
|
|
13804
13901
|
await this.#applyDeepLinks("ios", { operation, env });
|
|
13805
13902
|
await this.project.commit();
|
|
13806
13903
|
await this.#generateAssets({ operation, env });
|
|
@@ -13943,7 +14040,7 @@ ${error.message}`;
|
|
|
13943
14040
|
await this.#prepareTargetAssets();
|
|
13944
14041
|
await this.#prepareExternalFiles("android");
|
|
13945
14042
|
await this.#applyAndroidMetadata();
|
|
13946
|
-
await this.#applyPermissions();
|
|
14043
|
+
await this.#applyPermissions({ operation, env });
|
|
13947
14044
|
await this.#applyDeepLinks("android", { operation, env });
|
|
13948
14045
|
await this.project.commit();
|
|
13949
14046
|
await this.#generateAssets({ operation, env });
|
|
@@ -14077,7 +14174,7 @@ ${error.message}`;
|
|
|
14077
14174
|
const htmlSource = path41.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
|
|
14078
14175
|
if (!await Bun.file(htmlSource).exists())
|
|
14079
14176
|
throw new Error(`CSR html for mobile target '${this.target.name}' not found: ${htmlSource}`);
|
|
14080
|
-
await
|
|
14177
|
+
await rm6(this.targetWebRoot, { recursive: true, force: true });
|
|
14081
14178
|
await mkdir11(this.targetWebRoot, { recursive: true });
|
|
14082
14179
|
await Bun.write(path41.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
|
|
14083
14180
|
}
|
|
@@ -14158,7 +14255,7 @@ ${error.message}`;
|
|
|
14158
14255
|
await this.project.android.setVersionCode(this.target.buildNum);
|
|
14159
14256
|
await this.project.android.setAppName(this.target.appName);
|
|
14160
14257
|
}
|
|
14161
|
-
async#applyPermissions() {
|
|
14258
|
+
async#applyPermissions({ operation, env }) {
|
|
14162
14259
|
for (const permission of this.target.permissions ?? []) {
|
|
14163
14260
|
if (permission === "camera")
|
|
14164
14261
|
await this.addCamera();
|
|
@@ -14167,7 +14264,7 @@ ${error.message}`;
|
|
|
14167
14264
|
else if (permission === "location")
|
|
14168
14265
|
await this.addLocation();
|
|
14169
14266
|
else if (permission === "push")
|
|
14170
|
-
await this.addPush();
|
|
14267
|
+
await this.addPush({ operation, env });
|
|
14171
14268
|
}
|
|
14172
14269
|
}
|
|
14173
14270
|
async#applyDeepLinks(platform, { operation, env }) {
|
|
@@ -14186,7 +14283,7 @@ ${error.message}`;
|
|
|
14186
14283
|
await this.#setUrlSchemesInIos(schemes);
|
|
14187
14284
|
}
|
|
14188
14285
|
if (domains.length > 0)
|
|
14189
|
-
await this.#setAssociatedDomainsInIos(domains);
|
|
14286
|
+
await this.#setAssociatedDomainsInIos(domains, { operation, env });
|
|
14190
14287
|
return;
|
|
14191
14288
|
}
|
|
14192
14289
|
if (platform === "android") {
|
|
@@ -14280,12 +14377,64 @@ ${error.message}`;
|
|
|
14280
14377
|
this.#setPermissionsInAndroid(["ACCESS_COARSE_LOCATION", "ACCESS_FINE_LOCATION"]);
|
|
14281
14378
|
this.#setFeaturesInAndroid(["android.hardware.location.gps"]);
|
|
14282
14379
|
}
|
|
14283
|
-
async addPush() {
|
|
14380
|
+
async addPush({ operation, env }) {
|
|
14284
14381
|
await this.#setPermissionInIos({
|
|
14285
14382
|
userNotificationsUsageDescription: "$(PRODUCT_NAME) uses notifications to keep you updated."
|
|
14286
14383
|
});
|
|
14384
|
+
await Promise.all([
|
|
14385
|
+
this.project.ios.updateInfoPlist(this.iosTargetName, "Debug", { UIBackgroundModes: ["remote-notification"] }),
|
|
14386
|
+
this.project.ios.updateInfoPlist(this.iosTargetName, "Release", { UIBackgroundModes: ["remote-notification"] }),
|
|
14387
|
+
this.#writeEntitlementsInIos(this.target.deepLinks?.domains ?? [], { operation, env }),
|
|
14388
|
+
this.#ensurePushAppDelegateInIos()
|
|
14389
|
+
]);
|
|
14287
14390
|
this.#setPermissionsInAndroid(["POST_NOTIFICATIONS"]);
|
|
14288
14391
|
}
|
|
14392
|
+
async#ensurePushAppDelegateInIos() {
|
|
14393
|
+
const appDelegatePath = path41.join(this.app.cwdPath, this.iosProjectPath, "App/AppDelegate.swift");
|
|
14394
|
+
if (!await Bun.file(appDelegatePath).exists())
|
|
14395
|
+
return;
|
|
14396
|
+
const editor = await FileEditor.create(appDelegatePath);
|
|
14397
|
+
let content = editor.getContent();
|
|
14398
|
+
if (!content.includes("import FirebaseCore")) {
|
|
14399
|
+
content = content.replace("import Capacitor", `import Capacitor
|
|
14400
|
+
import FirebaseCore`);
|
|
14401
|
+
}
|
|
14402
|
+
if (!content.includes("import FirebaseMessaging")) {
|
|
14403
|
+
content = content.replace("import FirebaseCore", `import FirebaseCore
|
|
14404
|
+
import FirebaseMessaging`);
|
|
14405
|
+
}
|
|
14406
|
+
if (!content.includes("FirebaseApp.configure()")) {
|
|
14407
|
+
content = content.replace(/\n(\s*)return true/, `
|
|
14408
|
+
$1FirebaseApp.configure()
|
|
14409
|
+
|
|
14410
|
+
$1return true`);
|
|
14411
|
+
}
|
|
14412
|
+
if (!content.includes("didRegisterForRemoteNotificationsWithDeviceToken")) {
|
|
14413
|
+
const delegateMethods = `
|
|
14414
|
+
func application(_ application: UIApplication,
|
|
14415
|
+
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
|
14416
|
+
Messaging.messaging().apnsToken = deviceToken
|
|
14417
|
+
NotificationCenter.default.post(
|
|
14418
|
+
name: .capacitorDidRegisterForRemoteNotifications,
|
|
14419
|
+
object: deviceToken
|
|
14420
|
+
)
|
|
14421
|
+
}
|
|
14422
|
+
|
|
14423
|
+
func application(_ application: UIApplication,
|
|
14424
|
+
didFailToRegisterForRemoteNotificationsWithError error: Error) {
|
|
14425
|
+
NotificationCenter.default.post(
|
|
14426
|
+
name: .capacitorDidFailToRegisterForRemoteNotifications,
|
|
14427
|
+
object: error
|
|
14428
|
+
)
|
|
14429
|
+
}
|
|
14430
|
+
`;
|
|
14431
|
+
content = content.replace(`
|
|
14432
|
+
func applicationWillResignActive`, `${delegateMethods}
|
|
14433
|
+
func applicationWillResignActive`);
|
|
14434
|
+
}
|
|
14435
|
+
if (content !== editor.getContent())
|
|
14436
|
+
await editor.setContent(content).save();
|
|
14437
|
+
}
|
|
14289
14438
|
async#setPermissionInIos(permissions) {
|
|
14290
14439
|
const updateNs = Object.fromEntries(Object.entries(permissions).map(([key, value]) => [`NS${capitalize5(key)}`, value]));
|
|
14291
14440
|
await Promise.all([
|
|
@@ -14303,25 +14452,35 @@ ${error.message}`;
|
|
|
14303
14452
|
this.project.ios.updateInfoPlist(this.iosTargetName, "Release", { CFBundleURLTypes: urlTypes })
|
|
14304
14453
|
]);
|
|
14305
14454
|
}
|
|
14306
|
-
async#setAssociatedDomainsInIos(domains) {
|
|
14455
|
+
async#setAssociatedDomainsInIos(domains, { operation, env }) {
|
|
14456
|
+
await this.#writeEntitlementsInIos(domains, { operation, env });
|
|
14457
|
+
}
|
|
14458
|
+
async#writeEntitlementsInIos(domains, runConfig) {
|
|
14307
14459
|
const entitlementsRelPath = "App/App.entitlements";
|
|
14308
14460
|
const entitlementsPath = path41.join(this.app.cwdPath, this.iosProjectPath, entitlementsRelPath);
|
|
14309
14461
|
const values = domains.map((domain) => `applinks:${domain}`);
|
|
14462
|
+
const usesPush = this.target.permissions?.includes("push") ?? false;
|
|
14463
|
+
const apsEnvironment = resolveIosApnsEnvironment(runConfig);
|
|
14310
14464
|
const body = [
|
|
14311
14465
|
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
14312
14466
|
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
|
|
14313
14467
|
'<plist version="1.0">',
|
|
14314
14468
|
"<dict>",
|
|
14315
|
-
" <key>
|
|
14316
|
-
|
|
14317
|
-
|
|
14318
|
-
|
|
14469
|
+
...usesPush ? [" <key>aps-environment</key>", ` <string>${apsEnvironment}</string>`] : [],
|
|
14470
|
+
...values.length > 0 ? [
|
|
14471
|
+
" <key>com.apple.developer.associated-domains</key>",
|
|
14472
|
+
" <array>",
|
|
14473
|
+
...values.map((value) => ` <string>${value}</string>`),
|
|
14474
|
+
" </array>"
|
|
14475
|
+
] : [],
|
|
14319
14476
|
"</dict>",
|
|
14320
14477
|
"</plist>",
|
|
14321
14478
|
""
|
|
14322
14479
|
].join(`
|
|
14323
14480
|
`);
|
|
14324
|
-
await
|
|
14481
|
+
const currentBody = await Bun.file(entitlementsPath).exists() ? await Bun.file(entitlementsPath).text() : undefined;
|
|
14482
|
+
if (currentBody !== body)
|
|
14483
|
+
await writeFile2(entitlementsPath, body);
|
|
14325
14484
|
await this.#setCodeSignEntitlementsInIos(entitlementsRelPath);
|
|
14326
14485
|
}
|
|
14327
14486
|
async#setCodeSignEntitlementsInIos(entitlementsRelPath) {
|
|
@@ -14425,7 +14584,7 @@ ${filter}$1`);
|
|
|
14425
14584
|
for (const permission of permissions) {
|
|
14426
14585
|
if (this.#hasPermissionInAndroid(permission)) {
|
|
14427
14586
|
this.app.logger.info(`${permission} already exists in android`);
|
|
14428
|
-
|
|
14587
|
+
continue;
|
|
14429
14588
|
}
|
|
14430
14589
|
this.app.logger.info(`Adding ${permission} to android`);
|
|
14431
14590
|
this.project.android.getAndroidManifest().injectFragment("manifest", `<uses-permission android:name="android.permission.${permission}" />`);
|
|
@@ -14441,7 +14600,7 @@ ${filter}$1`);
|
|
|
14441
14600
|
return Array.from(usesPermission).map((permission) => permission.getAttribute("android:name"));
|
|
14442
14601
|
}
|
|
14443
14602
|
#hasPermissionInAndroid(permission) {
|
|
14444
|
-
return this.#getPermissionsInAndroid().includes(permission);
|
|
14603
|
+
return this.#getPermissionsInAndroid().includes(`android.permission.${permission}`);
|
|
14445
14604
|
}
|
|
14446
14605
|
}
|
|
14447
14606
|
// pkgs/@akanjs/devkit/commandDecorators/targetMeta.ts
|
|
@@ -15545,6 +15704,7 @@ class AkanQualityScanner {
|
|
|
15545
15704
|
const warnings = [
|
|
15546
15705
|
...this.#scanGlobalQuality(sourceFiles),
|
|
15547
15706
|
...sourceFiles.flatMap((sourceFile2) => this.#scanSingleFileQuality(sourceFile2)),
|
|
15707
|
+
...sourceFiles.flatMap((sourceFile2) => this.#scanComponentQuality(sourceFile2)),
|
|
15548
15708
|
...sourceFiles.flatMap((sourceFile2) => this.#scanConventionQuality(sourceFile2)),
|
|
15549
15709
|
...sourceFiles.flatMap((sourceFile2) => this.#scanLayoutQuality(sourceFile2))
|
|
15550
15710
|
];
|
|
@@ -15673,6 +15833,28 @@ class AkanQualityScanner {
|
|
|
15673
15833
|
}
|
|
15674
15834
|
return warnings;
|
|
15675
15835
|
}
|
|
15836
|
+
#scanComponentQuality(sourceFile2) {
|
|
15837
|
+
if (!isComponentDeclarationFile(sourceFile2.file))
|
|
15838
|
+
return [];
|
|
15839
|
+
const exportedNames = getExportedDeclarationNames(sourceFile2.sourceFile);
|
|
15840
|
+
const allowedInternalInterfaces = new Set([...exportedNames].map((name) => `${name}Props`));
|
|
15841
|
+
const warnings = [];
|
|
15842
|
+
for (const declaration of getInternalTypeOrFunctionDeclarations(sourceFile2.sourceFile)) {
|
|
15843
|
+
if (exportedNames.has(declaration.name))
|
|
15844
|
+
continue;
|
|
15845
|
+
if (declaration.kind === "interface" && allowedInternalInterfaces.has(declaration.name))
|
|
15846
|
+
continue;
|
|
15847
|
+
warnings.push({
|
|
15848
|
+
rule: "akan.file.component-internal-declaration",
|
|
15849
|
+
scope: "file",
|
|
15850
|
+
severity: "warning",
|
|
15851
|
+
file: sourceFile2.file,
|
|
15852
|
+
line: declaration.line,
|
|
15853
|
+
message: `Component file should not declare non-exported ${declaration.kind} "${declaration.name}". Only a "<Component>Props" interface may stay internal; move other types or helpers to a separate file in ui/, webkit/, or common/ by purpose.`
|
|
15854
|
+
});
|
|
15855
|
+
}
|
|
15856
|
+
return warnings;
|
|
15857
|
+
}
|
|
15676
15858
|
#scanConventionQuality(sourceFile2) {
|
|
15677
15859
|
const suffix = CONVENTION_SUFFIXES.find((candidate) => sourceFile2.file.endsWith(candidate));
|
|
15678
15860
|
if (!suffix)
|
|
@@ -15756,7 +15938,7 @@ function formatQualityLocation(file, line) {
|
|
|
15756
15938
|
}
|
|
15757
15939
|
function getExportedFunctionLikes(sourceFile2) {
|
|
15758
15940
|
const declarations = [];
|
|
15759
|
-
const
|
|
15941
|
+
const nameExempt = isPageRouteFile(sourceFile2.file) || isUiComponentFile(sourceFile2.file);
|
|
15760
15942
|
for (const statement of sourceFile2.sourceFile.statements) {
|
|
15761
15943
|
if (ts11.isFunctionDeclaration(statement) && statement.name && isExported(statement)) {
|
|
15762
15944
|
declarations.push({
|
|
@@ -15765,7 +15947,7 @@ function getExportedFunctionLikes(sourceFile2) {
|
|
|
15765
15947
|
file: sourceFile2.file,
|
|
15766
15948
|
line: getLine(sourceFile2.sourceFile, statement),
|
|
15767
15949
|
bodyFingerprint: getBodyFingerprint(sourceFile2.sourceFile, statement.body),
|
|
15768
|
-
duplicateNameExempt:
|
|
15950
|
+
duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile2.file, false)
|
|
15769
15951
|
});
|
|
15770
15952
|
}
|
|
15771
15953
|
if (ts11.isClassDeclaration(statement) && statement.name && isExported(statement)) {
|
|
@@ -15775,7 +15957,7 @@ function getExportedFunctionLikes(sourceFile2) {
|
|
|
15775
15957
|
file: sourceFile2.file,
|
|
15776
15958
|
line: getLine(sourceFile2.sourceFile, statement),
|
|
15777
15959
|
bodyFingerprint: getBodyFingerprint(sourceFile2.sourceFile, statement),
|
|
15778
|
-
duplicateNameExempt:
|
|
15960
|
+
duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile2.file, isEnumClassStatement(sourceFile2.sourceFile, statement))
|
|
15779
15961
|
});
|
|
15780
15962
|
}
|
|
15781
15963
|
if (ts11.isVariableStatement(statement) && isExported(statement)) {
|
|
@@ -15788,7 +15970,7 @@ function getExportedFunctionLikes(sourceFile2) {
|
|
|
15788
15970
|
file: sourceFile2.file,
|
|
15789
15971
|
line: getLine(sourceFile2.sourceFile, declaration),
|
|
15790
15972
|
bodyFingerprint: getBodyFingerprint(sourceFile2.sourceFile, declaration.initializer),
|
|
15791
|
-
duplicateNameExempt:
|
|
15973
|
+
duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile2.file, false)
|
|
15792
15974
|
});
|
|
15793
15975
|
}
|
|
15794
15976
|
}
|
|
@@ -15799,6 +15981,10 @@ function isPageRouteFile(file) {
|
|
|
15799
15981
|
const segments = file.split("/");
|
|
15800
15982
|
return (segments[0] === "apps" || segments[0] === "libs") && segments[2] === "page";
|
|
15801
15983
|
}
|
|
15984
|
+
function isUiComponentFile(file) {
|
|
15985
|
+
const segments = file.split("/");
|
|
15986
|
+
return (segments[0] === "apps" || segments[0] === "libs") && segments[2] === "ui";
|
|
15987
|
+
}
|
|
15802
15988
|
function isConventionDuplicateNameExempt(file, isEnumClass) {
|
|
15803
15989
|
if (!isInLibModule(file))
|
|
15804
15990
|
return false;
|
|
@@ -15824,6 +16010,72 @@ function isEnumClassStatement(sourceFile2, statement) {
|
|
|
15824
16010
|
function getExportedClassNames(sourceFile2) {
|
|
15825
16011
|
return sourceFile2.statements.filter((statement) => ts11.isClassDeclaration(statement) && !!statement.name).filter((statement) => isExported(statement)).map((statement) => statement.name.text);
|
|
15826
16012
|
}
|
|
16013
|
+
function isComponentDeclarationFile(file) {
|
|
16014
|
+
if (!file.endsWith(".tsx"))
|
|
16015
|
+
return false;
|
|
16016
|
+
const segments = file.split("/");
|
|
16017
|
+
const [root, , area] = segments;
|
|
16018
|
+
if (root !== "apps" && root !== "libs")
|
|
16019
|
+
return false;
|
|
16020
|
+
if (area === "lib" || area === "ui")
|
|
16021
|
+
return true;
|
|
16022
|
+
return root === "apps" && area === "page";
|
|
16023
|
+
}
|
|
16024
|
+
function getExportedDeclarationNames(sourceFile2) {
|
|
16025
|
+
const names = new Set;
|
|
16026
|
+
for (const statement of sourceFile2.statements) {
|
|
16027
|
+
if (ts11.isExportDeclaration(statement) && statement.exportClause && ts11.isNamedExports(statement.exportClause)) {
|
|
16028
|
+
for (const element of statement.exportClause.elements) {
|
|
16029
|
+
names.add(element.name.text);
|
|
16030
|
+
if (element.propertyName)
|
|
16031
|
+
names.add(element.propertyName.text);
|
|
16032
|
+
}
|
|
16033
|
+
continue;
|
|
16034
|
+
}
|
|
16035
|
+
if (!isExported(statement))
|
|
16036
|
+
continue;
|
|
16037
|
+
for (const name of getStatementDeclarationNames(statement))
|
|
16038
|
+
names.add(name);
|
|
16039
|
+
}
|
|
16040
|
+
return names;
|
|
16041
|
+
}
|
|
16042
|
+
function getStatementDeclarationNames(statement) {
|
|
16043
|
+
if (ts11.isFunctionDeclaration(statement) && statement.name)
|
|
16044
|
+
return [statement.name.text];
|
|
16045
|
+
if (ts11.isClassDeclaration(statement) && statement.name)
|
|
16046
|
+
return [statement.name.text];
|
|
16047
|
+
if (ts11.isInterfaceDeclaration(statement))
|
|
16048
|
+
return [statement.name.text];
|
|
16049
|
+
if (ts11.isTypeAliasDeclaration(statement))
|
|
16050
|
+
return [statement.name.text];
|
|
16051
|
+
if (ts11.isEnumDeclaration(statement))
|
|
16052
|
+
return [statement.name.text];
|
|
16053
|
+
if (ts11.isVariableStatement(statement)) {
|
|
16054
|
+
return statement.declarationList.declarations.filter((declaration) => ts11.isIdentifier(declaration.name)).map((declaration) => declaration.name.text);
|
|
16055
|
+
}
|
|
16056
|
+
return [];
|
|
16057
|
+
}
|
|
16058
|
+
function getInternalTypeOrFunctionDeclarations(sourceFile2) {
|
|
16059
|
+
const declarations = [];
|
|
16060
|
+
for (const statement of sourceFile2.statements) {
|
|
16061
|
+
if (isExported(statement))
|
|
16062
|
+
continue;
|
|
16063
|
+
if (ts11.isInterfaceDeclaration(statement)) {
|
|
16064
|
+
declarations.push({ name: statement.name.text, kind: "interface", line: getLine(sourceFile2, statement) });
|
|
16065
|
+
} else if (ts11.isTypeAliasDeclaration(statement)) {
|
|
16066
|
+
declarations.push({ name: statement.name.text, kind: "type", line: getLine(sourceFile2, statement) });
|
|
16067
|
+
} else if (ts11.isFunctionDeclaration(statement) && statement.name) {
|
|
16068
|
+
declarations.push({ name: statement.name.text, kind: "function", line: getLine(sourceFile2, statement) });
|
|
16069
|
+
} else if (ts11.isVariableStatement(statement)) {
|
|
16070
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
16071
|
+
if (!ts11.isIdentifier(declaration.name) || !isFunctionLikeInitializer(declaration.initializer))
|
|
16072
|
+
continue;
|
|
16073
|
+
declarations.push({ name: declaration.name.text, kind: "function", line: getLine(sourceFile2, declaration) });
|
|
16074
|
+
}
|
|
16075
|
+
}
|
|
16076
|
+
}
|
|
16077
|
+
return declarations;
|
|
16078
|
+
}
|
|
15827
16079
|
function getPlaceholderExportWarnings(sourceFile2) {
|
|
15828
16080
|
if (!sourceFile2.file.endsWith("/index.ts") && !sourceFile2.file.endsWith("/index.tsx"))
|
|
15829
16081
|
return [];
|
|
@@ -21194,7 +21446,7 @@ class LibraryCommand extends command("library", [LibraryScript], ({ public: targ
|
|
|
21194
21446
|
}
|
|
21195
21447
|
|
|
21196
21448
|
// pkgs/@akanjs/cli/localRegistry/localRegistry.runner.ts
|
|
21197
|
-
import { mkdir as mkdir13, rm as
|
|
21449
|
+
import { mkdir as mkdir13, rm as rm7 } from "fs/promises";
|
|
21198
21450
|
import path47 from "path";
|
|
21199
21451
|
import { Logger as Logger19 } from "akanjs/common";
|
|
21200
21452
|
var defaultLocalRegistryUrl = "http://127.0.0.1:4873";
|
|
@@ -21237,13 +21489,13 @@ class LocalRegistryRunner extends runner("localRegistry") {
|
|
|
21237
21489
|
try {
|
|
21238
21490
|
await workspace.spawn("docker", ["rm", "-f", containerName], { stdio: "inherit" });
|
|
21239
21491
|
} catch {}
|
|
21240
|
-
await
|
|
21492
|
+
await rm7(path47.join(workspace.workspaceRoot, ".akan/verdaccio"), { recursive: true, force: true });
|
|
21241
21493
|
Logger19.info("Local registry storage has been reset");
|
|
21242
21494
|
}
|
|
21243
21495
|
async smoke(workspace, { registryUrl } = {}) {
|
|
21244
21496
|
const registry = this.getRegistryUrl(registryUrl);
|
|
21245
21497
|
const smokeRoot = path47.join(workspace.workspaceRoot, ".akan/e2e");
|
|
21246
|
-
await
|
|
21498
|
+
await rm7(path47.join(smokeRoot, smokeRepoName), { recursive: true, force: true });
|
|
21247
21499
|
await workspace.spawn(process.execPath, [
|
|
21248
21500
|
"dist/pkgs/create-akan-workspace/index.js",
|
|
21249
21501
|
smokeRepoName,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/cli",
|
|
3
|
-
"version": "2.3.11-rc.
|
|
3
|
+
"version": "2.3.11-rc.9",
|
|
4
4
|
"sourceType": "module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@langchain/openai": "^1.4.6",
|
|
35
35
|
"@tailwindcss/node": "^4.3.0",
|
|
36
36
|
"@trapezedev/project": "^7.1.4",
|
|
37
|
-
"akanjs": "2.3.11-rc.
|
|
37
|
+
"akanjs": "2.3.11-rc.9",
|
|
38
38
|
"chalk": "^5.6.2",
|
|
39
39
|
"commander": "^14.0.3",
|
|
40
40
|
"daisyui": "5.5.23",
|
|
@@ -132,6 +132,20 @@
|
|
|
132
132
|
}
|
|
133
133
|
},
|
|
134
134
|
"overrides": [
|
|
135
|
+
{
|
|
136
|
+
"includes": [
|
|
137
|
+
"apps/**/*.ts",
|
|
138
|
+
"apps/**/*.tsx",
|
|
139
|
+
"libs/**/*.ts",
|
|
140
|
+
"libs/**/*.tsx",
|
|
141
|
+
"!**/*.test.ts",
|
|
142
|
+
"!**/*.test.tsx",
|
|
143
|
+
"!**/*.spec.ts",
|
|
144
|
+
"!**/*.spec.tsx",
|
|
145
|
+
"!**/common/**"
|
|
146
|
+
],
|
|
147
|
+
"plugins": ["./node_modules/@akanjs/devkit/lint/no-throw-raw-error.grit"]
|
|
148
|
+
},
|
|
135
149
|
{
|
|
136
150
|
"includes": ["**/page/**/*.ts", "**/page/**/*.tsx", "**/*.Unit.tsx", "**/*.View.tsx"],
|
|
137
151
|
"plugins": [
|