lecodes-sdk 2.0.4 → 2.0.6
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 +104 -76
- package/dist/global.d.ts +2 -5
- package/dist/host.d.ts +3 -0
- package/dist/types/inject.d.ts +3 -3
- package/dist/types/runtime/device.d.ts +7 -0
- package/dist/types/runtime/rpc.d.ts +11 -17
- package/dist/types/runtime/wire.d.ts +53 -0
- package/dist/types/server/auth/api.d.ts +42 -0
- package/dist/types/server/auth/appConfig.d.ts +1 -5
- package/dist/types/server/auth/models.d.ts +119 -70
- package/dist/types/server/auth/types.d.ts +19 -43
- package/dist/types/server/channel.d.ts +57 -19
- package/dist/types/server/context.d.ts +2 -2
- package/dist/types/server/db/defineDb.d.ts +10 -0
- package/dist/types/server/db/index.d.ts +1 -1
- package/dist/types/server/db/types.d.ts +76 -6
- package/dist/types/server/inject.d.ts +0 -1
- package/dist/types/ui/UINode.d.ts +19 -5
- package/dist/types/ui/UIScreen.d.ts +1 -0
- package/dist/types/ui/UITabs.d.ts +8 -6
- package/dist/types/ui/theme.d.ts +48 -13
- package/dist/types/version.d.ts +1 -1
- package/dist/types.json +1 -1
- package/package.json +3 -2
- package/prompts/README.md +1 -1
- package/prompts/design.md +19 -19
- package/prompts/dist/2d-game.md +45 -31
- package/prompts/dist/3d-app.md +45 -31
- package/prompts/dist/ar-app.md +45 -31
- package/prompts/dist/design.md +25 -24
- package/prompts/dist/ui-app.md +45 -31
- package/prompts/ui-design.md +6 -5
- package/prompts/ui.md +25 -22
- package/src/bridges/device.d.ts +9 -0
- package/src/bridges/tree.d.ts +5 -0
- package/src/chisel.ts +1 -1
- package/src/compile/bundler.ts +6 -0
- package/src/compile/compileProject.ts +3 -1
- package/src/compile/index.ts +3 -1
- package/src/compile/serverSplit.ts +58 -11
- package/src/compile/serverTypes.ts +189 -8
- package/src/host.d.ts +3 -0
- package/src/inject.ts +6 -6
- package/src/runtime/device.ts +12 -0
- package/src/runtime/rpc.ts +101 -40
- package/src/runtime/wire.ts +35 -0
- package/src/server/auth/api.ts +94 -0
- package/src/server/auth/appConfig.ts +2 -3
- package/src/server/auth/host.ts +244 -174
- package/src/server/auth/models.ts +45 -62
- package/src/server/auth/types.ts +19 -34
- package/src/server/channel.ts +97 -29
- package/src/server/channelHub.ts +153 -0
- package/src/server/context.ts +2 -2
- package/src/server/db/defineDb.ts +96 -36
- package/src/server/db/index.ts +1 -1
- package/src/server/db/types.ts +76 -8
- package/src/server/host.ts +25 -10
- package/src/server/inject.ts +2 -2
- package/src/server/runtime.ts +34 -12
- package/src/ui/UINode.ts +22 -5
- package/src/ui/UIScreen.ts +5 -0
- package/src/ui/UITabs.ts +19 -17
- package/src/ui/styleColor.ts +10 -1
- package/src/ui/theme.ts +96 -41
- package/src/version.ts +1 -1
- package/tests/helpers/fakeTree.ts +1 -0
- package/dist/types/plugins/oauth.d.ts +0 -25
- package/dist/types/server/auth/global.d.ts +0 -56
- package/src/plugins/oauth.ts +0 -61
- package/src/server/auth/global.ts +0 -80
- package/tests/helpers/memoryMarci.ts +0 -124
package/README.md
CHANGED
|
@@ -1,52 +1,76 @@
|
|
|
1
|
-
# sdk — the
|
|
1
|
+
# lecodes-sdk — the import-free LeCodes API
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
(
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
The TypeScript API LeCodes apps are written against: **UI**, **2D**, **3D** and the platform
|
|
4
|
+
runtime (network, storage, input, audio, device, plugins) in one surface of **globals** — user code
|
|
5
|
+
writes `UIScreen`, `Scene`, `Sprite`, `fetch`, … with **no imports**. The `lecodes` CLI compiles a
|
|
6
|
+
project through this package into one `app.js`; the bundler (chisel) keeps only the methods a
|
|
7
|
+
project reaches, so a UI app carries no 3D code and a 2D game no UI kit. The same bundle runs on
|
|
8
|
+
the LeCodes hosts: desktop, iOS, Android and the web player.
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
**API reference:** [docs/index.md](./docs/index.md) — every global, example-first; how to build
|
|
11
|
+
a whole thing out of it is the [cookbook](./docs/cookbook/README.md). `bun run docs:check` verifies
|
|
12
|
+
that every global has exactly one page and that the links resolve.
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
```ts
|
|
15
|
+
// UI — no imports
|
|
16
|
+
let taps = 0
|
|
17
|
+
const label = UIText('Taps: 0').style({ color: '#fff', fontSize: 22 })
|
|
18
|
+
|
|
19
|
+
UIScreen(
|
|
20
|
+
label,
|
|
21
|
+
UIButton(UIText('Tap me').style({ color: '#fff' }))
|
|
22
|
+
.style({ bgColor: '#4f7cff', borderRadius: 12, p: 16, $pressed: { opacity: 0.8 } })
|
|
23
|
+
.onClick(() => { label.text = `Taps: ${++taps}` }),
|
|
24
|
+
)
|
|
25
|
+
.style({ bgColor: '#1e2230', alignItems: 'center', justifyContent: 'center', gap: 16 })
|
|
26
|
+
.open()
|
|
27
|
+
```
|
|
12
28
|
|
|
13
29
|
```ts
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
// 3D — no imports; behaviour is an Aspect attached to a node
|
|
31
|
+
Physics.configure({ gravity: [0, -9.81, 0] })
|
|
32
|
+
|
|
33
|
+
class Turn extends Aspect<'turn'> {
|
|
34
|
+
speed = 90 // degrees per second
|
|
35
|
+
private angle = 0
|
|
36
|
+
protected update(dt: number) { // every frame; dt = game seconds
|
|
37
|
+
this.angle += this.speed * dt
|
|
38
|
+
this.node.eulerAngles = [0, this.angle, 0]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const scene = new Scene({ skybox: '#10131a' })
|
|
43
|
+
const mat = Material.lit({ color: '#e33' })
|
|
44
|
+
const ground = Mesh.box({ material: mat, scale: [10, 0.2, 10] })
|
|
45
|
+
.aspect(Shape, {}) // a box collider fitted to the mesh
|
|
46
|
+
.aspect(Physics, { motion: 'static' })
|
|
47
|
+
const ball = Mesh.sphere({ material: mat, position: [0, 5, 0] })
|
|
48
|
+
.aspect(Shape, {})
|
|
49
|
+
.aspect(Physics, { mass: 1 }) // dynamic: the physics step moves it
|
|
50
|
+
const cube = Mesh.box({ material: mat, position: [2, 1, 0] })
|
|
51
|
+
.aspect(Turn, { speed: 180 }) // cube.turn is the attached aspect
|
|
52
|
+
scene.add(ground, ball, cube, Light.sun())
|
|
53
|
+
scene.camera.position = [0, 6, 12]
|
|
54
|
+
scene.camera.lookAt([0, 0, 0])
|
|
55
|
+
scene.open()
|
|
31
56
|
```
|
|
32
57
|
|
|
33
58
|
## Fluent math (`Vec2` / `Vec3` / `Quat` / `Mat4`)
|
|
34
59
|
|
|
35
|
-
Per-frame math reads like the formula — no
|
|
36
|
-
|
|
37
|
-
never mutates its source. They
|
|
38
|
-
a vector does.
|
|
60
|
+
Per-frame math reads like the formula — no out-params. Vectors are *mutable structs with pure
|
|
61
|
+
methods*: fields are settable (`v.x = 3`, `v.set(…)`), but every method returns a NEW value and
|
|
62
|
+
never mutates its source. They are iterable and accept raw tuples anywhere, so `[0, 1, 0]` works
|
|
63
|
+
wherever a vector does.
|
|
39
64
|
|
|
40
65
|
```ts
|
|
41
|
-
const dir
|
|
66
|
+
const dir = target.position.sub(self.position).normalize()
|
|
42
67
|
self.position = self.position.add(dir.scale(speed * dt))
|
|
43
68
|
if (a.distanceTo(b) < 2) explode()
|
|
44
69
|
node.quaternion = node.quaternion.mul(Quat.fromAxisAngle(Vec3.up, turn))
|
|
45
70
|
|
|
46
|
-
//
|
|
47
|
-
node.x = 3
|
|
48
|
-
const p = node.position; p.y = 5; node.position = p
|
|
49
|
-
// node.position.x = 3 ← a no-op (mutates a discarded copy); use node.x instead
|
|
71
|
+
// node getters return fresh copies (value semantics, like Unity):
|
|
72
|
+
node.position.x = 3 // compiled to a single-axis write — the direct spelling works
|
|
73
|
+
const p = node.position; p.y = 5; node.position = p // a stored copy: mutate it, assign it back
|
|
50
74
|
|
|
51
75
|
// Mat4 keeps the metal exposed (public .m) for low-level surgery:
|
|
52
76
|
let m = node.matrix.translate(pivot).rotateY(yaw * dt).translate(pivot.negate())
|
|
@@ -54,64 +78,68 @@ m.m[12] += vx * dt
|
|
|
54
78
|
node.matrix = m
|
|
55
79
|
```
|
|
56
80
|
|
|
57
|
-
`Quat
|
|
58
|
-
perspective`. All of it is fuzz-tested against gl-matrix (dev-only oracle) in
|
|
81
|
+
`Quat` / `Mat4` cover the rest: `Quat.fromEuler / lookRotation / slerp`, `Mat4.compose / decompose /
|
|
82
|
+
lookAt / perspective`. All of it is fuzz-tested against gl-matrix (a dev-only oracle) in
|
|
83
|
+
`tests/math/oracle.test.ts`.
|
|
59
84
|
|
|
60
85
|
## Design rules
|
|
61
86
|
|
|
62
|
-
- **
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
87
|
+
- **Globals only.** `src/inject.ts` is the one file that exports public names; a project's imports
|
|
88
|
+
are relative paths to its own files and assets. Variants are static factories (`Mesh.box()`,
|
|
89
|
+
`Material.lit()`, `Texture2D.load()`), not free functions.
|
|
90
|
+
- **UI elements are handles** to the runtime's tree (docs/tree.md at the repo root): factories take
|
|
91
|
+
content, appearance goes through chained `.style()`, states are `$name` class blocks.
|
|
92
|
+
- **Behaviour is an `Aspect`** on a node and a **`System`** on a scene; the phases are methods
|
|
93
|
+
(`updateBefore` / `update` / `updateFixed`) — no hand-written game loops.
|
|
94
|
+
- **Native resources are owned handles**: a node, texture, material or player is freed once nothing
|
|
95
|
+
references it and nothing native owns it; `destroy()` frees a node early.
|
|
96
|
+
- **Hosts differ, the API does not**: an optional host capability is feature-detected
|
|
97
|
+
(`Physics.supported`, a plugin's `isSupported`), never versioned.
|
|
68
98
|
|
|
69
99
|
## Layout
|
|
70
100
|
|
|
71
101
|
```
|
|
72
102
|
src/
|
|
73
|
-
inject.ts
|
|
74
|
-
|
|
75
|
-
host.d.ts
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
inject.ts THE aggregation point — the only file that exports public globals
|
|
104
|
+
host.d.ts host-provided globals (setTimeout, setLoop, console, asset, font, DEG2RAD, EDITOR)
|
|
105
|
+
bridges/ the host contract: one .d.ts per bridge (_creator*, host tables) — never bundled
|
|
106
|
+
chisel.ts the chisel vocabulary: every SDK name the bundler's passes key on
|
|
107
|
+
version.ts SDK_VERSION — its major is the bundle ↔ runtime contract
|
|
108
|
+
core/ Aspect / System, signals, events, Time, StateMachine, color, owned-handle pins
|
|
109
|
+
math/ Mathf, Vec2 / Vec3, Quat, Mat4 (no gl-matrix shipped)
|
|
110
|
+
canvas/ Canvas / Bitmap — vector drawing over the AnyCanvas core
|
|
111
|
+
animate/ animate(), Timeline, easings — the keyframe tween core
|
|
112
|
+
runtime/ fetch, storage, files, device, input, media, touch, app, share, date, rpc
|
|
113
|
+
audio/ game audio: Sound, Voice, Bus, audio
|
|
114
|
+
net/ multiplayer: Net, replication
|
|
115
|
+
ui/ UIScreen / UIRow / UIText / … + Router, UIPager, widgets, theme, transitions
|
|
116
|
+
g2/ 2D: Scene2D, Node2D, Sprite, Tilemap, tilesets, Box2D physics
|
|
117
|
+
gl/ 3D: Scene, Node, Mesh, Model, Material, Light, physics/, vehicle/, animation/, nav/, terrain/
|
|
118
|
+
scene/ scenes as data (defineScene), materials, Level, editor plugins
|
|
119
|
+
plugins/ OAuth, Service + the first-party plugins vendored under plugins/gen
|
|
120
|
+
server/ the host side of app backends (`lecodes-sdk/server`)
|
|
121
|
+
compile/ the project compiler (bundler, entry detection, macros) — `lecodes-sdk/compile`
|
|
122
|
+
docs/ the API reference + cookbook
|
|
123
|
+
prompts/ codegen prompts for the platform's in-editor assistant (`bun run prompts:build`)
|
|
124
|
+
tests/<area>/ bun tests, one folder per src area; tests/helpers = the fake host (`lecodes-sdk/testing`)
|
|
86
125
|
```
|
|
87
126
|
|
|
88
127
|
## Build & test
|
|
89
128
|
|
|
90
129
|
```sh
|
|
91
|
-
bun run build #
|
|
92
|
-
bun test #
|
|
130
|
+
bun run build # dist/global.d.ts + host.d.ts + editor.d.ts + types.json — the editor types
|
|
131
|
+
bun test # every suite; `bun test tests/<area>` for one area
|
|
93
132
|
bun run typecheck # tsc --noEmit
|
|
133
|
+
bun run docs:check # every global documented exactly once, sources + links resolve
|
|
94
134
|
```
|
|
95
135
|
|
|
96
|
-
|
|
97
|
-
has the layout, the shared stubs and the one-process rules.
|
|
98
|
-
|
|
99
|
-
`tests/headless/` holds live WebGL2 render harnesses (manual; need chrome-headless-shell). The 2D
|
|
100
|
-
harness is green: a project compiled through the real `compileProject` renders correct pixels.
|
|
136
|
+
[tests/README.md](tests/README.md) has the test layout, the shared stubs and the one-process rules.
|
|
101
137
|
|
|
102
138
|
## How it integrates
|
|
103
139
|
|
|
104
|
-
The
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
## Deferred (API present, native pending)
|
|
111
|
-
|
|
112
|
-
- 2D physics / collider triggers (`.collider()` is a no-op stub; `Node2D.add()` hierarchy).
|
|
113
|
-
- Live 2D↔3D engine switching is wired in the viewer host (two canvases) but pending a real dual
|
|
114
|
-
project to verify.
|
|
115
|
-
|
|
116
|
-
`ARScene.addControls(target, options?)` ports the AR object-placement gesture recipe (one-finger drag,
|
|
117
|
-
two-finger pinch-scale + twist-rotate) onto the fluent math; returns a `{ remove() }` handle.
|
|
140
|
+
The CLI (`lecodes compile | render | test | dev`) and the build service compile every project
|
|
141
|
+
through `lecodes-sdk/compile`: entry detection (`main.ts`, else the import-graph root), the
|
|
142
|
+
`asset()` / `font()` / `assetIcon()` macros, then chisel over the SDK **source** — the bundle is
|
|
143
|
+
built from `src/`, not from a prebuilt runtime. Every bundle opens with `// sdk: <version>`; a host
|
|
144
|
+
refuses a bundle whose major differs from its runtime's (the SDK and the runtimes are one version,
|
|
145
|
+
`bun run set-version` at the repo root). Plugins import the SDK through `lecodes-sdk/plugin`.
|
package/dist/global.d.ts
CHANGED
|
@@ -71,7 +71,6 @@ declare global {
|
|
|
71
71
|
const Node: typeof SDK.Node
|
|
72
72
|
const Node2D: typeof SDK.Node2D
|
|
73
73
|
const Noise: typeof SDK.Noise
|
|
74
|
-
const OAuth: typeof SDK.OAuth
|
|
75
74
|
const OneWay2D: typeof SDK.OneWay2D
|
|
76
75
|
const Particles: typeof SDK.Particles
|
|
77
76
|
const Physics: typeof SDK.Physics
|
|
@@ -246,10 +245,10 @@ declare global {
|
|
|
246
245
|
type CameraView = SDK.CameraView
|
|
247
246
|
type Canvas = SDK.Canvas
|
|
248
247
|
type CellsData = SDK.CellsData
|
|
248
|
+
type ChannelSubscription = SDK.ChannelSubscription
|
|
249
249
|
type CharacterController = SDK.CharacterController
|
|
250
250
|
type CharacterController2D = SDK.CharacterController2D
|
|
251
251
|
type ClickEvent<T = any> = SDK.ClickEvent<T>
|
|
252
|
-
type ClientChannel<E extends Record<string, unknown> = Record<string, unknown>> = SDK.ClientChannel<E>
|
|
253
252
|
type ClipAlign = SDK.ClipAlign
|
|
254
253
|
type ClipCycle = SDK.ClipCycle
|
|
255
254
|
type ClipDef = SDK.ClipDef
|
|
@@ -404,8 +403,6 @@ declare global {
|
|
|
404
403
|
type Node = SDK.Node
|
|
405
404
|
type Node2D = SDK.Node2D
|
|
406
405
|
type Noise = SDK.Noise
|
|
407
|
-
type OAuthCredential = SDK.OAuthCredential
|
|
408
|
-
type OAuthProviderName = SDK.OAuthProviderName
|
|
409
406
|
type OneWay2D = SDK.OneWay2D
|
|
410
407
|
type OrientationLock = SDK.OrientationLock
|
|
411
408
|
type Particles = SDK.Particles
|
|
@@ -497,6 +494,7 @@ declare global {
|
|
|
497
494
|
type Texture2D = SDK.Texture2D
|
|
498
495
|
type TextureLoadOptions = SDK.TextureLoadOptions
|
|
499
496
|
type ThemeAccessors<T> = SDK.ThemeAccessors<T>
|
|
497
|
+
type ThemeRoles = SDK.ThemeRoles
|
|
500
498
|
type ThemeValues = SDK.ThemeValues
|
|
501
499
|
type TileBlock = SDK.TileBlock
|
|
502
500
|
type TileMaterial = SDK.TileMaterial
|
|
@@ -575,7 +573,6 @@ declare global {
|
|
|
575
573
|
type With<N, A extends Aspect<any, any, any>> = SDK.With<N, A>
|
|
576
574
|
// ---- server globals (available in *.server.ts; using them in client code is a build error) ----
|
|
577
575
|
const ApiError: typeof SERVER.ApiError
|
|
578
|
-
const auth: typeof SERVER.auth
|
|
579
576
|
const channel: typeof SERVER.channel
|
|
580
577
|
const defineDb: typeof SERVER.defineDb
|
|
581
578
|
const model: typeof SERVER.model
|
package/dist/host.d.ts
CHANGED
|
@@ -31,6 +31,9 @@ declare global {
|
|
|
31
31
|
/** Compile-time macro: `asset('./data.json')` yields the file's PARSED data (a .json file is
|
|
32
32
|
* data, not code — it ships inside the bundle). See the `string` overload for everything else. */
|
|
33
33
|
function asset(path: `${string}.json`): any
|
|
34
|
+
/** Compile-time macro: `asset('./logo.svg')` yields the file as an SVG image source — for
|
|
35
|
+
* `UIImage(...)` and `bgImage`. */
|
|
36
|
+
function asset(path: `${string}.svg`): { readonly svg: string, tintColor: string | null }
|
|
34
37
|
/** Compile-time macro: `asset('./hero.png')` is desugared by the bundler into the module import
|
|
35
38
|
* for that resource. The file must exist — a path that resolves to nothing fails the compile
|
|
36
39
|
* (`asset not found: ./hero.png (main.ts:3)`); there is no runtime fallback. Calls inside
|
package/dist/types/inject.d.ts
CHANGED
|
@@ -21,7 +21,8 @@ export { device, type HapticStyle, type MotionOptions } from "./runtime/device";
|
|
|
21
21
|
export { Input, InputChannel, type InputKeyEvent, type InputGamepadEvent, type InputEventName, type GamepadState, type GamepadAxisName } from "./runtime/input";
|
|
22
22
|
export { WebSocket } from "./runtime/net";
|
|
23
23
|
export { Net, NetPlayer, Replicated, NetEntity, type NetMessage, type NetRole, type NetStatus, type NetEvents, type NetLaunch, type NetInput, type NetKind, type NetTransform, type NetCorrection } from "./net";
|
|
24
|
-
export { __rpc, __channel, __serverOnly, RpcError
|
|
24
|
+
export { __rpc, __channel, __serverOnly, RpcError } from "./runtime/rpc";
|
|
25
|
+
export type { ChannelSubscription } from "./server/channel";
|
|
25
26
|
export { AudioPlayer, VideoPlayer } from "./runtime/media";
|
|
26
27
|
export { Sound, type SoundOptions } from "./audio/Sound";
|
|
27
28
|
export { Voice, type VoiceEvents } from "./audio/Voice";
|
|
@@ -57,7 +58,7 @@ export { UIScreen, type UIScreenStyle, UIRow, UIColumn, UIBox, type UIContainerS
|
|
|
57
58
|
export { Presentable } from "./ui/UI";
|
|
58
59
|
export type { DismissOptions, PresentOptions, Transition, TransitionName, TransitionPose, TransitionSpec } from "./ui/UI";
|
|
59
60
|
export type { UINode, UINodeChild } from "./ui/UINode";
|
|
60
|
-
export { theme, type ThemeValues, type ThemeAccessors } from "./ui/theme";
|
|
61
|
+
export { theme, type ThemeValues, type ThemeAccessors, type ThemeRoles } from "./ui/theme";
|
|
61
62
|
export { animate, type AnimateOptions, type AnimateValue, type AnimateOut } from "./animate/tween/animateValue";
|
|
62
63
|
export { cubicBezier } from "./animate/bezier";
|
|
63
64
|
export { Timeline, type TimelineOptions, type TimelineAddOptions, type TimelinePosition } from "./animate/tween/Timeline";
|
|
@@ -70,7 +71,6 @@ export { CameraView, type CameraFacing } from "./plugins/gen/camera/sdk/camera";
|
|
|
70
71
|
export { Geolocation, type GeoPosition, type GeoOptions, type GeoWatch } from "./plugins/gen/geolocation/sdk/geolocation";
|
|
71
72
|
export { MapView, type MapOptions, type MapStyle, type MapStyleName, type MapCamera, type MapTap, type LngLat, type CameraMove, type FitOptions, type MapPaddingValues, type MarkerItem, type MarkerTap, type MarkerLayer, type MarkerLayerOptions, type LineLayer, type LineLayerOptions, type UserLocationOptions, } from "./plugins/gen/map/sdk/map";
|
|
72
73
|
export { Push, type PushPayload, type PushStatus, type PushRegisterOptions, type PushEvent } from "./plugins/gen/push/sdk/push";
|
|
73
|
-
export { OAuth, type OAuthCredential, type OAuthProviderName } from "./plugins/oauth";
|
|
74
74
|
export { Service } from "./plugins/service";
|
|
75
75
|
export { defineScene, use, ref, make, SceneHandle } from "./scene/defineScene";
|
|
76
76
|
export { defineMaterial, MaterialHandle } from "./scene/material";
|
|
@@ -56,6 +56,13 @@ export declare const device: {
|
|
|
56
56
|
* feels native on each platform; see {@link HapticStyle}. Host-gated: a silent no-op where there's
|
|
57
57
|
* no haptic hardware (iPad, older iPhones, web, headless). */
|
|
58
58
|
vibrate(style?: HapticStyle): void;
|
|
59
|
+
/** The host's performance overlay: one line over everything with the frames per second the
|
|
60
|
+
* display actually got, how evenly they came (`66 fps · 73% even` is judder, `60 fps · 100% even`
|
|
61
|
+
* is smooth), and the GPU's and the main thread's milliseconds per frame. The host measures and
|
|
62
|
+
* draws it itself about once a second — nothing of it runs in the app's JS, so it does not change
|
|
63
|
+
* what it measures. It belongs to the host, not to the project: it stays on when another project
|
|
64
|
+
* is opened. Reads `false`, and writing does nothing, on hosts without one (web, headless). */
|
|
65
|
+
statsOverlay: boolean;
|
|
59
66
|
/** Device-orientation sensor (gyro + accelerometer, fused) for tilt/steering and magic-window /
|
|
60
67
|
* 360° panoramas. Poll `attitude` / `gravity` inside setLoop; they return the freshest fused
|
|
61
68
|
* sample, so the sensor rate need not match your frame rate. Host-gated: a no-op with no sensor. */
|
|
@@ -10,15 +10,13 @@
|
|
|
10
10
|
* Wire (implemented by the runner):
|
|
11
11
|
* POST <serverUrl>/api/<id> body {"args":[…]}, `authorization: Bearer <session>` when known
|
|
12
12
|
* → 200 {"ok":true,"result":…,"session"?:"…"} | {"ok":false,"status":n,"message":"…","session"?:"…"}
|
|
13
|
-
* WS <serverUrl>/ws
|
|
14
|
-
* ← {t:"session",session} {t:"ok",id} {t:"err",id,status,message} {t:"ev",ch,topic,event,data}
|
|
15
|
-
* (`ev` is addressed by channel + topic, not by subscription id, so the server can fan one publish out
|
|
16
|
-
* to every socket of a topic natively; the client delivers it to each matching subscription.)
|
|
13
|
+
* WS <serverUrl>/ws the channel socket — its frames are ./wire.ts
|
|
17
14
|
*
|
|
18
15
|
* The session token is transport-owned (cookie-like): stored under `lecodes.session:<serverUrl>` in
|
|
19
16
|
* localStorage, sent on every call and on the socket, replaced whenever a response carries `session`.
|
|
20
17
|
* User code never sees it — "am I logged in" is an endpoint (`me()`), see the plan.
|
|
21
18
|
*/
|
|
19
|
+
import type { ChannelSubscription } from "../server/channel";
|
|
22
20
|
/** Rejection value of a failed endpoint call: `status` mirrors the server's `ApiError`
|
|
23
21
|
* (0 = the request itself failed: no network / no server). */
|
|
24
22
|
export declare class RpcError extends Error {
|
|
@@ -29,16 +27,12 @@ export declare class RpcError extends Error {
|
|
|
29
27
|
export declare const __rpc: (serverUrl: string, id: string) => (...args: unknown[]) => Promise<any>;
|
|
30
28
|
/** A server-only export (db, models, helpers) referenced from client code: any use throws. */
|
|
31
29
|
export declare const __serverOnly: (id: string) => any;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
/** Build the client proxy of channel `id`. */
|
|
44
|
-
export declare const __channel: (serverUrl: string, id: string) => ClientChannel<any>;
|
|
30
|
+
/**
|
|
31
|
+
* Build the client proxy of channel `id` — what a `channel()` export of a `*.server.ts` file is in
|
|
32
|
+
* the app (its type is the server's: src/server/channel.ts). `subscribe([...args,] handler, options?)`:
|
|
33
|
+
* what stands before the handler travels to the channel's `groupBy`.
|
|
34
|
+
*/
|
|
35
|
+
export declare const __channel: (serverUrl: string, id: string) => {
|
|
36
|
+
subscribe(...all: unknown[]): ChannelSubscription;
|
|
37
|
+
publish(): never;
|
|
38
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The frames of the channel socket (`<serverUrl>/ws`) — the ONE description both ends are written
|
|
3
|
+
* against: the client transport (./rpc.ts) and the server's hub (../server/channelHub.ts, which the
|
|
4
|
+
* runner and the local backend of `lecodes dev` both run). JSON text frames, one per message.
|
|
5
|
+
*
|
|
6
|
+
* → hello who is on this socket. Sent first, and again whenever the session changes: the server
|
|
7
|
+
* then DROPS the socket's subscriptions (they were granted to someone else) and the
|
|
8
|
+
* client sends them again, under new ids.
|
|
9
|
+
* → sub subscribe to channel `ch`; `args` are what the app passed to `subscribe` before the
|
|
10
|
+
* handler — the channel's `groupBy` reads them.
|
|
11
|
+
* → unsub
|
|
12
|
+
* ← session a token minted while the socket was served (the first contact of a guest): the client
|
|
13
|
+
* stores it; nothing is dropped, the server already has it.
|
|
14
|
+
* ← ok the subscription stands; `group` is where the server put it (null = a channel without
|
|
15
|
+
* groups). The client learns its group only here — it never names one.
|
|
16
|
+
* ← err refused (a hook threw) — the subscription is gone.
|
|
17
|
+
* ← ev one published message, addressed by channel + group so the server sends one frame to
|
|
18
|
+
* every socket of a group; the client hands it to each of its subscriptions there.
|
|
19
|
+
*
|
|
20
|
+
* A group's value is not a secret: its subscriber is told it.
|
|
21
|
+
*/
|
|
22
|
+
/** What `groupBy` may answer. `42` and `"42"` are two groups. */
|
|
23
|
+
export type ChannelGroup = string | number;
|
|
24
|
+
export type ClientFrame = {
|
|
25
|
+
t: "hello";
|
|
26
|
+
session: string | null;
|
|
27
|
+
} | {
|
|
28
|
+
t: "sub";
|
|
29
|
+
id: number;
|
|
30
|
+
ch: string;
|
|
31
|
+
args: unknown[];
|
|
32
|
+
} | {
|
|
33
|
+
t: "unsub";
|
|
34
|
+
id: number;
|
|
35
|
+
};
|
|
36
|
+
export type ServerFrame = {
|
|
37
|
+
t: "session";
|
|
38
|
+
session: string;
|
|
39
|
+
} | {
|
|
40
|
+
t: "ok";
|
|
41
|
+
id: number;
|
|
42
|
+
group: ChannelGroup | null;
|
|
43
|
+
} | {
|
|
44
|
+
t: "err";
|
|
45
|
+
id: number;
|
|
46
|
+
status: number;
|
|
47
|
+
message: string;
|
|
48
|
+
} | {
|
|
49
|
+
t: "ev";
|
|
50
|
+
ch: string;
|
|
51
|
+
group: ChannelGroup | null;
|
|
52
|
+
data: unknown;
|
|
53
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `db.auth` — the BUNDLE side of sign-in, what `*.server.ts` code calls on a db made with
|
|
3
|
+
* `defineDb({...}).withAuth({ model: "User" })`:
|
|
4
|
+
*
|
|
5
|
+
* const db = defineDb({ User, Post }).withAuth({ model: "User" })
|
|
6
|
+
*
|
|
7
|
+
* export async function register(login: string, password: string, name: string) {
|
|
8
|
+
* await db.auth.signUpWithPassword(login, password, { name })
|
|
9
|
+
* }
|
|
10
|
+
* export async function me() { return db.auth.user().select({ id: true, name: true }) }
|
|
11
|
+
* export async function removePost(id: number) {
|
|
12
|
+
* await db.auth.requireUser({ role: "admin" }).select({ id: true })
|
|
13
|
+
* …
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* The platform knows a request's session and the ID of its user (the host resolved the token before
|
|
17
|
+
* the endpoint ran). Everything else about a user is a row of the project's own model, and is READ:
|
|
18
|
+
* `user()` / `requireUser()` are queries over that model — typed by it, run when awaited — narrowed to
|
|
19
|
+
* the user of the request. Sign-in operations forward to the host's `AuthOps` on
|
|
20
|
+
* `globalThis.__lecodesAuth` (a seam: the compiled bundle carries its own SDK copy).
|
|
21
|
+
*/
|
|
22
|
+
/** The collections of a db with auth, by role (defineDb.ts). */
|
|
23
|
+
export type AuthCollections = {
|
|
24
|
+
model: string;
|
|
25
|
+
user: any;
|
|
26
|
+
session: any;
|
|
27
|
+
identity: any;
|
|
28
|
+
};
|
|
29
|
+
export declare const createAuthApi: (tables: () => AuthCollections) => {
|
|
30
|
+
user: () => any;
|
|
31
|
+
requireUser: (where?: Record<string, unknown>) => any;
|
|
32
|
+
readonly sessionId: number;
|
|
33
|
+
signUpWithPassword: (login: string, password: string, data?: Record<string, unknown>) => Promise<void>;
|
|
34
|
+
signInWithPassword: (login: string, password: string) => Promise<void>;
|
|
35
|
+
setPassword: (password: string) => Promise<void>;
|
|
36
|
+
sendCode: (email: string) => Promise<void>;
|
|
37
|
+
signInWithCode: (email: string, code: string) => Promise<void>;
|
|
38
|
+
signIn: (userId: number) => Promise<void>;
|
|
39
|
+
signOut: () => Promise<void>;
|
|
40
|
+
readonly sessions: any;
|
|
41
|
+
readonly identities: any;
|
|
42
|
+
};
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The project's `app.json` subset the server runtime reads
|
|
2
|
+
* The project's `app.json` subset the server runtime reads: the app's name (the sign-in mail).
|
|
3
3
|
*
|
|
4
4
|
* This module is a placeholder the COMPILER REPLACES: `compileServerBundle({ app })` puts a module with the
|
|
5
5
|
* real values at this same path in chisel's file map (project files win over SDK files), so every SDK module
|
|
6
6
|
* that imports `app` gets the project's config as a plain dependency — no globals, no evaluation-order games.
|
|
7
7
|
* Outside a compiled bundle (tests, tooling) `globalThis.__lecodesApp` can stand in.
|
|
8
8
|
*/
|
|
9
|
-
export type AuthProvider = "email" | "google" | "apple" | "yandex" | "vk";
|
|
10
9
|
export type AppConfig = {
|
|
11
10
|
name?: string;
|
|
12
|
-
auth?: {
|
|
13
|
-
providers?: AuthProvider[];
|
|
14
|
-
};
|
|
15
11
|
};
|
|
16
12
|
export declare const app: AppConfig;
|