Skip to content

Commit 4e5d2a5

Browse files
Merge branch 'main' into issue-828-colored-components-diagram-elements-are
2 parents 6835377 + dcc7af1 commit 4e5d2a5

349 files changed

Lines changed: 43416 additions & 3040 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/clear-signs-live.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tumaet/webapp": patch
3+
---
4+
5+
Start every bundled design-pattern template in a clean, visually balanced editing state, with stable shared hierarchy trunks and automatic routing preserved for associations.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tumaet/apollon": minor
3+
---
4+
5+
Create cleaner diagrams with automatic edges that balance connection points, reduce collisions with nodes and nearby edges, and stay responsive while you drag, without losing pinned endpoints, hand-placed bends, aligned component interfaces, or compatibility with older diagrams; embedding apps can also normalize diagrams in server-side code through the new `@tumaet/apollon/model` entry.

.changeset/three-socks-teach.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tumaet/webapp": patch
3+
---
4+
5+
Rebuild the iPhone and iPad app on the redesigned editor with the familiar Apollon branding, and stop the web app from loading its font from Google — it is now self-hosted.

.codacy.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Codacy configuration.
2+
#
3+
# `exclude_paths` is additive to Codacy's default ignores and does not change
4+
# which analysis tools are enabled — it only tells Codacy to skip these files.
5+
exclude_paths:
6+
# Vendored verbatim from the fastlane project
7+
# (https://github.com/fastlane/fastlane) and updated by re-copying, not by
8+
# hand. We do not restyle it to local lint rules.
9+
- "standalone/webapp/ios/App/AppStoreScreenshots/SnapshotHelper.swift"

