lecodes-sdk 2.1.1 → 2.2.1

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/global.d.ts CHANGED
@@ -159,6 +159,7 @@ declare global {
159
159
  const __rpc: typeof SDK.__rpc
160
160
  const __serverOnly: typeof SDK.__serverOnly
161
161
  const __uiMap: typeof SDK.__uiMap
162
+ const action: typeof SDK.action
162
163
  const animate: typeof SDK.animate
163
164
  const app: typeof SDK.app
164
165
  const audio: typeof SDK.audio
@@ -168,6 +169,7 @@ declare global {
168
169
  const computed: typeof SDK.computed
169
170
  const cubicBezier: typeof SDK.cubicBezier
170
171
  const curve: typeof SDK.curve
172
+ const dataOf: typeof SDK.dataOf
171
173
  const date: typeof SDK.date
172
174
  const defineMaterial: typeof SDK.defineMaterial
173
175
  const defineScene: typeof SDK.defineScene
@@ -182,6 +184,7 @@ declare global {
182
184
  const easeOut: typeof SDK.easeOut
183
185
  const effect: typeof SDK.effect
184
186
  const encodeCells: typeof SDK.encodeCells
187
+ const failureOf: typeof SDK.failureOf
185
188
  const fetch: typeof SDK.fetch
186
189
  const fetchLocal: typeof SDK.fetchLocal
187
190
  const files: typeof SDK.files
@@ -199,6 +202,7 @@ declare global {
199
202
  const registerEditorWindow: typeof SDK.registerEditorWindow
200
203
  const registerFont: typeof SDK.registerFont
201
204
  const resolveTire: typeof SDK.resolveTire
205
+ const resource: typeof SDK.resource
202
206
  const rot180: typeof SDK.rot180
203
207
  const rot270: typeof SDK.rot270
204
208
  const rot90: typeof SDK.rot90
@@ -212,6 +216,7 @@ declare global {
212
216
  const toast: typeof SDK.toast
213
217
  const use: typeof SDK.use
214
218
  type ARScene<T extends ARMode = "default"> = SDK.ARScene<T>
219
+ type Action<A extends unknown[], R> = SDK.Action<A, R>
215
220
  type ActiveClip = SDK.ActiveClip
216
221
  type AeroConfig = SDK.AeroConfig
217
222
  type AnimateOptions<T extends AnimateValue> = SDK.AnimateOptions<T>
@@ -288,6 +293,7 @@ declare global {
288
293
  type EditorWindowFn = SDK.EditorWindowFn
289
294
  type EngineConfig = SDK.EngineConfig
290
295
  type EventMap = SDK.EventMap
296
+ type Failure = SDK.Failure
291
297
  type Feet = SDK.Feet
292
298
  type FeetOptions = SDK.FeetOptions
293
299
  type FetchResponse = SDK.FetchResponse
@@ -337,6 +343,7 @@ declare global {
337
343
  type LineLayerOptions = SDK.LineLayerOptions
338
344
  type LitMaterialDef = SDK.LitMaterialDef
339
345
  type LngLat = SDK.LngLat
346
+ type Loaded<T> = SDK.Loaded<T>
340
347
  type LoadedScene<D extends SceneDef> = SDK.LoadedScene<D>
341
348
  type LoadedScene2d<D extends Scene2dDef> = SDK.LoadedScene2d<D>
342
349
  type Locale = SDK.Locale
@@ -436,6 +443,7 @@ declare global {
436
443
  type RagdollPart = SDK.RagdollPart
437
444
  type Ray = SDK.Ray
438
445
  type Replicated = SDK.Replicated
446
+ type Resource<T> = SDK.Resource<T>
439
447
  type ReverbParams = SDK.ReverbParams
440
448
  type ReverbPreset = SDK.ReverbPreset
441
449
  type RibbonOptions = SDK.RibbonOptions
@@ -4,6 +4,12 @@ export interface Signal<T> {
4
4
  value: T;
5
5
  /** Read without subscribing the current effect/computed. */
6
6
  peek(): T;
7
+ /**
8
+ * Kept on the device under `key`: what the last run left there replaces the initial value (when
9
+ * it is there and reads as JSON), and every write is saved. JSON values only — a date, a class
10
+ * instance or a function does not survive the round trip. `signal<Line[]>([]).stored("cart")`.
11
+ */
12
+ stored(key: string): Signal<T>;
7
13
  }
8
14
  export interface Computed<T> {
9
15
  readonly value: T;
@@ -22,6 +22,7 @@ export { Input, InputChannel, type InputKeyEvent, type InputGamepadEvent, type I
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
24
  export { __rpc, __channel, __serverOnly, RpcError } from "./runtime/rpc";
25
+ export { resource, action, dataOf, failureOf, type Loaded, type Failure, type Resource, type Action } from "./runtime/resource";
25
26
  export type { ChannelSubscription } from "./server/channel";
26
27
  export type { StoredFile, StoredImage } from "./server/files/models";
27
28
  export { AudioPlayer, VideoPlayer } from "./runtime/media";
@@ -0,0 +1,49 @@
1
+ import { type Computed } from "../core/signals";
2
+ /** Why a call failed: the server's refusal in its words — or `offline`, the request never reached
3
+ * it (then `message` is the transport's note, not something to show; say it in your own words). */
4
+ export type Failure = {
5
+ readonly message: string;
6
+ readonly offline: boolean;
7
+ };
8
+ /** What was asked of the server, at any moment: one value a screen draws in its three states. */
9
+ export type Loaded<T> = {
10
+ readonly state: "loading";
11
+ } | {
12
+ readonly state: "ready";
13
+ readonly data: T;
14
+ } | ({
15
+ readonly state: "failed";
16
+ } & Failure);
17
+ /** The data once it is there; `otherwise` until then. */
18
+ export declare const dataOf: <T>(loaded: Loaded<T>, otherwise: T) => T;
19
+ /** The failure, or null while there is none. */
20
+ export declare const failureOf: <T>(loaded: Loaded<T>) => Failure | null;
21
+ export interface Resource<T> {
22
+ /** The request now — read in an effect, a computed or a binding, the screen follows it. */
23
+ readonly value: Loaded<T>;
24
+ /** Read without subscribing. */
25
+ peek(): Loaded<T>;
26
+ /** Ask again. What is shown stays until the answer. */
27
+ reload(): void;
28
+ }
29
+ /**
30
+ * What `load` answers, as a `Loaded` signal: asked at once, again when a signal `load` read changes
31
+ * and on `reload()`. An answer that arrives after a newer request was made is dropped. While the
32
+ * data is asked for again, what is there stays. With `initial` — rows the bundle carries — the data
33
+ * is ready from the start and the server's answer replaces it; a failure then leaves it as it is,
34
+ * since what is shown is real.
35
+ */
36
+ export declare function resource<T>(load: () => Promise<T>, options?: {
37
+ initial?: T;
38
+ }): Resource<T>;
39
+ export type Action<A extends unknown[], R> = ((...args: A) => Promise<R | null>) & {
40
+ /** True while a call runs; a call made meanwhile is ignored (it resolves to null). */
41
+ readonly busy: Computed<boolean>;
42
+ /** Why the last call failed; null when it did not. Cleared as a call starts. */
43
+ readonly error: Computed<Failure | null>;
44
+ };
45
+ /**
46
+ * Something the person does that the server must carry out. Resolves to what the server answered,
47
+ * or null when the call failed (then `error` says why) or was ignored while busy.
48
+ */
49
+ export declare function action<A extends unknown[], R>(run: (...args: A) => Promise<R>): Action<A, R>;
@@ -282,6 +282,10 @@ export interface Query<T extends ModelTypes, Sel = T["scalars"]> extends Promise
282
282
  }>;
283
283
  aggregate<A extends T["aggregate"]>(query: A): Op<AggregateResult<T["model"], A>> & Sub<T["name"], NoInfer<A>>;
284
284
  insert(data: T["insert"]): Op<T["id"]>;
285
+ /** The new row by `select`'s shape — its defaults, dates and files as stored: one call, nothing to read back. */
286
+ insert<S extends T["query"]>(data: T["insert"], options: {
287
+ select: S;
288
+ }): Promise<Rows<T, S>>;
285
289
  update(id: IdArg<T["id"]>, data: T["update"]): Op<void>;
286
290
  /** Applies `data` to every row the chain's `where` matches (all rows without one); resolves to the number of rows. */
287
291
  updateMany(data: T["update"]): Op<number>;
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import type { Field, FieldMeta } from "./fields";
10
10
  import type { IdentityPublicFields, SessionPublicFields } from "../auth/models";
11
- import type { StoredFile, UploadedFile as File } from "../files/models";
11
+ import type { FileWrite, StoredFile } from "../files/models";
12
12
  import type { CompareNumValue, CompareRefListValue, CompareRefValue, CompareStrValue, CompareValue, CustomSearchValue, FullTextSearch, JsonCondition, JsonPathWhere, Op, PrimitiveListUpdate, Query as MarciQuery, RefListUpdate, RefListUpdateOrdered, RefUpdate, RefUpdateStruct, Rows, Sub, UpdateNumValue, VectorSearch, WhereValue } from "./marci/query";
13
13
  export type Fields = Record<string, Field<any, any>>;
14
14
  export type Model<F extends Fields = Fields> = {
@@ -66,7 +66,7 @@ export type Scalars<S, N extends keyof S> = Pick<Row<S, N>, (ScalarKeys<FieldsOf
66
66
  export type ScalarSelect<S, N extends keyof S> = {
67
67
  [K in (ScalarKeys<FieldsOf<S[N]>> | keyof Id<S, N>) & keyof Row<S, N>]: true;
68
68
  };
69
- type FieldInsert<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M["kind"] extends "one" ? Nullable<M, Id<S, ModelName<S, Fld>>> : M["kind"] extends "many" | "list" ? Id<S, ModelName<S, Fld>>[] : M["kind"] extends "struct" ? Nullable<M, StructInsert<S, StructFieldsOf<Fld>>> : M["kind"] extends "file" ? Nullable<M, Arr<M, File>> : Nullable<M, Arr<M, TsOf<Fld>>>;
69
+ type FieldInsert<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M["kind"] extends "one" ? Nullable<M, Id<S, ModelName<S, Fld>>> : M["kind"] extends "many" | "list" ? Id<S, ModelName<S, Fld>>[] : M["kind"] extends "struct" ? Nullable<M, StructInsert<S, StructFieldsOf<Fld>>> : M["kind"] extends "file" ? Nullable<M, Arr<M, FileWrite>> : Nullable<M, Arr<M, TsOf<Fld>>>;
70
70
  type RequiredKeys<F extends Fields> = {
71
71
  [K in keyof F]: K extends IdKeys<F> ? never : MetaOf<F[K]>["optional"] extends true ? never : MetaOf<F[K]>["hasDefault"] extends true ? never : MetaOf<F[K]>["kind"] extends "many" | "list" ? never : MetaOf<F[K]>["kind"] extends "file" ? (MetaOf<F[K]>["array"] extends true ? never : K) : K;
72
72
  }[keyof F];
@@ -80,7 +80,7 @@ type InsertOf<S, F extends Fields> = Simplify<{
80
80
  }>;
81
81
  export type Insert<S, N extends keyof S> = InsertOf<S, FieldsOf<S[N]>>;
82
82
  type StructInsert<S, F extends Fields> = InsertOf<S, F>;
83
- type FieldUpdate<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M["kind"] extends "one" ? Nullable<M, RefUpdate<Id<S, ModelName<S, Fld>>>> : M["kind"] extends "many" ? RefListUpdate<Id<S, ModelName<S, Fld>>> : M["kind"] extends "list" ? RefListUpdateOrdered<Id<S, ModelName<S, Fld>>> : M["kind"] extends "struct" ? RefUpdateStruct<StructInsert<S, StructFieldsOf<Fld>>, UpdateOf<S, StructFieldsOf<Fld>>> | null : M["kind"] extends "file" ? Nullable<M, Arr<M, File | StoredFile>> : M["array"] extends true ? TsOf<Fld>[] | PrimitiveListUpdate<TsOf<Fld>> : Nullable<M, TsOf<Fld> | (IsNum<M> extends true ? UpdateNumValue : never)>;
83
+ type FieldUpdate<S, Fld, M extends FieldMeta = MetaOf<Fld>> = M["kind"] extends "one" ? Nullable<M, RefUpdate<Id<S, ModelName<S, Fld>>>> : M["kind"] extends "many" ? RefListUpdate<Id<S, ModelName<S, Fld>>> : M["kind"] extends "list" ? RefListUpdateOrdered<Id<S, ModelName<S, Fld>>> : M["kind"] extends "struct" ? RefUpdateStruct<StructInsert<S, StructFieldsOf<Fld>>, UpdateOf<S, StructFieldsOf<Fld>>> | null : M["kind"] extends "file" ? Nullable<M, Arr<M, FileWrite | StoredFile>> : M["array"] extends true ? TsOf<Fld>[] | PrimitiveListUpdate<TsOf<Fld>> : Nullable<M, TsOf<Fld> | (IsNum<M> extends true ? UpdateNumValue : never)>;
84
84
  type UpdateOf<S, F extends Fields> = {
85
85
  [K in Exclude<keyof F, IdKeys<F>>]?: FieldUpdate<S, F[K]>;
86
86
  };
@@ -44,6 +44,13 @@ export type UploadedFile = {
44
44
  readonly size: number;
45
45
  readonly type: string;
46
46
  };
47
+ /** What a file field is written with. A project's own type check sees the endpoint's `File` as the
48
+ * app's (global.d.ts: a name and a size — the type is read from the bytes on arrival), so the write
49
+ * asks for no more; what arrives is an `UploadedFile`. */
50
+ export type FileWrite = {
51
+ readonly name: string;
52
+ readonly size: number;
53
+ };
47
54
  /** One `t.file()` field of the schema; `image` = it is a `t.image()`, with its rule. */
48
55
  export type FileField = {
49
56
  model: string;
@@ -29,6 +29,13 @@ type InputStyle = {
29
29
  * still work in both modes. Scrolling never dismisses the keyboard on any setting.
30
30
  */
31
31
  keyboardDismiss?: boolean;
32
+ /**
33
+ * Takes the focus when its screen opens — the keyboard is up from the first moment. For a
34
+ * screen made for typing: a composer, a chat, a search, a one-field form; not the first field
35
+ * of a long form. Once per input (a screen shown again does not take the keyboard back); one
36
+ * per screen. The SDK's own behaviour over `focus()`: a design tool shows the screen as it opens.
37
+ */
38
+ autofocus?: boolean;
32
39
  /** Hard cap on the text length — enforced by the host while typing/pasting. */
33
40
  maxLength?: number;
34
41
  /** Auto-capitalization hint; omitted = platform default. */
@@ -7,6 +7,11 @@ export type UIVirtualizedListStyle = DrawableStyle & ElementStyle & {
7
7
  keyboardDismissMode?: "interactive" | "scroll" | "none";
8
8
  };
9
9
  export interface VListConfig<T> {
10
+ /** The rows, read reactively: the list follows the signals this reads, the way a container's
11
+ * function children do. Rows are told apart by `keyOf`; a row whose item is another object
12
+ * re-renders. Appended rows and rows added at the start are told from a rewrite (a chat at
13
+ * its bottom follows what is appended; older history above moves nothing). */
14
+ data: () => T[];
10
15
  /** Stable unique key of an item. */
11
16
  keyOf: (item: T) => string;
12
17
  /** Subtree factory — called when the item enters the window; the subtree lives until it
@@ -23,20 +28,9 @@ export interface VListConfig<T> {
23
28
  inverted?: boolean;
24
29
  }
25
30
  /** A windowed (virtualized) list: only the items near the viewport are mounted — for long feeds
26
- * and chats. Items are keyed; feed it via `setData`/`append`/`prepend`. */
31
+ * and chats. Fed by `data`, a function over signals. */
27
32
  export interface UIVirtualizedList<T = unknown> extends UIElementBase<UIVirtualizedListStyle> {
28
33
  readonly type: "vlist";
29
- /** Replace the data wholesale — vanished keys are unmounted by the window sync. */
30
- setData(items: T[]): this;
31
- /** Append items to the end (auto-scrolls when `inverted` and resting at the bottom). */
32
- append(...items: T[]): this;
33
- /** Insert at the start WITHOUT a scroll jump (the runtime compensates the offset). */
34
- prepend(...items: T[]): this;
35
- /** Update items with the same keys: mounted ones re-render; the cached height persists until
36
- * re-measured. */
37
- update(...items: T[]): this;
38
- /** Remove items by key. */
39
- removeByKey(...keys: string[]): this;
40
34
  /** Number of data items (mounted or not). */
41
35
  readonly itemCount: number;
42
36
  /** The data item under `key`, if any. */
@@ -62,6 +56,7 @@ export declare class VListElement<T> extends Element<"vlist"> implements UIVirtu
62
56
  private readonly erl;
63
57
  private readonly strl;
64
58
  private _refreshCallback?;
59
+ private keys;
65
60
  private items;
66
61
  private mounted;
67
62
  private keyOf;
@@ -74,12 +69,10 @@ export declare class VListElement<T> extends Element<"vlist"> implements UIVirtu
74
69
  private _inited;
75
70
  constructor(config: VListConfig<T>);
76
71
  private _ensure;
77
- private register;
78
- setData(items: T[]): this;
79
- append(...items: T[]): this;
80
- prepend(...items: T[]): this;
81
- update(...items: T[]): this;
82
- removeByKey(...keys: string[]): this;
72
+ /** The data as it is now against what the runtime holds: rows added at the end or at the start
73
+ * are inserts (the runtime anchors the scroll: a chat follows an append, history above moves
74
+ * nothing), rows gone are removals, anything else a rewrite of the keys (measured heights stay). */
75
+ private _apply;
83
76
  get itemCount(): number;
84
77
  getItem(key: string): T | undefined;
85
78
  scrollTo(offset: number, animated?: boolean): void;
@@ -90,6 +83,6 @@ export declare class VListElement<T> extends Element<"vlist"> implements UIVirtu
90
83
  onEndReached(thresholdPx: number, callback: () => void): this;
91
84
  onStartReached(thresholdPx: number, callback: () => void): this;
92
85
  }
93
- /** Create a virtualized list from a config (`keyOf` + `render` + `estimatedHeight` required),
94
- * then feed it via `setData`/`append`/`prepend`. Give it a size (`flexGrow: 1` as a screen body). */
86
+ /** Create a virtualized list from a config (`data` + `keyOf` + `render` + `estimatedHeight`
87
+ * required). Give it a size (`flexGrow: 1` as a screen body). */
95
88
  export declare function UIVirtualizedList<T>(config: VListConfig<T>): UIVirtualizedList<T>;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,4 @@
1
- export declare const SDK_VERSION = "2.1.1";
1
+ export declare const SDK_VERSION = "2.2.1";
2
2
  /** The major of a semver string, or null when it is not one. */
3
3
  export declare const sdkMajor: (version: string | null | undefined) => number | null;
4
4
  /** The `// sdk: <version>` line of a compiled bundle's header (sdk/src/compile/header.ts), read from