create-apexjs 0.6.7 → 0.6.8
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/package.json +1 -1
- package/templates/default/layouts/default.alpine +48 -19
- package/templates/features/data/db/index.ts +25 -24
- package/templates/mobile/android/README.md +53 -0
- package/templates/mobile/android/app/build.gradle.kts +30 -0
- package/templates/mobile/android/app/src/main/AndroidManifest.xml +24 -0
- package/templates/mobile/android/app/src/main/java/site/apexjs/shell/ApexBridge.kt +59 -0
- package/templates/mobile/android/app/src/main/java/site/apexjs/shell/ApexDbStore.kt +31 -0
- package/templates/mobile/android/app/src/main/java/site/apexjs/shell/ApexEngine.kt +66 -0
- package/templates/mobile/android/app/src/main/java/site/apexjs/shell/ApexInterceptor.kt +83 -0
- package/templates/mobile/android/app/src/main/java/site/apexjs/shell/MainActivity.kt +96 -0
- package/templates/mobile/android/app/src/main/res/drawable-hdpi/splash.png +0 -0
- package/templates/mobile/android/app/src/main/res/drawable-mdpi/splash.png +0 -0
- package/templates/mobile/android/app/src/main/res/drawable-xhdpi/splash.png +0 -0
- package/templates/mobile/android/app/src/main/res/drawable-xxhdpi/splash.png +0 -0
- package/templates/mobile/android/app/src/main/res/drawable-xxxhdpi/splash.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
- package/templates/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
- package/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
- package/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/templates/mobile/android/app/src/main/res/values/ic_launcher_background.xml +4 -0
- package/templates/mobile/android/app/src/main/res/values/strings.xml +4 -0
- package/templates/mobile/android/app/src/main/res/values/themes.xml +11 -0
- package/templates/mobile/android/build.gradle.kts +4 -0
- package/templates/mobile/android/gradle.properties +3 -0
- package/templates/mobile/android/play_store_512.png +0 -0
- package/templates/mobile/android/settings.gradle.kts +4 -0
- package/templates/mobile/apex-bridge.js +22 -0
- package/templates/mobile/gen-mobile-assets.mjs +101 -0
- package/templates/mobile/ios/ApexApp.swift +106 -0
- package/templates/mobile/ios/ApexDbStore.swift +74 -0
- package/templates/mobile/ios/ApexEngine.swift +253 -0
- package/templates/mobile/ios/ApexSchemeHandler.swift +349 -0
- package/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
- package/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/icon-1024.png +0 -0
- package/templates/mobile/ios/Assets.xcassets/LaunchBackground.colorset/Contents.json +20 -0
- package/templates/mobile/ios/Info.plist +60 -0
- package/templates/mobile/ios/README.md +153 -0
- package/templates/mobile/ios/Tests/ApexEngineTests.swift +74 -0
- package/templates/mobile/ios/project.yml +75 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// ApexEngineTests — runs on the iOS Simulator in CI (GitHub Actions macOS runner), no Mac needed
|
|
2
|
+
// locally. This is the highest-value iOS check: it proves the `apex build --mobile` bundle — the
|
|
3
|
+
// SHIM, the whole SSR + API pipeline, and the **asm.js SQLite** DB — actually runs under
|
|
4
|
+
// **JavaScriptCore** (iOS's engine, different from Android's V8). It drives ApexEngine directly, so
|
|
5
|
+
// it does NOT depend on WKURLSchemeHandler (the one remaining device-only unknown — POST bodies on
|
|
6
|
+
// a custom scheme — still needs a real device/UI test).
|
|
7
|
+
import JavaScriptCore
|
|
8
|
+
import XCTest
|
|
9
|
+
|
|
10
|
+
@testable import ApexShell
|
|
11
|
+
|
|
12
|
+
final class ApexEngineTests: XCTestCase {
|
|
13
|
+
/// server.mjs + apex-bridge.js are copied into the TEST bundle by CI (see project.yml resources).
|
|
14
|
+
private func makeEngine(snapshot: String? = nil) throws -> ApexEngine {
|
|
15
|
+
try ApexEngine(snapshot: snapshot, bundle: Bundle(for: Self.self))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private func request(_ url: String, method: String = "GET", body: String? = nil) -> String {
|
|
19
|
+
let obj: [String: Any] = [
|
|
20
|
+
"url": url,
|
|
21
|
+
"method": method,
|
|
22
|
+
"headers": ["content-type": "application/json"],
|
|
23
|
+
"body": body as Any? ?? NSNull(),
|
|
24
|
+
]
|
|
25
|
+
let data = try! JSONSerialization.data(withJSONObject: obj)
|
|
26
|
+
return String(data: data, encoding: .utf8)!
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/// SSR of a DB-backed page renders the seeded rows — proves JSContext runs the bundle + asm.js DB.
|
|
30
|
+
func testGuestbookRendersSeededRowsOnJavaScriptCore() async throws {
|
|
31
|
+
let engine = try makeEngine()
|
|
32
|
+
let res = await engine.handle(request("apex://localhost/guestbook"))
|
|
33
|
+
XCTAssertTrue(res.contains("Ada Lovelace"), "seeded row missing — bundle/DB didn't run on JSCore. Got: \(res.prefix(400))")
|
|
34
|
+
XCTAssertTrue(res.contains("Alan Turing"))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// POST inserts through the Drizzle deferred proxy on asm.js SQLite, and it persists across a
|
|
38
|
+
/// simulated cold start via the snapshot seam.
|
|
39
|
+
func testPostInsertsAndSurvivesSnapshotRestore() async throws {
|
|
40
|
+
let engine = try makeEngine()
|
|
41
|
+
_ = await engine.handle(request("apex://localhost/guestbook")) // lazy-init + seed the DB
|
|
42
|
+
|
|
43
|
+
let post = await engine.handle(
|
|
44
|
+
request(
|
|
45
|
+
"apex://localhost/api/messages",
|
|
46
|
+
method: "POST",
|
|
47
|
+
body: #"{"author":"iOS CI","body":"runs on JavaScriptCore"}"#
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
XCTAssertTrue(post.contains("iOS CI"), "POST /api/messages did not echo the created row: \(post.prefix(400))")
|
|
51
|
+
|
|
52
|
+
let after = await engine.handle(request("apex://localhost/guestbook"))
|
|
53
|
+
XCTAssertTrue(after.contains("iOS CI"), "new message not visible after POST")
|
|
54
|
+
|
|
55
|
+
// Cold-start persistence: export bytes, boot a fresh engine with them, data survives.
|
|
56
|
+
let snap = engine.snapshot()
|
|
57
|
+
XCTAssertFalse(snap.isEmpty, "snapshot export returned empty")
|
|
58
|
+
let restored = try makeEngine(snapshot: snap)
|
|
59
|
+
let restoredBody = await restored.handle(request("apex://localhost/guestbook"))
|
|
60
|
+
XCTAssertTrue(restoredBody.contains("iOS CI"), "message did not survive snapshot restore")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Sealed-cookie auth works on JSCore (HMAC, no WebCrypto): login sets a cookie, whoami is gated.
|
|
64
|
+
func testAuthLoginOnJavaScriptCore() async throws {
|
|
65
|
+
let engine = try makeEngine()
|
|
66
|
+
let anon = await engine.handle(request("apex://localhost/api/whoami"))
|
|
67
|
+
XCTAssertTrue(anon.contains("401"), "gated whoami should be 401 when anonymous: \(anon.prefix(200))")
|
|
68
|
+
|
|
69
|
+
let login = await engine.handle(
|
|
70
|
+
request("apex://localhost/api/login", method: "POST", body: #"{"name":"Ada"}"#)
|
|
71
|
+
)
|
|
72
|
+
XCTAssertTrue(login.contains("apex-session"), "login should set a session cookie: \(login.prefix(300))")
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# XcodeGen spec — generates ApexShell.xcodeproj from source, so the iOS project can be built on a
|
|
2
|
+
# CI macOS runner (or any Mac) without hand-authoring an .xcodeproj in Xcode.
|
|
3
|
+
# brew install xcodegen && (cd ios && xcodegen generate)
|
|
4
|
+
# The app + test bundle resources (server.mjs, apex-bridge.js, assets/, favicon.svg) are produced by
|
|
5
|
+
# `apex build --mobile` and copied into ios/Generated/ before generating (see .github/workflows/ios.yml).
|
|
6
|
+
name: ApexShell
|
|
7
|
+
options:
|
|
8
|
+
bundleIdPrefix: site.apexjs
|
|
9
|
+
deploymentTarget:
|
|
10
|
+
iOS: "15.0"
|
|
11
|
+
createIntermediateGroups: true
|
|
12
|
+
|
|
13
|
+
settings:
|
|
14
|
+
base:
|
|
15
|
+
SWIFT_VERSION: "5.0"
|
|
16
|
+
CODE_SIGNING_ALLOWED: "NO" # simulator builds/tests need no signing
|
|
17
|
+
|
|
18
|
+
targets:
|
|
19
|
+
ApexShell:
|
|
20
|
+
type: application
|
|
21
|
+
platform: iOS
|
|
22
|
+
sources:
|
|
23
|
+
- path: ApexApp.swift
|
|
24
|
+
- path: ApexEngine.swift
|
|
25
|
+
- path: ApexSchemeHandler.swift
|
|
26
|
+
- path: ApexDbStore.swift
|
|
27
|
+
- path: Assets.xcassets
|
|
28
|
+
- path: Generated/server.mjs
|
|
29
|
+
type: file
|
|
30
|
+
buildPhase: resources
|
|
31
|
+
- path: Generated/apex-bridge.js
|
|
32
|
+
type: file
|
|
33
|
+
buildPhase: resources
|
|
34
|
+
- path: Generated/assets
|
|
35
|
+
type: folder # blue folder reference → served verbatim at /assets/*
|
|
36
|
+
buildPhase: resources
|
|
37
|
+
- path: Generated/favicon.svg
|
|
38
|
+
type: file
|
|
39
|
+
buildPhase: resources
|
|
40
|
+
settings:
|
|
41
|
+
base:
|
|
42
|
+
PRODUCT_BUNDLE_IDENTIFIER: site.apexjs.shell
|
|
43
|
+
INFOPLIST_FILE: Info.plist
|
|
44
|
+
GENERATE_INFOPLIST_FILE: "NO"
|
|
45
|
+
TARGETED_DEVICE_FAMILY: "1,2"
|
|
46
|
+
|
|
47
|
+
ApexShellTests:
|
|
48
|
+
type: bundle.unit-test
|
|
49
|
+
platform: iOS
|
|
50
|
+
sources:
|
|
51
|
+
- path: Tests
|
|
52
|
+
# The engine test loads the bundle from its OWN (test) bundle, so copy the JS here too.
|
|
53
|
+
- path: Generated/server.mjs
|
|
54
|
+
type: file
|
|
55
|
+
buildPhase: resources
|
|
56
|
+
- path: Generated/apex-bridge.js
|
|
57
|
+
type: file
|
|
58
|
+
buildPhase: resources
|
|
59
|
+
dependencies:
|
|
60
|
+
- target: ApexShell
|
|
61
|
+
settings:
|
|
62
|
+
base:
|
|
63
|
+
TEST_HOST: "$(BUILT_PRODUCTS_DIR)/ApexShell.app/ApexShell"
|
|
64
|
+
BUNDLE_LOADER: "$(TEST_HOST)"
|
|
65
|
+
PRODUCT_BUNDLE_IDENTIFIER: site.apexjs.shell.tests
|
|
66
|
+
|
|
67
|
+
schemes:
|
|
68
|
+
ApexShell:
|
|
69
|
+
build:
|
|
70
|
+
targets:
|
|
71
|
+
ApexShell: all
|
|
72
|
+
ApexShellTests: [test]
|
|
73
|
+
test:
|
|
74
|
+
targets:
|
|
75
|
+
- ApexShellTests
|