.github/workflows/deploy-prod.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,19 @@ jobs:
8282
image-tag: ${{ inputs.image-tag }}
8383
deployment-base-path: "/opt/apollon/app"
8484
secrets: inherit
85+
86+
# Publish the matching over-the-air web-bundle update for the mobile app right
87+
# after the web app is deployed ("deploy == OTA publish"). Opt-in: only runs
88+
# where the ENABLE_LIVE_UPDATE variable is "true", so operators who don't ship
89+
# a mobile app are unaffected.
90+
publish-live-update:
91+
needs: deploy-app
92+
if: ${{ inputs.deploy-app && vars.ENABLE_LIVE_UPDATE == 'true' }}
93+
uses: ./.github/workflows/ios-live-update.yml
94+
with:
95+
# Build the OTA bundle from the SAME commit as the deployed image, not from
96+
# whatever ref this workflow was dispatched on — otherwise a rollback or a
97+
# redeploy of an older `sha-<commit>` tag would ship a web bundle that does
98+
# not match the web app that just went live.
99+
source-ref: ${{ inputs.image-tag }}
100+
secrets: inherit
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
name: ios-live-update
2+
3+
# Publishes an over-the-air web-bundle update for the mobile app. The bundle is
4+
# the SAME dist the webapp deploy ships, signed with the Capgo private key, and
5+
# copied to the directory the webapp nginx serves at /live-updates/. Reuses the
6+
# EXISTING deployment identity and gateway (VM_* + DEPLOYMENT_GATEWAY_*), so no
7+
# new key or user is introduced. Runs on manual dispatch and is callable from
8+
# the production deploy so a normal deploy also publishes the matching bundle.
9+
#
10+
# Uses (already configured for deploys):
11+
# secrets: CAPGO_PRIVATE_KEY, VM_SSH_PRIVATE_KEY, DEPLOYMENT_GATEWAY_SSH_KEY
12+
# vars: CAPGO_PUBLIC_KEY, CAPGO_MIN_NATIVE_VERSION, VM_HOST, VM_USERNAME,
13+
# DEPLOYMENT_GATEWAY_HOST, DEPLOYMENT_GATEWAY_USER, DEPLOYMENT_GATEWAY_PORT
14+
15+
on:
16+
workflow_dispatch:
17+
inputs:
18+
source-ref:
19+
description: >
20+
Commit to package, as the deployed image tag (`sha-<commit>`) or a raw
21+
commit SHA. Empty uses the dispatched ref.
22+
required: false
23+
type: string
24+
workflow_call:
25+
inputs:
26+
source-ref:
27+
description: "Deployed image tag (`sha-<commit>`) or commit SHA to package."
28+
required: false
29+
type: string
30+
31+
concurrency:
32+
group: ios-live-update-${{ github.ref }}
33+
cancel-in-progress: false
34+
35+
permissions:
36+
contents: read
37+
38+
jobs:
39+
publish:
40+
runs-on: ubuntu-latest
41+
environment: Production
42+
steps:
43+
# `sha-<commit>` is the tag convention build-and-push publishes images under,
44+
# so stripping the prefix yields the commit the deployed image was built from.
45+
- name: Resolve the commit to package
46+
id: source
47+
run: |
48+
REF="${{ inputs.source-ref }}"
49+
echo "ref=${REF#sha-}" >> "$GITHUB_OUTPUT"
50+
51+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
52+
with:
53+
ref: ${{ steps.source.outputs.ref }}
54+
55+
- uses: pnpm/action-setup@ac6db6d3c1f721f886538a378a2d73e85697340a # v6.0.8
56+
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6
57+
with:
58+
node-version-file: .nvmrc
59+
cache: pnpm
60+
61+
- name: Install dependencies
62+
run: pnpm install --frozen-lockfile
63+
64+
- name: Build web bundle
65+
run: |
66+
pnpm --filter @tumaet/apollon run build
67+
pnpm --filter @tumaet/webapp run build
68+
69+
- name: Build + sign the live-update bundle
70+
working-directory: standalone/webapp
71+
env:
72+
CAPGO_PRIVATE_KEY: ${{ secrets.CAPGO_PRIVATE_KEY }}
73+
CAPGO_PUBLIC_KEY: ${{ vars.CAPGO_PUBLIC_KEY }}
74+
CAPGO_MIN_NATIVE_VERSION: ${{ vars.CAPGO_MIN_NATIVE_VERSION }}
75+
run: pnpm run live-update:build
76+
77+
# Upload the immutable bundle zip(s) FIRST so the manifest never points at
78+
# a file that is not yet on the host.
79+
- name: Copy bundle zips to the VM
80+
uses: appleboy/scp-action@ff85246acaad7bdce478db94a363cd2bf7c90345 # v1.0.0
81+
with:
82+
host: ${{ vars.VM_HOST }}
83+
username: ${{ vars.VM_USERNAME }}
84+
key: ${{ secrets.VM_SSH_PRIVATE_KEY }}
85+
proxy_host: ${{ vars.DEPLOYMENT_GATEWAY_HOST }}
86+
proxy_username: ${{ vars.DEPLOYMENT_GATEWAY_USER }}
87+
proxy_key: ${{ secrets.DEPLOYMENT_GATEWAY_SSH_KEY }}
88+
proxy_port: ${{ vars.DEPLOYMENT_GATEWAY_PORT }}
89+
source: "standalone/webapp/live-updates-dist/*.zip"
90+
target: "/opt/apollon/app/live-updates/"
91+
strip_components: 3
92+
93+
- name: Copy manifest to the VM
94+
uses: appleboy/scp-action@ff85246acaad7bdce478db94a363cd2bf7c90345 # v1.0.0
95+
with:
96+
host: ${{ vars.VM_HOST }}
97+
username: ${{ vars.VM_USERNAME }}
98+
key: ${{ secrets.VM_SSH_PRIVATE_KEY }}
99+
proxy_host: ${{ vars.DEPLOYMENT_GATEWAY_HOST }}
100+
proxy_username: ${{ vars.DEPLOYMENT_GATEWAY_USER }}
101+
proxy_key: ${{ secrets.DEPLOYMENT_GATEWAY_SSH_KEY }}
102+
proxy_port: ${{ vars.DEPLOYMENT_GATEWAY_PORT }}
103+
source: "standalone/webapp/live-updates-dist/manifest.json"
104+
target: "/opt/apollon/app/live-updates/"
105+
strip_components: 3

.github/workflows/ios-testflight-release.yml

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,40 @@
1-
name: ios-testflight-release
1+
name: ios-release
22

33
on:
44
workflow_dispatch:
5+
inputs:
6+
destination:
7+
description: Where to publish the build and App Store assets
8+
required: true
9+
default: testflight
10+
type: choice
11+
options:
12+
- testflight
13+
- app-store-assets
14+
- app-store
15+
submit_for_review:
16+
description: Submit the App Store version for review after upload
17+
required: true
18+
default: false
19+
type: boolean
20+
screenshot_style:
21+
description: Screenshot presentation to upload
22+
required: true
23+
default: framed
24+
type: choice
25+
options:
26+
- raw
27+
- framed
528

629
concurrency:
7-
group: ios-testflight-release-${{ github.ref }}
30+
group: ios-release-${{ github.ref }}
831
cancel-in-progress: false
932

1033
permissions:
1134
contents: read
1235

