@inglorious/create-app 1.12.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/bin/index.js +3 -0
- package/bin/lib/app.js +17 -3
- package/bin/lib/dependabot.js +28 -0
- package/bin/lib/mobile.js +53 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,6 +31,8 @@ For the JavaScript and TypeScript Vite templates, the CLI then asks about the ap
|
|
|
31
31
|
| Add push notifications? | `--push` / `--no-push` | Firebase Cloud Messaging, a permission prompt and the Supabase side of sending; turns on PWA support |
|
|
32
32
|
| Enable PWA support? | `--pwa` / `--no-pwa` | `vite-plugin-pwa`, a manifest, icons, and a service worker that keeps installed apps on the latest version |
|
|
33
33
|
|
|
34
|
+
Every template except `minimal` also gets `.github/dependabot.yml`, which opens weekly dependency updates on GitHub grouped into two pull requests: one for `@inglorious/*`, one for everything else.
|
|
35
|
+
|
|
34
36
|
Every template except `minimal` then asks whether to add agent skills (`--skills` / `--no-skills`). Saying yes runs the [skills CLI](https://skills.sh) in the new project. It asks which coding agents to install for, and installs the [Inglorious Forge skills](https://github.com/IngloriousCoderz/forge-skills) that match your choices: `forge`, `forge-best-practices`, `app-recipe`, `store`, `web` and `web-best-practices` always, plus `ssx`, `vite-plugin-jsx` or `vite-plugin-vue`, `ui` and `ui-best-practices`, `i18n`, `firebase` and `supabase` when the project uses them. If the install fails, the CLI prints the command to retry it.
|
|
35
37
|
|
|
36
38
|
The app is generated in the syntax you chose: lit-html, JSX or Vue. Every question answered on the command line is skipped, so a project can be created without any prompt:
|
|
@@ -99,7 +101,7 @@ For Android and iOS builds, install Android Studio with the Android SDK and a Ja
|
|
|
99
101
|
|
|
100
102
|
Every Vite app is versioned with [Changesets](https://github.com/changesets/changesets): describe each change with `pnpm changeset`, and `pnpm release:version` raises the version in `package.json` and writes `CHANGELOG.md`. The app reads that version as `import.meta.env.VITE_APP_VERSION`.
|
|
101
103
|
|
|
102
|
-
Mobile apps also get `pnpm mobile:release`, which copies the version into the iOS and Android projects, raises the build number they share (every store upload needs a new one), builds with the values in `.env` rather than `.env.local`, and syncs. The generated README describes the whole release, upload included. With `--push` too, an `app_versions` table in Supabase holds each platform's minimum build: an older install shows nothing but an update page, so raising it makes a release mandatory.
|
|
104
|
+
Mobile apps also get `pnpm mobile:release`, which copies the version into the iOS and Android projects, raises the build number they share (every store upload needs a new one), builds with the values in `.env` rather than `.env.local`, and syncs. The generated README describes the whole release, upload included. With `--push` too, an `app_versions` table in Supabase holds each platform's minimum build: an older install shows nothing but an update page, so raising it makes a release mandatory. Mobile apps also open links to their domain in the app: with routing, `watchAppLinks` from `@inglorious/web/app-links` sends the router to the link's path, and `public/.well-known/apple-app-site-association` is generated for iOS. The generated README lists the steps left: your Team ID, the Associated Domains capability, and serving that file as JSON.
|
|
103
105
|
|
|
104
106
|
## License
|
|
105
107
|
|
package/bin/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
USER_ARG_START_INDEX,
|
|
17
17
|
VITE_APP_TEMPLATES,
|
|
18
18
|
} from "./lib/constants.js"
|
|
19
|
+
import { addDependabot } from "./lib/dependabot.js"
|
|
19
20
|
import { SYNTAXES, TEMPLATES } from "./lib/features.js"
|
|
20
21
|
import { copyDir } from "./lib/file.js"
|
|
21
22
|
import { addFirebaseSupport } from "./lib/firebase.js"
|
|
@@ -173,6 +174,8 @@ async function main() {
|
|
|
173
174
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"))
|
|
174
175
|
pkg.name = projectName
|
|
175
176
|
|
|
177
|
+
addDependabot(targetDir)
|
|
178
|
+
|
|
176
179
|
const hasAppFeatures =
|
|
177
180
|
features.ui ||
|
|
178
181
|
features.routing ||
|
package/bin/lib/app.js
CHANGED
|
@@ -69,6 +69,7 @@ export function addAppFeatures(targetDir, pkg, options) {
|
|
|
69
69
|
app.isVue = app.renderer === "vue"
|
|
70
70
|
app.hasPrompts = app.analytics || app.push
|
|
71
71
|
app.nativeUpdate = app.mobile && app.push
|
|
72
|
+
app.appLinks = app.mobile && app.routing
|
|
72
73
|
app.layout = layout(app)
|
|
73
74
|
|
|
74
75
|
const components = COMPONENTS[app.renderer]
|
|
@@ -150,8 +151,10 @@ function addDependencies(pkg, app) {
|
|
|
150
151
|
CAPACITOR_FIREBASE_VERSION
|
|
151
152
|
pkg.dependencies["@supabase/supabase-js"] = SUPABASE_VERSION
|
|
152
153
|
}
|
|
153
|
-
if (app.nativeUpdate) {
|
|
154
|
+
if (app.nativeUpdate || app.appLinks) {
|
|
154
155
|
pkg.dependencies["@capacitor/app"] = CAPACITOR_APP_VERSION
|
|
156
|
+
}
|
|
157
|
+
if (app.nativeUpdate) {
|
|
155
158
|
pkg.dependencies["@inglorious/supabase"] = "workspace:*"
|
|
156
159
|
}
|
|
157
160
|
}
|
|
@@ -210,9 +213,14 @@ function mainSource(app) {
|
|
|
210
213
|
if (app.hasPrompts) {
|
|
211
214
|
imports.push('import { renderPrompts } from "./common/prompt"')
|
|
212
215
|
}
|
|
216
|
+
if (app.nativeUpdate || app.appLinks) {
|
|
217
|
+
imports.push('import { App as NativeApp } from "@capacitor/app"')
|
|
218
|
+
}
|
|
219
|
+
if (app.appLinks) {
|
|
220
|
+
imports.push('import { watchAppLinks } from "@inglorious/web/app-links"')
|
|
221
|
+
}
|
|
213
222
|
if (app.nativeUpdate) {
|
|
214
223
|
imports.push(
|
|
215
|
-
'import { App as NativeApp } from "@capacitor/app"',
|
|
216
224
|
'import { when } from "@inglorious/web/directives/when"',
|
|
217
225
|
'import { watchNativeUpdate } from "@inglorious/web/native-update"',
|
|
218
226
|
)
|
|
@@ -245,6 +253,12 @@ supabase.auth.onAuthStateChange((_event, session) => {
|
|
|
245
253
|
})`
|
|
246
254
|
: ""
|
|
247
255
|
|
|
256
|
+
const appLinks = app.appLinks
|
|
257
|
+
? `
|
|
258
|
+
|
|
259
|
+
watchAppLinks(NativeApp, store)`
|
|
260
|
+
: ""
|
|
261
|
+
|
|
248
262
|
const nativeUpdate = app.nativeUpdate
|
|
249
263
|
? `
|
|
250
264
|
|
|
@@ -262,7 +276,7 @@ function renderApp(api${app.isTypeScript ? ": AppApi" : ""}) {
|
|
|
262
276
|
|
|
263
277
|
return `${importBlock(imports)}
|
|
264
278
|
|
|
265
|
-
${body}${session}${nativeUpdate}
|
|
279
|
+
${body}${session}${appLinks}${nativeUpdate}
|
|
266
280
|
`
|
|
267
281
|
}
|
|
268
282
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import fs from "fs"
|
|
2
|
+
import path from "path"
|
|
3
|
+
|
|
4
|
+
const DEPENDABOT_CONFIG = `version: 2
|
|
5
|
+
updates:
|
|
6
|
+
- package-ecosystem: "npm"
|
|
7
|
+
directory: "/"
|
|
8
|
+
schedule:
|
|
9
|
+
interval: "weekly"
|
|
10
|
+
# One pull request a week for Inglorious Forge, one for everything else.
|
|
11
|
+
groups:
|
|
12
|
+
inglorious:
|
|
13
|
+
patterns: ["@inglorious/*"]
|
|
14
|
+
dependencies:
|
|
15
|
+
patterns: ["*"]
|
|
16
|
+
`
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Keeps the app's dependencies current with weekly Dependabot pull requests,
|
|
20
|
+
* grouped so each week brings two at most instead of one per package.
|
|
21
|
+
*
|
|
22
|
+
* @param {string} targetDir
|
|
23
|
+
*/
|
|
24
|
+
export function addDependabot(targetDir) {
|
|
25
|
+
const dir = path.join(targetDir, ".github")
|
|
26
|
+
fs.mkdirSync(dir, { recursive: true })
|
|
27
|
+
fs.writeFileSync(path.join(dir, "dependabot.yml"), DEPENDABOT_CONFIG)
|
|
28
|
+
}
|
package/bin/lib/mobile.js
CHANGED
|
@@ -2,7 +2,11 @@ import fs from "fs"
|
|
|
2
2
|
import { EOL } from "os"
|
|
3
3
|
import path from "path"
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
CAPACITOR_VERSION,
|
|
7
|
+
INDENTATION,
|
|
8
|
+
TYPESCRIPT_VERSION,
|
|
9
|
+
} from "./constants.js"
|
|
6
10
|
import { copyDir, toJavaIdentifier } from "./file.js"
|
|
7
11
|
|
|
8
12
|
export function addMobileSupport(targetDir, pkg, projectName, templatesRoot) {
|
|
@@ -34,6 +38,7 @@ export function addMobileSupport(targetDir, pkg, projectName, templatesRoot) {
|
|
|
34
38
|
path.join(targetDir, "capacitor.config.ts"),
|
|
35
39
|
createCapacitorConfigSource(projectName),
|
|
36
40
|
)
|
|
41
|
+
writeAppSiteAssociation(targetDir, projectName)
|
|
37
42
|
includeInNodeProject(targetDir, "capacitor.config.ts")
|
|
38
43
|
|
|
39
44
|
appendMobileSetupToReadme(targetDir)
|
|
@@ -107,6 +112,27 @@ pnpm mobile:android
|
|
|
107
112
|
pnpm mobile:ios
|
|
108
113
|
\`\`\`
|
|
109
114
|
|
|
115
|
+
### Opening links in the app
|
|
116
|
+
|
|
117
|
+
With Universal Links, a link to the app's domain opens the installed app instead of the browser, and the router goes to the link's path. The app's side is done; three steps are yours:
|
|
118
|
+
|
|
119
|
+
1. Replace \`TEAM_ID\` in \`public/.well-known/apple-app-site-association\` with your Apple Developer Team ID, and keep the bundle ID in step with \`appId\` in \`capacitor.config.ts\`. Add paths that must stay in the browser as \`{ "/": "/path*", "exclude": true }\` before the last entry.
|
|
120
|
+
2. In Xcode, select the app target, open **Signing & Capabilities**, add **Associated Domains**, and enter \`applinks:your-domain.com\`.
|
|
121
|
+
3. Serve the file as JSON, without a redirect. On Vercel, add this to \`vercel.json\`:
|
|
122
|
+
|
|
123
|
+
\`\`\`json
|
|
124
|
+
{
|
|
125
|
+
"headers": [
|
|
126
|
+
{
|
|
127
|
+
"source": "/.well-known/apple-app-site-association",
|
|
128
|
+
"headers": [{ "key": "Content-Type", "value": "application/json" }]
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
\`\`\`
|
|
133
|
+
|
|
134
|
+
Test on a device by tapping a link in Notes or Messages; typing it in Safari does not count. Apple caches the file, so a change can take a few hours to arrive. Android App Links need \`/.well-known/assetlinks.json\` with your signing certificate's SHA-256 fingerprint and an intent filter in \`AndroidManifest.xml\`; see https://developer.android.com/training/app-links.
|
|
135
|
+
|
|
110
136
|
### Releasing
|
|
111
137
|
|
|
112
138
|
The version users see comes from \`package.json\`, the same on the web, Android and iOS. The build number is shared by both native apps and must go up with every store upload.
|
|
@@ -123,7 +149,7 @@ The version users see comes from \`package.json\`, the same on the web, Android
|
|
|
123
149
|
}
|
|
124
150
|
|
|
125
151
|
export function createCapacitorConfigSource(projectName) {
|
|
126
|
-
const appId =
|
|
152
|
+
const appId = appIdOf(projectName)
|
|
127
153
|
|
|
128
154
|
return `import type { CapacitorConfig } from "@capacitor/cli"
|
|
129
155
|
|
|
@@ -137,6 +163,31 @@ export default config
|
|
|
137
163
|
`
|
|
138
164
|
}
|
|
139
165
|
|
|
166
|
+
function appIdOf(projectName) {
|
|
167
|
+
return `com.inglorious.${toJavaIdentifier(projectName)}`
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Links carrying a session token, from sign-up and password-reset emails,
|
|
171
|
+
// stay in the browser, where the sign-in flow expects them.
|
|
172
|
+
function writeAppSiteAssociation(targetDir, projectName) {
|
|
173
|
+
const association = {
|
|
174
|
+
applinks: {
|
|
175
|
+
details: [
|
|
176
|
+
{
|
|
177
|
+
appIDs: [`TEAM_ID.${appIdOf(projectName)}`],
|
|
178
|
+
components: [{ "#": "*access_token*", exclude: true }, { "/": "*" }],
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
const dir = path.join(targetDir, "public", ".well-known")
|
|
184
|
+
fs.mkdirSync(dir, { recursive: true })
|
|
185
|
+
fs.writeFileSync(
|
|
186
|
+
path.join(dir, "apple-app-site-association"),
|
|
187
|
+
JSON.stringify(association, null, INDENTATION) + EOL,
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
140
191
|
function includeInNodeProject(targetDir, file) {
|
|
141
192
|
const tsconfigPath = path.join(targetDir, "tsconfig.node.json")
|
|
142
193
|
if (!fs.existsSync(tsconfigPath)) return
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inglorious/create-app",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "A scaffolding tool to quickly create a new app with Inglorious Web.",
|
|
5
5
|
"author": "Matteo Antony Mistretta <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
|
|
6
6
|
"license": "MIT",
|