castle-web-sdk 0.4.6 → 0.4.7

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 CHANGED
@@ -19,6 +19,7 @@ import { setup, initCard, Storage, Leaderboard } from "castle-web-sdk";
19
19
  - [Time](#time)
20
20
  - [User](#user)
21
21
  - [Pass](#pass)
22
+ - [Lifecycle](#lifecycle)
22
23
  - [Setup](#setup)
23
24
  - [CastleError](#castleerror)
24
25
 
@@ -223,6 +224,30 @@ if (status === "purchased" || status === "alreadyOwned") {
223
224
  }
224
225
  ```
225
226
 
227
+ ## Lifecycle
228
+
229
+ `Lifecycle` tells the host when the deck has painted its first frame, so
230
+ the Castle feed can reveal it right away instead of waiting out a fixed
231
+ delay.
232
+
233
+ ### `Lifecycle.ready()`
234
+
235
+ Signal that the deck has painted its first presentable frame. Idempotent
236
+ — only the first call has any effect.
237
+
238
+ Kits already wire this up to fire as soon as the first frame paints; if
239
+ you change how the deck first renders, make sure it still fires there. If
240
+ nothing calls this, the feed reveals the deck on its own after a brief
241
+ timeout.
242
+
243
+ If you call it right after kicking off your initial render, wait for the
244
+ next paint first so the host doesn't reveal a blank frame:
245
+
246
+ ```js
247
+ createRoot(root).render(<App />);
248
+ requestAnimationFrame(() => requestAnimationFrame(() => Lifecycle.ready()));
249
+ ```
250
+
226
251
  ## Setup
227
252
 
228
253
  Startup, editor-mode check, and a file-write call for editor UI.
package/dist/castle.d.ts CHANGED
@@ -2,6 +2,8 @@ export { isEdit } from "./context";
2
2
  export { CastleError } from "./errors";
3
3
  export { Leaderboard } from "./leaderboard";
4
4
  export type { LeaderboardData, LeaderboardEntry, LeaderboardOptions, LeaderboardScope, LeaderboardSort, } from "./leaderboard";
5
+ export { Lifecycle } from "./lifecycle";
6
+ export type { CastleLifecycleApi } from "./lifecycle";
5
7
  export { Pass } from "./passes";
6
8
  export type { CastlePassApi, PassOfferResult, PassOfferStatus, } from "./passes";
7
9
  export { CARD_RATIO, initCard, onBeforeRestart, setup, writeFile } from "./runtime";
package/dist/castle.js CHANGED
@@ -2,6 +2,7 @@
2
2
  export { isEdit } from "./context";
3
3
  export { CastleError } from "./errors";
4
4
  export { Leaderboard } from "./leaderboard";
5
+ export { Lifecycle } from "./lifecycle";
5
6
  export { Pass } from "./passes";
6
7
  export { CARD_RATIO, initCard, onBeforeRestart, setup, writeFile } from "./runtime";
7
8
  export { SharedStorage, Storage } from "./storage";
@@ -115,3 +115,8 @@ export interface CommandResponseEnvelope {
115
115
  error?: SerializedCommandError;
116
116
  }
117
117
  export declare function isResponseEnvelope(value: unknown): value is CommandResponseEnvelope;
118
+ export type LifecycleEvent = "ready";
119
+ export interface LifecycleEnvelope {
120
+ castleSdk: typeof CASTLE_SDK_PROTOCOL;
121
+ lifecycle: LifecycleEvent;
122
+ }
@@ -0,0 +1,4 @@
1
+ export interface CastleLifecycleApi {
2
+ ready(): void;
3
+ }
4
+ export declare const Lifecycle: CastleLifecycleApi;
@@ -0,0 +1,13 @@
1
+ // Deck-side lifecycle signals. The feed reveals the deck when it reports `ready`
2
+ // (its first presentable frame) instead of waiting out a fixed timer.
3
+ import { hostNotify } from "./transport";
4
+ let readySent = false;
5
+ function ready() {
6
+ if (readySent)
7
+ return;
8
+ readySent = true;
9
+ hostNotify("ready");
10
+ }
11
+ export const Lifecycle = {
12
+ ready,
13
+ };
@@ -1,4 +1,4 @@
1
- import { type CommandName, type CommandParams, type CommandResult } from "./commands";
1
+ import { type CommandName, type CommandParams, type CommandResult, type LifecycleEvent } from "./commands";
2
2
  type PostChannel = "mobile" | "web";
3
3
  interface ReactNativeWebViewBridge {
4
4
  postMessage: (message: string) => void;
@@ -13,4 +13,5 @@ declare global {
13
13
  }
14
14
  export declare function hostRequest<C extends CommandName>(command: C, params: CommandParams[C]): Promise<CommandResult[C]>;
15
15
  export declare function getCommandChannel(): PostChannel | "local";
16
+ export declare function hostNotify(event: LifecycleEvent): void;
16
17
  export {};
package/dist/transport.js CHANGED
@@ -52,6 +52,20 @@ export async function hostRequest(command, params) {
52
52
  export function getCommandChannel() {
53
53
  return resolveChannel();
54
54
  }
55
+ // Fire-and-forget counterpart to hostRequest: no reply, no timeout. The local
56
+ // dev server has no surface to react to lifecycle events, so it's skipped.
57
+ export function hostNotify(event) {
58
+ if (typeof window === "undefined")
59
+ return;
60
+ const channel = resolveChannel();
61
+ if (channel === "local")
62
+ return;
63
+ const envelope = {
64
+ castleSdk: CASTLE_SDK_PROTOCOL,
65
+ lifecycle: event,
66
+ };
67
+ sendEnvelope(channel, envelope);
68
+ }
55
69
  function resolveChannel() {
56
70
  if (typeof window === "undefined")
57
71
  return "local";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "castle-web-sdk",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "type": "module",
5
5
  "main": "dist/castle.js",
6
6
  "types": "dist/castle.d.ts",