1336
jobs:
14-
testflight:
37+
release:
1538
runs-on: [self-hosted, macOS]
1639
timeout-minutes: 60
1740
defaults:
@@ -32,6 +55,11 @@ jobs:
3255
- name: Install dependencies
3356
run: pnpm install --frozen-lockfile
3457

58+
- name: Validate App Store metadata and public links
59+
if: inputs.destination != 'testflight'
60+
working-directory: standalone/webapp
61+
run: pnpm appstore:metadata:validate
62+
3563
- name: Install Ruby gems (fastlane + cocoapods)
3664
working-directory: standalone/webapp
3765
run: |
@@ -53,15 +81,49 @@ jobs:
5381
5482
- name: Capacitor sync (iOS)
5583
working-directory: standalone/webapp
84+
# Bake the live-update signing public key into the app so the updater
85+
# strictly rejects any bundle it can't verify. Unset (e.g. forks) → the
86+
# feature is simply disabled, not insecure.
87+
env:
88+
CAPGO_PUBLIC_KEY: ${{ vars.CAPGO_PUBLIC_KEY }}
89+
# Fail the build if the signing key is missing rather than shipping
90+
# OTA with signature enforcement silently disabled.
91+
CAPGO_REQUIRE_SIGNING: "true"
5692
run: pnpm exec cap sync ios
5793

5894
- name: Resolve marketing version and build number
95+
if: inputs.destination != 'app-store-assets'
5996
run: |
6097
MARKETING_VERSION=$(node -p "require('./standalone/webapp/package.json').version")
6198
echo "MARKETING_VERSION=$MARKETING_VERSION" >> "$GITHUB_ENV"
6299
echo "BUILD_NUMBER=$(date +'%Y%m%d%H%M')" >> "$GITHUB_ENV"
63100
101+
- name: Prepare licensed Apple product bezels
102+
if: inputs.destination != 'testflight' && inputs.screenshot_style == 'framed'
103+
working-directory: standalone/webapp
104+
run: pnpm run appstore:screenshots:prepare-frames
105+
106+
- name: Capture iPhone and iPad App Store screenshots
107+
if: inputs.destination != 'testflight'
108+
working-directory: standalone/webapp
109+
env:
110+
APP_STORE_SCREENSHOT_STYLE: ${{ inputs.screenshot_style }}
111+
run: bundle exec fastlane screenshots
112+
113+
- name: Upload App Store screenshot review
114+
if: inputs.destination != 'testflight'
115+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
116+
with:
117+
name: ios-app-store-screenshot-review
118+
path: |
119+
standalone/webapp/fastlane/screenshots/
120+
standalone/webapp/fastlane/screenshots-framed/
121+
standalone/webapp/fastlane/screenshots-review.html
122+
if-no-files-found: error
123+
retention-days: 14
124+
64125
- name: Build iOS app (Fastlane)
126+
if: inputs.destination != 'app-store-assets'
65127
working-directory: standalone/webapp
66128
env:
67129
BUILD_NUMBER: ${{ env.BUILD_NUMBER }}
@@ -72,18 +134,57 @@ jobs:
72134
API_KEY_ID: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_KEY_ID }}
73135
API_KEY_ISSUER_ID: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
74136
API_KEY_PASSWORD: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_PASSWORD }}
137+
# The lane rebuilds and re-syncs the web bundle before archiving, so the
138+
# signing key must be present here too — otherwise the archived binary
139+
# would accept unsigned live updates.
140+
CAPGO_PUBLIC_KEY: ${{ vars.CAPGO_PUBLIC_KEY }}
141+
CAPGO_REQUIRE_SIGNING: "true"
75142
run: bundle exec fastlane build
76143

77144
- name: Upload to TestFlight (Fastlane)
145+
if: inputs.destination == 'testflight'
78146
working-directory: standalone/webapp
79147
env:
80148
API_KEY_ID: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_KEY_ID }}
81149
API_KEY_ISSUER_ID: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
82150
API_KEY_PASSWORD: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_PASSWORD }}
83151
run: bundle exec fastlane release
84152

