lecodes-cli 0.18.2 → 0.19.2
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/dist/index.js +1866 -301
- package/package.json +14 -12
- package/runtime/scene-harness.json +1 -1
- package/runtime/sdk-types.json +1 -1
- package/src/api.ts +302 -0
- package/src/browserAuth.ts +87 -0
- package/src/cmgenTool.ts +104 -0
- package/src/commands/app.ts +891 -0
- package/src/commands/appAndroid.ts +603 -0
- package/src/commands/appDesktop.ts +326 -0
- package/src/commands/appDesktopMac.ts +470 -0
- package/src/commands/appIcon.ts +187 -0
- package/src/commands/appShared.ts +448 -0
- package/src/commands/appTemplates.ts +883 -0
- package/src/commands/appTemplatesAndroid.ts +599 -0
- package/src/commands/appTemplatesGradlew.ts +9 -0
- package/src/commands/assets.ts +28 -0
- package/src/commands/clone.ts +60 -0
- package/src/commands/compile.ts +253 -0
- package/src/commands/create.ts +59 -0
- package/src/commands/design.ts +863 -0
- package/src/commands/designTemplates.ts +11 -0
- package/src/commands/desktop.ts +122 -0
- package/src/commands/dev.ts +214 -0
- package/src/commands/diff.ts +59 -0
- package/src/commands/init.ts +191 -0
- package/src/commands/install.ts +198 -0
- package/src/commands/lightmap.ts +290 -0
- package/src/commands/link.ts +147 -0
- package/src/commands/login.ts +24 -0
- package/src/commands/navmesh.ts +225 -0
- package/src/commands/pn.ts +305 -0
- package/src/commands/projectTemplates.ts +129 -0
- package/src/commands/pull.ts +109 -0
- package/src/commands/push.ts +173 -0
- package/src/commands/render.ts +414 -0
- package/src/commands/scene.ts +148 -0
- package/src/commands/shaders.ts +157 -0
- package/src/commands/status.ts +29 -0
- package/src/commands/test.ts +370 -0
- package/src/commands/thumbs.ts +178 -0
- package/src/commands/types.ts +87 -0
- package/src/commands/update.ts +190 -0
- package/src/compile/assetIcons.ts +214 -0
- package/src/compile/collect.ts +46 -0
- package/src/compile/collectLocal.ts +37 -0
- package/src/compile/designCompile.ts +104 -0
- package/src/compile/fonts.ts +156 -0
- package/src/compile/headlessBundle.ts +129 -0
- package/src/compile/nativeStack.ts +21 -0
- package/src/compile/projectCompile.ts +109 -0
- package/src/compile/sceneCompile.ts +113 -0
- package/src/compile/screenEntry.ts +127 -0
- package/src/compile/shaders.ts +245 -0
- package/src/config.ts +42 -0
- package/src/designMeta.ts +35 -0
- package/src/desktopRenderer.ts +532 -0
- package/src/desktopScript.ts +276 -0
- package/src/dev/clientTemplates.ts +160 -0
- package/src/dev/devServer.ts +292 -0
- package/src/dev/wsServer.ts +144 -0
- package/src/distRoot.ts +20 -0
- package/src/ignore.ts +163 -0
- package/src/index.ts +491 -0
- package/src/lecodes-3d-editor.d.ts +41 -0
- package/src/lecodes-assets.d.ts +7 -0
- package/src/lecodes-design.d.ts +191 -0
- package/src/lecodes-renderer.d.ts +131 -0
- package/src/localFiles.ts +144 -0
- package/src/manifest.ts +46 -0
- package/src/matcTool.ts +137 -0
- package/src/peers.ts +40 -0
- package/src/project.ts +61 -0
- package/src/projectEnv.ts +94 -0
- package/src/qrcode-terminal.d.ts +9 -0
- package/src/releases.ts +125 -0
- package/src/serverDiff.ts +78 -0
- package/src/textDiff.ts +103 -0
- package/src/types.ts +0 -0
- package/src/util.ts +146 -0
- package/runtime/sdk/animate/animate.ts +0 -238
- package/runtime/sdk/animate/bezier.ts +0 -138
- package/runtime/sdk/animate/easings.ts +0 -126
- package/runtime/sdk/canvas/Canvas.ts +0 -305
- package/runtime/sdk/core/Aspect.ts +0 -512
- package/runtime/sdk/core/InspectorUI.ts +0 -212
- package/runtime/sdk/core/color.ts +0 -66
- package/runtime/sdk/core/compWrite.ts +0 -42
- package/runtime/sdk/core/events.ts +0 -38
- package/runtime/sdk/core/fields.ts +0 -120
- package/runtime/sdk/core/registry.ts +0 -23
- package/runtime/sdk/core/signals.ts +0 -277
- package/runtime/sdk/core/time.ts +0 -81
- package/runtime/sdk/g2/Camera2D.ts +0 -40
- package/runtime/sdk/g2/CharacterController2D.ts +0 -276
- package/runtime/sdk/g2/Node2D.ts +0 -267
- package/runtime/sdk/g2/OneWay2D.ts +0 -66
- package/runtime/sdk/g2/Physics2D.ts +0 -346
- package/runtime/sdk/g2/Scene2D.ts +0 -209
- package/runtime/sdk/g2/Shape2D.ts +0 -259
- package/runtime/sdk/g2/Sprite.ts +0 -89
- package/runtime/sdk/g2/SpriteAnimation.ts +0 -171
- package/runtime/sdk/g2/SpriteSheet.ts +0 -166
- package/runtime/sdk/g2/Texture2D.ts +0 -47
- package/runtime/sdk/g2/Tilemap.ts +0 -41
- package/runtime/sdk/g2/Tileset.ts +0 -71
- package/runtime/sdk/g2/Trigger2D.ts +0 -77
- package/runtime/sdk/g2/autotile.ts +0 -433
- package/runtime/sdk/g2/cells.ts +0 -91
- package/runtime/sdk/g2/defineScene2d.ts +0 -381
- package/runtime/sdk/g2/groups2d.ts +0 -106
- package/runtime/sdk/g2/loop.ts +0 -50
- package/runtime/sdk/g2/scenarios2d.ts +0 -69
- package/runtime/sdk/g2/touch.ts +0 -83
- package/runtime/sdk/gl/Camera.ts +0 -160
- package/runtime/sdk/gl/CameraPlace.ts +0 -52
- package/runtime/sdk/gl/CharacterController.ts +0 -238
- package/runtime/sdk/gl/Gearbox.ts +0 -212
- package/runtime/sdk/gl/Geometry.ts +0 -279
- package/runtime/sdk/gl/IK.ts +0 -193
- package/runtime/sdk/gl/InstancedMesh.ts +0 -132
- package/runtime/sdk/gl/Light.ts +0 -99
- package/runtime/sdk/gl/Lightmap.ts +0 -179
- package/runtime/sdk/gl/Material.ts +0 -245
- package/runtime/sdk/gl/Mesh.ts +0 -83
- package/runtime/sdk/gl/Model.ts +0 -64
- package/runtime/sdk/gl/Node.ts +0 -350
- package/runtime/sdk/gl/Noise.ts +0 -30
- package/runtime/sdk/gl/Particles.ts +0 -676
- package/runtime/sdk/gl/Physics.ts +0 -222
- package/runtime/sdk/gl/Plane.ts +0 -53
- package/runtime/sdk/gl/Ray.ts +0 -16
- package/runtime/sdk/gl/Scene.ts +0 -479
- package/runtime/sdk/gl/Shape.ts +0 -377
- package/runtime/sdk/gl/Texture.ts +0 -46
- package/runtime/sdk/gl/Trigger.ts +0 -45
- package/runtime/sdk/gl/Vehicle.ts +0 -473
- package/runtime/sdk/gl/Wheel.ts +0 -240
- package/runtime/sdk/gl/animation/AnimationClip.ts +0 -204
- package/runtime/sdk/gl/animation/Animator.ts +0 -87
- package/runtime/sdk/gl/animation/Layer.ts +0 -29
- package/runtime/sdk/gl/animation/Loop.ts +0 -25
- package/runtime/sdk/gl/animation/Playback.ts +0 -43
- package/runtime/sdk/gl/animation/core.ts +0 -294
- package/runtime/sdk/gl/controls.ts +0 -95
- package/runtime/sdk/gl/physicsEvents.ts +0 -20
- package/runtime/sdk/gl/scenarios.ts +0 -291
- package/runtime/sdk/gl/state.ts +0 -6
- package/runtime/sdk/gl/touch.ts +0 -68
- package/runtime/sdk/inject.ts +0 -186
- package/runtime/sdk/math/Mathf.ts +0 -118
- package/runtime/sdk/math/mat4.ts +0 -278
- package/runtime/sdk/math/quat.ts +0 -232
- package/runtime/sdk/math/vec.ts +0 -255
- package/runtime/sdk/plugins/camera.ts +0 -81
- package/runtime/sdk/plugins/geolocation.ts +0 -123
- package/runtime/sdk/plugins/oauth.ts +0 -61
- package/runtime/sdk/plugins/permission.ts +0 -7
- package/runtime/sdk/plugins/push.ts +0 -132
- package/runtime/sdk/plugins/qr.ts +0 -73
- package/runtime/sdk/plugins/service.ts +0 -47
- package/runtime/sdk/runtime/app.ts +0 -101
- package/runtime/sdk/runtime/appEvents.ts +0 -54
- package/runtime/sdk/runtime/channel.ts +0 -61
- package/runtime/sdk/runtime/clipboard.ts +0 -20
- package/runtime/sdk/runtime/datetime.ts +0 -329
- package/runtime/sdk/runtime/device.ts +0 -293
- package/runtime/sdk/runtime/fetch.ts +0 -77
- package/runtime/sdk/runtime/files.ts +0 -23
- package/runtime/sdk/runtime/input.ts +0 -175
- package/runtime/sdk/runtime/media.ts +0 -111
- package/runtime/sdk/runtime/misc.ts +0 -16
- package/runtime/sdk/runtime/net.ts +0 -36
- package/runtime/sdk/runtime/rpc.ts +0 -218
- package/runtime/sdk/runtime/service.ts +0 -83
- package/runtime/sdk/runtime/share.ts +0 -9
- package/runtime/sdk/runtime/storage.ts +0 -13
- package/runtime/sdk/runtime/touch.ts +0 -76
- package/runtime/sdk/scene/defineScene.ts +0 -1227
- package/runtime/sdk/scene/editorPlugins.ts +0 -92
- package/runtime/sdk/scene/gizmos.ts +0 -148
- package/runtime/sdk/scene/grammar.ts +0 -120
- package/runtime/sdk/scene/material.ts +0 -188
- package/runtime/sdk/server/auth/appConfig.ts +0 -12
- package/runtime/sdk/server/auth/global.ts +0 -80
- package/runtime/sdk/server/auth/host.ts +0 -318
- package/runtime/sdk/server/auth/models.ts +0 -83
- package/runtime/sdk/server/auth/types.ts +0 -50
- package/runtime/sdk/server/channel.ts +0 -56
- package/runtime/sdk/server/context.ts +0 -36
- package/runtime/sdk/server/db/defineDb.ts +0 -237
- package/runtime/sdk/server/db/fields.ts +0 -132
- package/runtime/sdk/server/db/httpTransport.ts +0 -93
- package/runtime/sdk/server/db/index.ts +0 -7
- package/runtime/sdk/server/db/marci/query.ts +0 -412
- package/runtime/sdk/server/db/types.ts +0 -202
- package/runtime/sdk/server/errors.ts +0 -12
- package/runtime/sdk/server/host.ts +0 -74
- package/runtime/sdk/server/inject.ts +0 -13
- package/runtime/sdk/server/runtime.ts +0 -133
- package/runtime/sdk/server/validate.ts +0 -87
- package/runtime/sdk/ui/NativeView.ts +0 -142
- package/runtime/sdk/ui/UI.ts +0 -39
- package/runtime/sdk/ui/UIBottomSheet.ts +0 -139
- package/runtime/sdk/ui/UIButton.ts +0 -101
- package/runtime/sdk/ui/UIContainer.ts +0 -60
- package/runtime/sdk/ui/UIImage.ts +0 -83
- package/runtime/sdk/ui/UIInput.ts +0 -185
- package/runtime/sdk/ui/UIModal.ts +0 -139
- package/runtime/sdk/ui/UINode.ts +0 -826
- package/runtime/sdk/ui/UIPager.ts +0 -362
- package/runtime/sdk/ui/UIPopover.ts +0 -100
- package/runtime/sdk/ui/UIScreen.ts +0 -123
- package/runtime/sdk/ui/UIScrollable.ts +0 -87
- package/runtime/sdk/ui/UISpacer.ts +0 -14
- package/runtime/sdk/ui/UITabs.ts +0 -236
- package/runtime/sdk/ui/UIText.ts +0 -51
- package/runtime/sdk/ui/UIVideo.ts +0 -88
- package/runtime/sdk/ui/UIVirtualizedList.ts +0 -241
- package/runtime/sdk/ui/UIWidget.ts +0 -127
- package/runtime/sdk/ui/fonts.ts +0 -13
- package/runtime/sdk/ui/presentable.ts +0 -117
- package/runtime/sdk/ui/router.ts +0 -132
- package/runtime/sdk/ui/theme.ts +0 -84
|
@@ -0,0 +1,883 @@
|
|
|
1
|
+
/* Templates for `lecodes app init ios` / `lecodes app sync` — distilled 1:1 from the
|
|
2
|
+
* hand-built, device-verified reference shell (docs/xcode-app-plan.md). Three ownership
|
|
3
|
+
* tiers: App/ Swift files are USER-owned after generation (init writes once, sync never
|
|
4
|
+
* touches them); Info.plist, the LeCodesRuntime package, Resources/ and the shell README
|
|
5
|
+
* are CLI-owned (sync regenerates); the pbxproj is written once at init — sync only restamps the
|
|
6
|
+
* MARKETING_VERSION / CURRENT_PROJECT_VERSION values (no structural edits, ever). */
|
|
7
|
+
|
|
8
|
+
export interface ShellIdentity {
|
|
9
|
+
displayName: string
|
|
10
|
+
bundleId: string
|
|
11
|
+
teamId: string
|
|
12
|
+
version: string
|
|
13
|
+
buildNumber: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Escape a value for a double-quoted pbxproj string. */
|
|
17
|
+
const pbxStr = (s: string) => s.replace(/[\\"]/g, m => "\\" + m)
|
|
18
|
+
|
|
19
|
+
export const pbxprojTemplate = ({ displayName, bundleId, teamId, version, buildNumber }: ShellIdentity): string => {
|
|
20
|
+
const target = `
|
|
21
|
+
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
22
|
+
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
|
23
|
+
CODE_SIGN_ENTITLEMENTS = "App/App.entitlements";
|
|
24
|
+
CODE_SIGN_STYLE = Automatic;
|
|
25
|
+
CURRENT_PROJECT_VERSION = ${buildNumber};
|
|
26
|
+
DEVELOPMENT_TEAM = "${pbxStr(teamId)}";
|
|
27
|
+
GENERATE_INFOPLIST_FILE = YES;
|
|
28
|
+
INFOPLIST_FILE = "App/Info.plist";
|
|
29
|
+
INFOPLIST_KEY_CFBundleDisplayName = "${pbxStr(displayName)}";
|
|
30
|
+
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
|
31
|
+
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
|
32
|
+
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
|
33
|
+
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
|
34
|
+
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
|
35
|
+
LD_RUNPATH_SEARCH_PATHS = (
|
|
36
|
+
"$(inherited)",
|
|
37
|
+
"@executable_path/Frameworks",
|
|
38
|
+
);
|
|
39
|
+
MARKETING_VERSION = ${version};
|
|
40
|
+
PRODUCT_BUNDLE_IDENTIFIER = "${pbxStr(bundleId)}";
|
|
41
|
+
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
42
|
+
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
|
43
|
+
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
|
44
|
+
SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor;
|
|
45
|
+
SWIFT_EMIT_LOC_STRINGS = YES;
|
|
46
|
+
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
|
47
|
+
SWIFT_VERSION = 5.0;
|
|
48
|
+
TARGETED_DEVICE_FAMILY = "1,2";`
|
|
49
|
+
|
|
50
|
+
const project = (debug: boolean) => `
|
|
51
|
+
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
52
|
+
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
|
53
|
+
CLANG_ANALYZER_NONNULL = YES;
|
|
54
|
+
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
|
55
|
+
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
|
56
|
+
CLANG_ENABLE_MODULES = YES;
|
|
57
|
+
CLANG_ENABLE_OBJC_ARC = YES;
|
|
58
|
+
CLANG_ENABLE_OBJC_WEAK = YES;
|
|
59
|
+
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
|
60
|
+
CLANG_WARN_BOOL_CONVERSION = YES;
|
|
61
|
+
CLANG_WARN_COMMA = YES;
|
|
62
|
+
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
63
|
+
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
|
64
|
+
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
65
|
+
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
|
66
|
+
CLANG_WARN_EMPTY_BODY = YES;
|
|
67
|
+
CLANG_WARN_ENUM_CONVERSION = YES;
|
|
68
|
+
CLANG_WARN_INFINITE_RECURSION = YES;
|
|
69
|
+
CLANG_WARN_INT_CONVERSION = YES;
|
|
70
|
+
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
|
71
|
+
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
|
72
|
+
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
73
|
+
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
|
74
|
+
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
|
75
|
+
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
|
76
|
+
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
|
77
|
+
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
|
78
|
+
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
|
79
|
+
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
80
|
+
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
|
81
|
+
COPY_PHASE_STRIP = NO;
|
|
82
|
+
DEBUG_INFORMATION_FORMAT = ${debug ? "dwarf" : "\"dwarf-with-dsym\""};
|
|
83
|
+
DEVELOPMENT_TEAM = "${pbxStr(teamId)}";${debug ? "" : `
|
|
84
|
+
ENABLE_NS_ASSERTIONS = NO;`}
|
|
85
|
+
ENABLE_STRICT_OBJC_MSGSEND = YES;${debug ? `
|
|
86
|
+
ENABLE_TESTABILITY = YES;` : ""}
|
|
87
|
+
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
|
88
|
+
GCC_C_LANGUAGE_STANDARD = gnu17;${debug ? `
|
|
89
|
+
GCC_DYNAMIC_NO_PIC = NO;` : ""}
|
|
90
|
+
GCC_NO_COMMON_BLOCKS = YES;${debug ? `
|
|
91
|
+
GCC_OPTIMIZATION_LEVEL = 0;
|
|
92
|
+
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
93
|
+
"DEBUG=1",
|
|
94
|
+
"$(inherited)",
|
|
95
|
+
);` : ""}
|
|
96
|
+
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
|
97
|
+
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
98
|
+
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
|
99
|
+
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
100
|
+
GCC_WARN_UNUSED_FUNCTION = YES;
|
|
101
|
+
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
102
|
+
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
|
103
|
+
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
|
104
|
+
MTL_ENABLE_DEBUG_INFO = ${debug ? "INCLUDE_SOURCE" : "NO"};
|
|
105
|
+
MTL_FAST_MATH = YES;${debug ? `
|
|
106
|
+
ONLY_ACTIVE_ARCH = YES;` : ""}
|
|
107
|
+
SDKROOT = iphoneos;${debug ? `
|
|
108
|
+
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
|
109
|
+
SWIFT_OPTIMIZATION_LEVEL = "-Onone";` : `
|
|
110
|
+
SWIFT_COMPILATION_MODE = wholemodule;
|
|
111
|
+
VALIDATE_PRODUCT = YES;`}`
|
|
112
|
+
|
|
113
|
+
return `// !$*UTF8*$!
|
|
114
|
+
{
|
|
115
|
+
archiveVersion = 1;
|
|
116
|
+
classes = {
|
|
117
|
+
};
|
|
118
|
+
objectVersion = 77;
|
|
119
|
+
objects = {
|
|
120
|
+
|
|
121
|
+
/* Begin PBXBuildFile section */
|
|
122
|
+
B73550812FEBAC710005B4CC /* LeCodesRuntime in Frameworks */ = {isa = PBXBuildFile; productRef = B73550802FEBAC710005B4CC /* LeCodesRuntime */; };
|
|
123
|
+
/* End PBXBuildFile section */
|
|
124
|
+
|
|
125
|
+
/* Begin PBXFileReference section */
|
|
126
|
+
B73550672FEBAC0F0005B4CC /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
127
|
+
/* End PBXFileReference section */
|
|
128
|
+
|
|
129
|
+
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
|
130
|
+
B73550792FEBAC100005B4CC /* Exceptions for "App" folder in "App" target */ = {
|
|
131
|
+
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
|
132
|
+
membershipExceptions = (
|
|
133
|
+
App.entitlements,
|
|
134
|
+
Info.plist,
|
|
135
|
+
);
|
|
136
|
+
target = B73550662FEBAC0F0005B4CC /* App */;
|
|
137
|
+
};
|
|
138
|
+
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
|
139
|
+
|
|
140
|
+
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
|
141
|
+
B73550692FEBAC0F0005B4CC /* App */ = {
|
|
142
|
+
isa = PBXFileSystemSynchronizedRootGroup;
|
|
143
|
+
exceptions = (
|
|
144
|
+
B73550792FEBAC100005B4CC /* Exceptions for "App" folder in "App" target */,
|
|
145
|
+
);
|
|
146
|
+
path = App;
|
|
147
|
+
sourceTree = "<group>";
|
|
148
|
+
};
|
|
149
|
+
/* End PBXFileSystemSynchronizedRootGroup section */
|
|
150
|
+
|
|
151
|
+
/* Begin PBXFrameworksBuildPhase section */
|
|
152
|
+
B73550642FEBAC0F0005B4CC /* Frameworks */ = {
|
|
153
|
+
isa = PBXFrameworksBuildPhase;
|
|
154
|
+
buildActionMask = 2147483647;
|
|
155
|
+
files = (
|
|
156
|
+
B73550812FEBAC710005B4CC /* LeCodesRuntime in Frameworks */,
|
|
157
|
+
);
|
|
158
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
159
|
+
};
|
|
160
|
+
/* End PBXFrameworksBuildPhase section */
|
|
161
|
+
|
|
162
|
+
/* Begin PBXGroup section */
|
|
163
|
+
B735505E2FEBAC0F0005B4CC = {
|
|
164
|
+
isa = PBXGroup;
|
|
165
|
+
children = (
|
|
166
|
+
B73550692FEBAC0F0005B4CC /* App */,
|
|
167
|
+
B73550682FEBAC0F0005B4CC /* Products */,
|
|
168
|
+
);
|
|
169
|
+
sourceTree = "<group>";
|
|
170
|
+
};
|
|
171
|
+
B73550682FEBAC0F0005B4CC /* Products */ = {
|
|
172
|
+
isa = PBXGroup;
|
|
173
|
+
children = (
|
|
174
|
+
B73550672FEBAC0F0005B4CC /* App.app */,
|
|
175
|
+
);
|
|
176
|
+
name = Products;
|
|
177
|
+
sourceTree = "<group>";
|
|
178
|
+
};
|
|
179
|
+
/* End PBXGroup section */
|
|
180
|
+
|
|
181
|
+
/* Begin PBXNativeTarget section */
|
|
182
|
+
B73550662FEBAC0F0005B4CC /* App */ = {
|
|
183
|
+
isa = PBXNativeTarget;
|
|
184
|
+
buildConfigurationList = B735507A2FEBAC100005B4CC /* Build configuration list for PBXNativeTarget "App" */;
|
|
185
|
+
buildPhases = (
|
|
186
|
+
B73550632FEBAC0F0005B4CC /* Sources */,
|
|
187
|
+
B73550642FEBAC0F0005B4CC /* Frameworks */,
|
|
188
|
+
B73550652FEBAC0F0005B4CC /* Resources */,
|
|
189
|
+
);
|
|
190
|
+
buildRules = (
|
|
191
|
+
);
|
|
192
|
+
dependencies = (
|
|
193
|
+
);
|
|
194
|
+
fileSystemSynchronizedGroups = (
|
|
195
|
+
B73550692FEBAC0F0005B4CC /* App */,
|
|
196
|
+
);
|
|
197
|
+
name = App;
|
|
198
|
+
packageProductDependencies = (
|
|
199
|
+
B73550802FEBAC710005B4CC /* LeCodesRuntime */,
|
|
200
|
+
);
|
|
201
|
+
productName = App;
|
|
202
|
+
productReference = B73550672FEBAC0F0005B4CC /* App.app */;
|
|
203
|
+
productType = "com.apple.product-type.application";
|
|
204
|
+
};
|
|
205
|
+
/* End PBXNativeTarget section */
|
|
206
|
+
|
|
207
|
+
/* Begin PBXProject section */
|
|
208
|
+
B735505F2FEBAC0F0005B4CC /* Project object */ = {
|
|
209
|
+
isa = PBXProject;
|
|
210
|
+
attributes = {
|
|
211
|
+
BuildIndependentTargetsInParallel = 1;
|
|
212
|
+
LastSwiftUpdateCheck = 2650;
|
|
213
|
+
LastUpgradeCheck = 2650;
|
|
214
|
+
TargetAttributes = {
|
|
215
|
+
B73550662FEBAC0F0005B4CC = {
|
|
216
|
+
CreatedOnToolsVersion = 26.5;
|
|
217
|
+
};
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
buildConfigurationList = B73550622FEBAC0F0005B4CC /* Build configuration list for PBXProject "App" */;
|
|
221
|
+
developmentRegion = en;
|
|
222
|
+
hasScannedForEncodings = 0;
|
|
223
|
+
knownRegions = (
|
|
224
|
+
en,
|
|
225
|
+
Base,
|
|
226
|
+
);
|
|
227
|
+
mainGroup = B735505E2FEBAC0F0005B4CC;
|
|
228
|
+
minimizedProjectReferenceProxies = 1;
|
|
229
|
+
packageReferences = (
|
|
230
|
+
B73550822FEBAC720005B4CC /* XCLocalSwiftPackageReference "LeCodesRuntime" */,
|
|
231
|
+
);
|
|
232
|
+
preferredProjectObjectVersion = 77;
|
|
233
|
+
productRefGroup = B73550682FEBAC0F0005B4CC /* Products */;
|
|
234
|
+
projectDirPath = "";
|
|
235
|
+
projectRoot = "";
|
|
236
|
+
targets = (
|
|
237
|
+
B73550662FEBAC0F0005B4CC /* App */,
|
|
238
|
+
);
|
|
239
|
+
};
|
|
240
|
+
/* End PBXProject section */
|
|
241
|
+
|
|
242
|
+
/* Begin PBXResourcesBuildPhase section */
|
|
243
|
+
B73550652FEBAC0F0005B4CC /* Resources */ = {
|
|
244
|
+
isa = PBXResourcesBuildPhase;
|
|
245
|
+
buildActionMask = 2147483647;
|
|
246
|
+
files = (
|
|
247
|
+
);
|
|
248
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
249
|
+
};
|
|
250
|
+
/* End PBXResourcesBuildPhase section */
|
|
251
|
+
|
|
252
|
+
/* Begin PBXSourcesBuildPhase section */
|
|
253
|
+
B73550632FEBAC0F0005B4CC /* Sources */ = {
|
|
254
|
+
isa = PBXSourcesBuildPhase;
|
|
255
|
+
buildActionMask = 2147483647;
|
|
256
|
+
files = (
|
|
257
|
+
);
|
|
258
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
259
|
+
};
|
|
260
|
+
/* End PBXSourcesBuildPhase section */
|
|
261
|
+
|
|
262
|
+
/* Begin XCBuildConfiguration section */
|
|
263
|
+
B735507B2FEBAC100005B4CC /* Debug */ = {
|
|
264
|
+
isa = XCBuildConfiguration;
|
|
265
|
+
buildSettings = {${target}
|
|
266
|
+
};
|
|
267
|
+
name = Debug;
|
|
268
|
+
};
|
|
269
|
+
B735507C2FEBAC100005B4CC /* Release */ = {
|
|
270
|
+
isa = XCBuildConfiguration;
|
|
271
|
+
buildSettings = {${target}
|
|
272
|
+
};
|
|
273
|
+
name = Release;
|
|
274
|
+
};
|
|
275
|
+
B735507D2FEBAC100005B4CC /* Debug */ = {
|
|
276
|
+
isa = XCBuildConfiguration;
|
|
277
|
+
buildSettings = {${project(true)}
|
|
278
|
+
};
|
|
279
|
+
name = Debug;
|
|
280
|
+
};
|
|
281
|
+
B735507E2FEBAC100005B4CC /* Release */ = {
|
|
282
|
+
isa = XCBuildConfiguration;
|
|
283
|
+
buildSettings = {${project(false)}
|
|
284
|
+
};
|
|
285
|
+
name = Release;
|
|
286
|
+
};
|
|
287
|
+
/* End XCBuildConfiguration section */
|
|
288
|
+
|
|
289
|
+
/* Begin XCConfigurationList section */
|
|
290
|
+
B73550622FEBAC0F0005B4CC /* Build configuration list for PBXProject "App" */ = {
|
|
291
|
+
isa = XCConfigurationList;
|
|
292
|
+
buildConfigurations = (
|
|
293
|
+
B735507D2FEBAC100005B4CC /* Debug */,
|
|
294
|
+
B735507E2FEBAC100005B4CC /* Release */,
|
|
295
|
+
);
|
|
296
|
+
defaultConfigurationIsVisible = 0;
|
|
297
|
+
defaultConfigurationName = Release;
|
|
298
|
+
};
|
|
299
|
+
B735507A2FEBAC100005B4CC /* Build configuration list for PBXNativeTarget "App" */ = {
|
|
300
|
+
isa = XCConfigurationList;
|
|
301
|
+
buildConfigurations = (
|
|
302
|
+
B735507B2FEBAC100005B4CC /* Debug */,
|
|
303
|
+
B735507C2FEBAC100005B4CC /* Release */,
|
|
304
|
+
);
|
|
305
|
+
defaultConfigurationIsVisible = 0;
|
|
306
|
+
defaultConfigurationName = Release;
|
|
307
|
+
};
|
|
308
|
+
/* End XCConfigurationList section */
|
|
309
|
+
|
|
310
|
+
/* Begin XCLocalSwiftPackageReference section */
|
|
311
|
+
B73550822FEBAC720005B4CC /* XCLocalSwiftPackageReference "LeCodesRuntime" */ = {
|
|
312
|
+
isa = XCLocalSwiftPackageReference;
|
|
313
|
+
relativePath = LeCodesRuntime;
|
|
314
|
+
};
|
|
315
|
+
/* End XCLocalSwiftPackageReference section */
|
|
316
|
+
|
|
317
|
+
/* Begin XCSwiftPackageProductDependency section */
|
|
318
|
+
B73550802FEBAC710005B4CC /* LeCodesRuntime */ = {
|
|
319
|
+
isa = XCSwiftPackageProductDependency;
|
|
320
|
+
productName = LeCodesRuntime;
|
|
321
|
+
};
|
|
322
|
+
/* End XCSwiftPackageProductDependency section */
|
|
323
|
+
};
|
|
324
|
+
rootObject = B735505F2FEBAC0F0005B4CC /* Project object */;
|
|
325
|
+
}
|
|
326
|
+
`
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export const SCHEME_XML = `<?xml version="1.0" encoding="UTF-8"?>
|
|
330
|
+
<Scheme
|
|
331
|
+
LastUpgradeVersion = "2650"
|
|
332
|
+
version = "1.7">
|
|
333
|
+
<BuildAction
|
|
334
|
+
parallelizeBuildables = "YES"
|
|
335
|
+
buildImplicitDependencies = "YES">
|
|
336
|
+
<BuildActionEntries>
|
|
337
|
+
<BuildActionEntry
|
|
338
|
+
buildForTesting = "YES"
|
|
339
|
+
buildForRunning = "YES"
|
|
340
|
+
buildForProfiling = "YES"
|
|
341
|
+
buildForArchiving = "YES"
|
|
342
|
+
buildForAnalyzing = "YES">
|
|
343
|
+
<BuildableReference
|
|
344
|
+
BuildableIdentifier = "primary"
|
|
345
|
+
BlueprintIdentifier = "B73550662FEBAC0F0005B4CC"
|
|
346
|
+
BuildableName = "App.app"
|
|
347
|
+
BlueprintName = "App"
|
|
348
|
+
ReferencedContainer = "container:App.xcodeproj">
|
|
349
|
+
</BuildableReference>
|
|
350
|
+
</BuildActionEntry>
|
|
351
|
+
</BuildActionEntries>
|
|
352
|
+
</BuildAction>
|
|
353
|
+
<TestAction
|
|
354
|
+
buildConfiguration = "Debug"
|
|
355
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
356
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
357
|
+
shouldUseLaunchSchemeArgsEnv = "YES">
|
|
358
|
+
<Testables>
|
|
359
|
+
</Testables>
|
|
360
|
+
</TestAction>
|
|
361
|
+
<LaunchAction
|
|
362
|
+
buildConfiguration = "Debug"
|
|
363
|
+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
364
|
+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
365
|
+
launchStyle = "0"
|
|
366
|
+
useCustomWorkingDirectory = "NO"
|
|
367
|
+
ignoresPersistentStateOnLaunch = "NO"
|
|
368
|
+
debugDocumentVersioning = "YES"
|
|
369
|
+
debugServiceExtension = "internal"
|
|
370
|
+
allowLocationSimulation = "YES">
|
|
371
|
+
<BuildableProductRunnable
|
|
372
|
+
runnableDebuggingMode = "0">
|
|
373
|
+
<BuildableReference
|
|
374
|
+
BuildableIdentifier = "primary"
|
|
375
|
+
BlueprintIdentifier = "B73550662FEBAC0F0005B4CC"
|
|
376
|
+
BuildableName = "App.app"
|
|
377
|
+
BlueprintName = "App"
|
|
378
|
+
ReferencedContainer = "container:App.xcodeproj">
|
|
379
|
+
</BuildableReference>
|
|
380
|
+
</BuildableProductRunnable>
|
|
381
|
+
</LaunchAction>
|
|
382
|
+
<ProfileAction
|
|
383
|
+
buildConfiguration = "Release"
|
|
384
|
+
shouldUseLaunchSchemeArgsEnv = "YES"
|
|
385
|
+
savedToolIdentifier = ""
|
|
386
|
+
useCustomWorkingDirectory = "NO"
|
|
387
|
+
debugDocumentVersioning = "YES">
|
|
388
|
+
<BuildableProductRunnable
|
|
389
|
+
runnableDebuggingMode = "0">
|
|
390
|
+
<BuildableReference
|
|
391
|
+
BuildableIdentifier = "primary"
|
|
392
|
+
BlueprintIdentifier = "B73550662FEBAC0F0005B4CC"
|
|
393
|
+
BuildableName = "App.app"
|
|
394
|
+
BlueprintName = "App"
|
|
395
|
+
ReferencedContainer = "container:App.xcodeproj">
|
|
396
|
+
</BuildableReference>
|
|
397
|
+
</BuildableProductRunnable>
|
|
398
|
+
</ProfileAction>
|
|
399
|
+
<AnalyzeAction
|
|
400
|
+
buildConfiguration = "Debug">
|
|
401
|
+
</AnalyzeAction>
|
|
402
|
+
<ArchiveAction
|
|
403
|
+
buildConfiguration = "Release"
|
|
404
|
+
revealArchiveInOrganizer = "YES">
|
|
405
|
+
</ArchiveAction>
|
|
406
|
+
</Scheme>
|
|
407
|
+
`
|
|
408
|
+
|
|
409
|
+
export const APP_DELEGATE = `//
|
|
410
|
+
// AppDelegate.swift
|
|
411
|
+
// Generated by lecodes app init — yours to edit.
|
|
412
|
+
//
|
|
413
|
+
|
|
414
|
+
import UIKit
|
|
415
|
+
import LeCodesRuntime
|
|
416
|
+
|
|
417
|
+
@main
|
|
418
|
+
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
419
|
+
|
|
420
|
+
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
421
|
+
// Plugin hook surface: installs the notification-center delegate (must be in
|
|
422
|
+
// place before the app finishes launching) and buffers launch-time events until
|
|
423
|
+
// a plugin that needs them registers. Inert if no installed plugin consumes it.
|
|
424
|
+
LeCodesAppHooks.install()
|
|
425
|
+
return true
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// APNs token callbacks → the plugin hook surface (consumed by the push plugin).
|
|
429
|
+
func application(_ application: UIApplication,
|
|
430
|
+
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
|
431
|
+
LeCodesAppHooks.remoteNotificationsToken(deviceToken)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
func application(_ application: UIApplication,
|
|
435
|
+
didFailToRegisterForRemoteNotificationsWithError error: Error) {
|
|
436
|
+
LeCodesAppHooks.remoteNotificationsError(error)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// MARK: UISceneSession Lifecycle
|
|
440
|
+
|
|
441
|
+
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
|
442
|
+
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
`
|
|
446
|
+
|
|
447
|
+
export const SCENE_DELEGATE = `//
|
|
448
|
+
// SceneDelegate.swift
|
|
449
|
+
// Generated by lecodes app init — yours to edit.
|
|
450
|
+
//
|
|
451
|
+
|
|
452
|
+
import UIKit
|
|
453
|
+
import LeCodesRuntime
|
|
454
|
+
|
|
455
|
+
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|
456
|
+
|
|
457
|
+
var window: UIWindow?
|
|
458
|
+
|
|
459
|
+
func scene(
|
|
460
|
+
_ scene: UIScene,
|
|
461
|
+
willConnectTo session: UISceneSession,
|
|
462
|
+
options connectionOptions: UIScene.ConnectionOptions
|
|
463
|
+
) {
|
|
464
|
+
guard let windowScene = (scene as? UIWindowScene) else { return }
|
|
465
|
+
|
|
466
|
+
// Cold-started by a notification tap: buffered by the hooks; a plugin that
|
|
467
|
+
// consumes it (push) drains the buffer when it registers — before the JS world
|
|
468
|
+
// boots, because makeKeyAndVisible() runs registerBundledPlugins via viewDidLoad.
|
|
469
|
+
if let response = connectionOptions.notificationResponse {
|
|
470
|
+
LeCodesAppHooks.coldStartNotification(response)
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
let window = UIWindow(windowScene: windowScene)
|
|
474
|
+
window.rootViewController = ViewController()
|
|
475
|
+
self.window = window
|
|
476
|
+
window.makeKeyAndVisible()
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
`
|
|
480
|
+
|
|
481
|
+
export const VIEW_CONTROLLER = `//
|
|
482
|
+
// ViewController.swift
|
|
483
|
+
// Generated by lecodes app init — yours to edit.
|
|
484
|
+
//
|
|
485
|
+
// Runs the bundled app.js (produced by \`lecodes app sync\`) offline: everything the
|
|
486
|
+
// script needs is provided by the SDK core (_creatorUI / _creatorUtils / console)
|
|
487
|
+
// plus the plugins registered below via LeCodesRuntime.
|
|
488
|
+
//
|
|
489
|
+
|
|
490
|
+
import UIKit
|
|
491
|
+
import LeCodesRuntime
|
|
492
|
+
|
|
493
|
+
class ViewController: LeCodesViewController {
|
|
494
|
+
|
|
495
|
+
override func viewDidLoad() {
|
|
496
|
+
super.viewDidLoad()
|
|
497
|
+
|
|
498
|
+
let lang = Locale.preferredLanguages.first.map { String($0.prefix(2)) } ?? "en"
|
|
499
|
+
engine.setLanguage(lang)
|
|
500
|
+
|
|
501
|
+
// \`// preload:\` assets (images, fonts) resolve out of the app bundle.
|
|
502
|
+
engine.setFetchLocal { path in
|
|
503
|
+
let ns = path as NSString
|
|
504
|
+
let ext = ns.pathExtension
|
|
505
|
+
let name = ns.deletingPathExtension
|
|
506
|
+
guard let url = Bundle.main.url(forResource: name, withExtension: ext.isEmpty ? nil : ext) else {
|
|
507
|
+
return nil
|
|
508
|
+
}
|
|
509
|
+
return try? Data(contentsOf: url)
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
registerBundledPlugins(in: engine)
|
|
513
|
+
|
|
514
|
+
// OTA (native, no JS involved): start the check FIRST — even a bundle that crashes
|
|
515
|
+
// on boot can never block its own fix — then run the newest local bundle (a
|
|
516
|
+
// downloaded update, or the embedded app.js). New code applies on the next launch.
|
|
517
|
+
// Configured via app.json "update" (→ Info.plist LeCodesUpdateURL); offline: no-op.
|
|
518
|
+
LeCodesUpdater.checkForUpdate()
|
|
519
|
+
guard let code = LeCodesUpdater.activeBundle() else {
|
|
520
|
+
print("LeCodes: bundled app.js is missing — run \`lecodes app sync\`")
|
|
521
|
+
return
|
|
522
|
+
}
|
|
523
|
+
engine.run(code)
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
`
|
|
527
|
+
|
|
528
|
+
/** A JSON value as plist XML — plugin manifests carry plist-typed JSON (push's
|
|
529
|
+
* `{"aps-environment": "development"}`, associated-domains arrays, …). */
|
|
530
|
+
const plistValue = (value: unknown, indent: string): string => {
|
|
531
|
+
if (typeof value === "string") return `<string>${value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")}</string>`
|
|
532
|
+
if (typeof value === "boolean") return value ? "<true/>" : "<false/>"
|
|
533
|
+
if (typeof value === "number") return Number.isInteger(value) ? `<integer>${value}</integer>` : `<real>${value}</real>`
|
|
534
|
+
if (Array.isArray(value)) {
|
|
535
|
+
if (value.length === 0) return "<array/>"
|
|
536
|
+
return `<array>\n${value.map(v => `${indent}\t${plistValue(v, indent + "\t")}`).join("\n")}\n${indent}</array>`
|
|
537
|
+
}
|
|
538
|
+
if (value && typeof value === "object") {
|
|
539
|
+
const entries = Object.entries(value as Record<string, unknown>)
|
|
540
|
+
if (entries.length === 0) return "<dict/>"
|
|
541
|
+
return `<dict>\n${entries.map(([k, v]) => `${indent}\t<key>${k}</key>\n${indent}\t${plistValue(v, indent + "\t")}`).join("\n")}\n${indent}</dict>`
|
|
542
|
+
}
|
|
543
|
+
return "<string></string>"
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/** App/App.entitlements — CLI-owned: the capabilities the installed plugins' manifests declare
|
|
547
|
+
* (push's aps-environment, …), sorted for stable diffs. Referenced by CODE_SIGN_ENTITLEMENTS
|
|
548
|
+
* in the pbxproj; Xcode's automatic signing enables the matching App ID capabilities from it
|
|
549
|
+
* (and archive/export rewrites values like aps-environment to their distribution form). */
|
|
550
|
+
export const entitlementsTemplate = (entries: Record<string, unknown>): string => {
|
|
551
|
+
const keys = Object.keys(entries).sort()
|
|
552
|
+
const body = keys.length === 0 ? "" :
|
|
553
|
+
keys.map(k => ` <key>${k}</key>\n ${plistValue(entries[k], "\t")}`).join("\n") + "\n"
|
|
554
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
555
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
556
|
+
<plist version="1.0">
|
|
557
|
+
<dict>
|
|
558
|
+
${body}</dict>
|
|
559
|
+
</plist>
|
|
560
|
+
`
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/** Info.plist — CLI-owned: the scene manifest plus usage-description keys merged from the
|
|
564
|
+
* installed plugins' manifests (sorted for stable diffs), plus the native OTA source
|
|
565
|
+
* (app.json "update" → LeCodesUpdater reads this key at launch). */
|
|
566
|
+
export const infoPlistTemplate = (pluginKeys: Record<string, string>, updateUrl?: string): string => {
|
|
567
|
+
const xml = (s: string) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
|
568
|
+
const keys = Object.keys(pluginKeys).sort()
|
|
569
|
+
const pluginBlock = keys.length === 0 ? "" : `
|
|
570
|
+
<!-- lecodes:plugins — merged from installed plugin manifests by \`lecodes app sync\` -->
|
|
571
|
+
${keys.map(k => ` <key>${k}</key>\n <string>${pluginKeys[k]}</string>`).join("\n")}`
|
|
572
|
+
const updateBlock = !updateUrl ? "" : `
|
|
573
|
+
<!-- lecodes:update — native OTA source (app.json "update"); LeCodesUpdater checks it at launch -->
|
|
574
|
+
<key>LeCodesUpdateURL</key>
|
|
575
|
+
<string>${xml(updateUrl)}</string>`
|
|
576
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
577
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
578
|
+
<plist version="1.0">
|
|
579
|
+
<dict>
|
|
580
|
+
<!-- Standard-encryption-only (HTTPS/TLS): declares export-compliance exemption
|
|
581
|
+
so App Store Connect skips the "Missing Compliance" prompt on every build.
|
|
582
|
+
Flip to <true/> only if the app adds its own non-exempt cryptography. -->
|
|
583
|
+
<key>ITSAppUsesNonExemptEncryption</key>
|
|
584
|
+
<false/>
|
|
585
|
+
<key>UIApplicationSceneManifest</key>
|
|
586
|
+
<dict>
|
|
587
|
+
<key>UIApplicationSupportsMultipleScenes</key>
|
|
588
|
+
<false/>
|
|
589
|
+
<key>UISceneConfigurations</key>
|
|
590
|
+
<dict>
|
|
591
|
+
<key>UIWindowSceneSessionRoleApplication</key>
|
|
592
|
+
<array>
|
|
593
|
+
<dict>
|
|
594
|
+
<key>UISceneConfigurationName</key>
|
|
595
|
+
<string>Default Configuration</string>
|
|
596
|
+
<key>UISceneDelegateClassName</key>
|
|
597
|
+
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
|
598
|
+
</dict>
|
|
599
|
+
</array>
|
|
600
|
+
</dict>
|
|
601
|
+
</dict>${pluginBlock}${updateBlock}
|
|
602
|
+
</dict>
|
|
603
|
+
</plist>
|
|
604
|
+
`
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
export const LAUNCH_STORYBOARD = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
608
|
+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
|
609
|
+
<dependencies>
|
|
610
|
+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
|
611
|
+
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
|
612
|
+
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
613
|
+
</dependencies>
|
|
614
|
+
<scenes>
|
|
615
|
+
<!--View Controller-->
|
|
616
|
+
<scene sceneID="EHf-IW-A2E">
|
|
617
|
+
<objects>
|
|
618
|
+
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
|
619
|
+
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
|
620
|
+
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
|
621
|
+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
622
|
+
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
|
623
|
+
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
|
624
|
+
</view>
|
|
625
|
+
</viewController>
|
|
626
|
+
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
|
627
|
+
</objects>
|
|
628
|
+
<point key="canvasLocation" x="53" y="375"/>
|
|
629
|
+
</scene>
|
|
630
|
+
</scenes>
|
|
631
|
+
</document>
|
|
632
|
+
`
|
|
633
|
+
|
|
634
|
+
export const ASSETS_ROOT_JSON = `{
|
|
635
|
+
"info" : {
|
|
636
|
+
"author" : "xcode",
|
|
637
|
+
"version" : 1
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
`
|
|
641
|
+
|
|
642
|
+
export const ACCENT_COLOR_JSON = `{
|
|
643
|
+
"colors" : [
|
|
644
|
+
{
|
|
645
|
+
"idiom" : "universal"
|
|
646
|
+
}
|
|
647
|
+
],
|
|
648
|
+
"info" : {
|
|
649
|
+
"author" : "xcode",
|
|
650
|
+
"version" : 1
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
`
|
|
654
|
+
|
|
655
|
+
export const APP_ICON_JSON = `{
|
|
656
|
+
"images" : [
|
|
657
|
+
{
|
|
658
|
+
"idiom" : "universal",
|
|
659
|
+
"platform" : "ios",
|
|
660
|
+
"size" : "1024x1024"
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
"appearances" : [
|
|
664
|
+
{
|
|
665
|
+
"appearance" : "luminosity",
|
|
666
|
+
"value" : "dark"
|
|
667
|
+
}
|
|
668
|
+
],
|
|
669
|
+
"idiom" : "universal",
|
|
670
|
+
"platform" : "ios",
|
|
671
|
+
"size" : "1024x1024"
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
"appearances" : [
|
|
675
|
+
{
|
|
676
|
+
"appearance" : "luminosity",
|
|
677
|
+
"value" : "tinted"
|
|
678
|
+
}
|
|
679
|
+
],
|
|
680
|
+
"idiom" : "universal",
|
|
681
|
+
"platform" : "ios",
|
|
682
|
+
"size" : "1024x1024"
|
|
683
|
+
}
|
|
684
|
+
],
|
|
685
|
+
"info" : {
|
|
686
|
+
"author" : "xcode",
|
|
687
|
+
"version" : 1
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
`
|
|
691
|
+
|
|
692
|
+
export interface RuntimePlugin {
|
|
693
|
+
/** Swift module / target name (manifest ios.module), e.g. "LeCodesCamera". */
|
|
694
|
+
module: string
|
|
695
|
+
/** Type exposing `static func register(in: LeCodesEngine)` (manifest ios.register). */
|
|
696
|
+
register: string
|
|
697
|
+
/** Plugin id, for the generated comments. */
|
|
698
|
+
id: string
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/** The SDK binary products (all vend the same `LeCodesSDK` module): core = UI only,
|
|
702
|
+
* 2d = + Creator2D, 3d = + CreatorGL/filament with Jolt physics (AR included), full = everything. */
|
|
703
|
+
export type SdkVariant = "core" | "2d" | "3d" | "full"
|
|
704
|
+
|
|
705
|
+
/** LeCodesRuntime/Package.swift — the CLI-owned dependency graph: the SDK variant + one
|
|
706
|
+
* vendored target per installed plugin.
|
|
707
|
+
*
|
|
708
|
+
* `sdkVersion` is always an exact release and is pinned with `.exact(…)`: the CLI also
|
|
709
|
+
* downloads that version's LeCodesSDKResources.bundle (filament assets) into App/Resources/,
|
|
710
|
+
* so letting SwiftPM drift to a newer release on its own would pair mismatched halves of one
|
|
711
|
+
* SDK. Moving the version is the CLI's job — `lecodes app update` (or app.json ios.sdk). */
|
|
712
|
+
export const runtimePackageTemplate = (sdkVersion: string, variant: SdkVariant, plugins: RuntimePlugin[]): string => {
|
|
713
|
+
const product = `LeCodesSDK-${variant}`
|
|
714
|
+
const pluginTargets = plugins.map(p => `
|
|
715
|
+
// plugin: ${p.id} (vendored — see plugins.lock.json)
|
|
716
|
+
.target(
|
|
717
|
+
name: "${p.module}",
|
|
718
|
+
dependencies: [.product(name: "${product}", package: "lecodes-ios-sdk")],
|
|
719
|
+
path: "Sources/${p.module}"
|
|
720
|
+
),`).join("")
|
|
721
|
+
const runtimeDeps = [`.product(name: "${product}", package: "lecodes-ios-sdk")`, ...plugins.map(p => `"${p.module}"`)]
|
|
722
|
+
return `// swift-tools-version:5.9
|
|
723
|
+
//
|
|
724
|
+
// GENERATED by lecodes — regenerated by \`lecodes app sync\`; do not edit.
|
|
725
|
+
// Owns the app's native dependency graph: the LeCodesSDK variant (auto-picked from what
|
|
726
|
+
// the compiled bundle uses, or forced via app.json ios.variant), the exact SDK release
|
|
727
|
+
// (app.json ios.sdk — move it with \`lecodes app update\`) and one vendored target per
|
|
728
|
+
// installed plugin (see plugins.lock.json).
|
|
729
|
+
|
|
730
|
+
import PackageDescription
|
|
731
|
+
|
|
732
|
+
let package = Package(
|
|
733
|
+
name: "LeCodesRuntime",
|
|
734
|
+
platforms: [.iOS(.v15)],
|
|
735
|
+
products: [
|
|
736
|
+
.library(name: "LeCodesRuntime", targets: ["LeCodesRuntime"]),
|
|
737
|
+
],
|
|
738
|
+
dependencies: [
|
|
739
|
+
.package(url: "https://github.com/letary/lecodes-ios-sdk.git", exact: "${sdkVersion}"),
|
|
740
|
+
],
|
|
741
|
+
targets: [
|
|
742
|
+
.target(
|
|
743
|
+
name: "LeCodesRuntime",
|
|
744
|
+
dependencies: [
|
|
745
|
+
${runtimeDeps.join(",\n ")},
|
|
746
|
+
],
|
|
747
|
+
path: "Sources/LeCodesRuntime"
|
|
748
|
+
),${pluginTargets}
|
|
749
|
+
]
|
|
750
|
+
)
|
|
751
|
+
`
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/** Sources/LeCodesRuntime/LeCodesRuntime.swift — SDK re-export + plugin registration +
|
|
755
|
+
* (server-backed projects, SDK ≥ 1.6.0) the baked project identity. Baking it here — in a
|
|
756
|
+
* CLI-owned file that runs BEFORE \`engine.run(code)\` — means every shell picks identity up
|
|
757
|
+
* from a plain \`lecodes app sync\`, with no edits to the user-owned ViewController. */
|
|
758
|
+
export const runtimeSwiftTemplate = (plugins: RuntimePlugin[], projectUuid?: string): string => {
|
|
759
|
+
const imports = plugins.map(p => `import ${p.module}\n`).join("")
|
|
760
|
+
const identity = !projectUuid ? "" : ` // World identity: this shell IS the project — the engine attributes the boot world so
|
|
761
|
+
// identity-gated services (push registration) see the app's uuid from its first
|
|
762
|
+
// synchronous statement. Baked from .lecodes/manifest.json by \`lecodes app sync\`.
|
|
763
|
+
engine.bootProjectUuid = "${projectUuid}"
|
|
764
|
+
`
|
|
765
|
+
const calls = plugins.map(p => ` ${p.register}.register(in: engine)\n`).join("")
|
|
766
|
+
const body = identity + calls
|
|
767
|
+
return `//
|
|
768
|
+
// LeCodesRuntime.swift
|
|
769
|
+
// GENERATED by lecodes — regenerated by \`lecodes app sync\`; do not edit.
|
|
770
|
+
//
|
|
771
|
+
// Re-exports the SDK (so app code needs only \`import LeCodesRuntime\`) and registers
|
|
772
|
+
// every plugin installed in app.json.
|
|
773
|
+
//
|
|
774
|
+
|
|
775
|
+
@_exported import LeCodesSDK
|
|
776
|
+
${imports}
|
|
777
|
+
public func registerBundledPlugins(in engine: LeCodesEngine) {
|
|
778
|
+
${body === "" ? "\n" : body}}
|
|
779
|
+
`
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/** ios/README.md — orientation for whoever opens the shell: what this folder is, who owns
|
|
783
|
+
* which files, and the daily workflow. CLI-owned: init writes it, sync regenerates it. */
|
|
784
|
+
export const IOS_README = `# ios/ — native Xcode shell
|
|
785
|
+
|
|
786
|
+
Generated by \`lecodes app init ios\` for the LeCodes project one folder up. The app runs the
|
|
787
|
+
compiled bundle in \`App/Resources/app.js\` — fully offline, nothing fetched at launch. This
|
|
788
|
+
folder is ignored by the platform (\`ios/\` in \`.lecodesignore\`) and is never pushed to LeCodes.
|
|
789
|
+
|
|
790
|
+
## Daily workflow
|
|
791
|
+
|
|
792
|
+
Edit the app's code at the project root (\`main.ts\` …), then:
|
|
793
|
+
|
|
794
|
+
\`\`\`
|
|
795
|
+
lecodes app sync # recompile app.js + assets into the shell, vendor plugins
|
|
796
|
+
lecodes app open # open App.xcodeproj in Xcode — build & run from there
|
|
797
|
+
\`\`\`
|
|
798
|
+
|
|
799
|
+
\`lecodes app doctor\` preflights builds; \`lecodes app build ios\` archives and exports an
|
|
800
|
+
.ipa; \`lecodes app upload ios\` sends the archive to App Store Connect.
|
|
801
|
+
|
|
802
|
+
## SDK version
|
|
803
|
+
|
|
804
|
+
\`../app.json\` \`ios.sdk\` is the exact \`lecodes-ios-sdk\` release this shell links —
|
|
805
|
+
\`lecodes app init\` pinned the newest one at the time, so builds stay reproducible.
|
|
806
|
+
|
|
807
|
+
\`\`\`
|
|
808
|
+
lecodes app update # → newest SDK release + newest plugin tags, then sync
|
|
809
|
+
lecodes app update --check # what's available, writes nothing
|
|
810
|
+
lecodes app update --sdk 1.3.0
|
|
811
|
+
\`\`\`
|
|
812
|
+
|
|
813
|
+
Set \`"sdk": "latest"\` instead of a version to re-resolve on every sync (needs network;
|
|
814
|
+
offline it keeps whatever the shell already links). The pin is exact rather than a range
|
|
815
|
+
because the CLI also downloads that release's filament resources bundle into
|
|
816
|
+
\`App/Resources/\` — the two halves of one SDK must not drift apart.
|
|
817
|
+
|
|
818
|
+
## Who owns what
|
|
819
|
+
|
|
820
|
+
Yours — \`lecodes app sync\` never touches these:
|
|
821
|
+
|
|
822
|
+
- \`App/*.swift\` (AppDelegate, SceneDelegate, ViewController) — customize freely, add files.
|
|
823
|
+
App-local native code goes here too: add a Swift file that calls
|
|
824
|
+
\`engine.registerCallback\` / \`registerService\`, and invoke it from ViewController.
|
|
825
|
+
- \`App/Assets.xcassets/\` — the app icon. Easy path: set \`app.json\` \`"icon"\` to a square
|
|
826
|
+
≥1024px image and every sync renders AppIcon.png from it (flattened over \`"iconBackground"\`,
|
|
827
|
+
default white — App Store icons must be opaque). Or leave the key unset and drop a
|
|
828
|
+
1024×1024 PNG into AppIcon.appiconset/ yourself — sync never touches it then.
|
|
829
|
+
- \`App/Base.lproj/LaunchScreen.storyboard\`
|
|
830
|
+
|
|
831
|
+
CLI-owned — regenerated on every sync, hand edits are overwritten:
|
|
832
|
+
|
|
833
|
+
- \`App/Resources/\` — the compiled app.js + every asset it references (fonts included), so
|
|
834
|
+
the app runs fully offline. Globs in app.json \`"resources": {"remote": [...]}\` opt heavy
|
|
835
|
+
assets (videos, big models) back into streaming from the server instead.
|
|
836
|
+
- \`App/Info.plist\` — template + the installed plugins' usage keys
|
|
837
|
+
- \`App/App.entitlements\` — the capabilities the installed plugins declare (e.g. push)
|
|
838
|
+
- \`LeCodesRuntime/\` — local Swift package: the LeCodesSDK dependency, vendored plugin
|
|
839
|
+
sources (Sources/<Module>/), and the registerBundledPlugins entry point
|
|
840
|
+
- the version values inside \`App.xcodeproj/project.pbxproj\` (from app.json)
|
|
841
|
+
- this README
|
|
842
|
+
|
|
843
|
+
## SDK variant
|
|
844
|
+
|
|
845
|
+
Sync links the smallest SDK product that covers what the compiled bundle actually uses:
|
|
846
|
+
\`core\` (UI only), \`2d\` (+ 2D engine with physics), \`3d\` (+ 3D/AR engine with physics,
|
|
847
|
+
~17 MB heavier), or \`full\` (everything). Adding your first 3D scene or 2D game to the
|
|
848
|
+
project switches it automatically on the next sync; set \`ios.variant\` in \`../app.json\`
|
|
849
|
+
to pin one instead.
|
|
850
|
+
|
|
851
|
+
## Over-the-air updates
|
|
852
|
+
|
|
853
|
+
With \`"update": true\` in \`../app.json\` (server-backed projects; or
|
|
854
|
+
\`"update": {"url": "https://…/app.js"}\` for any static hosting), the app checks that URL
|
|
855
|
+
at launch — natively, before any JS runs, so a broken bundle can never block its own fix.
|
|
856
|
+
Unchanged code costs a ~0-byte 304; new code downloads in the background and runs on the
|
|
857
|
+
NEXT launch. Offline it's a silent no-op — the app always launches from a local bundle.
|
|
858
|
+
An App Store update always beats a cached OTA bundle. JS only: adding/removing native
|
|
859
|
+
plugins still needs a store release.
|
|
860
|
+
|
|
861
|
+
Shipping an update is just \`lecodes push --publish\` — no rebuild, no store review:
|
|
862
|
+
running apps download the new code on their next launch and run it on the launch after.
|
|
863
|
+
|
|
864
|
+
Shells generated before OTA support have a \`ViewController.swift\` that reads app.js from
|
|
865
|
+
\`Bundle.main\` directly, so downloaded updates would never run — and since \`App/*.swift\`
|
|
866
|
+
is yours, sync won't rewrite it (\`lecodes app doctor\` flags this). Replace the
|
|
867
|
+
\`Bundle.main\` load with:
|
|
868
|
+
|
|
869
|
+
\`\`\`swift
|
|
870
|
+
LeCodesUpdater.checkForUpdate()
|
|
871
|
+
guard let code = LeCodesUpdater.activeBundle() else {
|
|
872
|
+
print("LeCodes: bundled app.js is missing — run \`lecodes app sync\`")
|
|
873
|
+
return
|
|
874
|
+
}
|
|
875
|
+
engine.run(code)
|
|
876
|
+
\`\`\`
|
|
877
|
+
|
|
878
|
+
## Config
|
|
879
|
+
|
|
880
|
+
Identity lives in \`../app.json\` (name, version, plugins, ios.bundleId / teamId / variant /
|
|
881
|
+
buildNumber) — edit it there, then re-run \`lecodes app sync\`. Plugins are managed with
|
|
882
|
+
\`lecodes app plugin add <id | github:owner/repo[@tag]>\` and pinned in \`../plugins.lock.json\`.
|
|
883
|
+
`
|