153+
- name: Upload App Store metadata and screenshots (Fastlane)
154+
if: inputs.destination == 'app-store-assets'
155+
working-directory: standalone/webapp
156+
env:
157+
APP_STORE_SCREENSHOT_STYLE: ${{ inputs.screenshot_style }}
158+
API_KEY_ID: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_KEY_ID }}
159+
API_KEY_ISSUER_ID: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
160+
API_KEY_PASSWORD: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_PASSWORD }}
161+
# Optional: App Review contact. Unset secrets are skipped, leaving the
162+
# existing App Store Connect values untouched.
163+
APP_REVIEW_FIRST_NAME: ${{ secrets.IOS_APP_REVIEW_FIRST_NAME }}
164+
APP_REVIEW_LAST_NAME: ${{ secrets.IOS_APP_REVIEW_LAST_NAME }}
165+
APP_REVIEW_EMAIL: ${{ secrets.IOS_APP_REVIEW_EMAIL }}
166+
APP_REVIEW_PHONE: ${{ secrets.IOS_APP_REVIEW_PHONE }}
167+
run: bundle exec fastlane store_assets
168+
169+
- name: Upload App Store build, metadata, and screenshots (Fastlane)
170+
if: inputs.destination == 'app-store'
171+
working-directory: standalone/webapp
172+
env:
173+
APP_STORE_SCREENSHOT_STYLE: ${{ inputs.screenshot_style }}
174+
API_KEY_ID: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_KEY_ID }}
175+
API_KEY_ISSUER_ID: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
176+
API_KEY_PASSWORD: ${{ secrets.IOS_APP_STORE_CONNECT_API_KEY_PASSWORD }}
177+
SUBMIT_FOR_REVIEW: ${{ inputs.submit_for_review }}
178+
# Optional: App Review contact. Unset secrets are skipped, leaving the
179+
# existing App Store Connect values untouched.
180+
APP_REVIEW_FIRST_NAME: ${{ secrets.IOS_APP_REVIEW_FIRST_NAME }}
181+
APP_REVIEW_LAST_NAME: ${{ secrets.IOS_APP_REVIEW_LAST_NAME }}
182+
APP_REVIEW_EMAIL: ${{ secrets.IOS_APP_REVIEW_EMAIL }}
183+
APP_REVIEW_PHONE: ${{ secrets.IOS_APP_REVIEW_PHONE }}
184+
run: bundle exec fastlane release_app_store
185+
85186
- name: Upload IPA artifact
86-
if: always()
187+
if: always() && inputs.destination != 'app-store-assets'
87188
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
88189
with:
89190
name: ios-ipa

.github/workflows/pr-health-checks.yml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -393,18 +393,30 @@ jobs:
393393
run: pnpm --filter @tumaet/apollon run test
394394

395395
- name: Verify ESM exports-map resolution
396-
# The library is ESM-only. `import.meta.resolve` (sync, no side
397-
# effects) validates every subpath in the exports map — actually
398-
# evaluating the module would require jsdom.
396+
# The library is ESM-only. `import.meta.resolve` validates every
397+
# subpath in the exports map. The model-only entry is intentionally
398+
# DOM-free; the follow-up check evaluates its complete runtime graph.
399399
working-directory: standalone/server
400400
run: |
401401
node --input-type=module -e '
402402
const root = import.meta.resolve("@tumaet/apollon");
403403
const internals = import.meta.resolve("@tumaet/apollon/internals");
404404
const exportEntry = import.meta.resolve("@tumaet/apollon/export");
405+
const model = import.meta.resolve("@tumaet/apollon/model");
405406
const css = import.meta.resolve("@tumaet/apollon/style.css");
406-
console.log({ root, internals, exportEntry, css });
407+
const schema = import.meta.resolve("@tumaet/apollon/schema");
408+
const packageJson = import.meta.resolve("@tumaet/apollon/package.json");
409+
console.log({
410+
root,
411+
internals,
412+
exportEntry,
413+
model,
414+
css,
415+
schema,
416+
packageJson,
417+
});
407418
'
419+
node ../../scripts/check-model-entry.mjs
408420
409421
- name: Lint published package shape (publint)
410422
working-directory: library

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ android/
6363
**/fastlane/README.md
6464
**/fastlane/test_output
6565
**/fastlane/screenshots
66+
**/fastlane/screenshots-framed
67+
**/fastlane/screenshots-preview
68+
**/fastlane/screenshots-review.html
69+
**/fastlane/device-frames
70+
**/.DerivedData*/
6671

6772
# Capacitor generated icons
6873
icons/
@@ -79,3 +84,6 @@ docs/build/
7984

8085
# Temp dir used by scripts/check-doc-snippets.mjs (removed on each run)
8186
docs/.snippet-typecheck/
87+
88+
# Live-update publish artifacts (built by scripts/build-live-update.mjs)
89+
**/live-updates-dist/

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ ios/
77
.docusaurus/
88
**/playwright-report/
99
**/test-results/
10+
**/fastlane/README.md
1011
pnpm-lock.yaml
1112

1213
# Generated by the TanStack Router plugin (committed, not hand-formatted).

0 commit comments

Comments
 (0)