@tinyburg/lego-tower-sdk 0.0.0-stage → 0.1.0

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.
@@ -0,0 +1,83 @@
1
+ /**
2
+ * LEGO Tower SDK: signed calls against Nimblebit's NBSync service.
3
+ *
4
+ * Signing reuses `@tinyburg/nimblebit-sdk` (`NimblebitAuth`): the game secret
5
+ * salt (from `NBSync._ss`) is provided as the auth key, and each request is
6
+ * `md5(<preimage> + <secret salt>)` with a random uint32 `salt` in the path.
7
+ * All method preimages below are the Tiny Tower formula with the `lt` game code.
8
+ *
9
+ * The methods that were exercised live against sync.nimblebit.com are marked
10
+ * VERIFIED; save-bearing / write paths follow the same pattern but were not
11
+ * exercised. Save bytes are returned raw (base64-decoded); inflating (pako) and
12
+ * parsing into a save schema is left to the caller.
13
+ *
14
+ * @since 1.0.0
15
+ * @category SDK
16
+ */
17
+ import type * as Schema from "effect/Schema";
18
+ import * as Effect from "effect/Effect";
19
+ import { HttpClient } from "effect/http";
20
+ import * as Redacted from "effect/Redacted";
21
+ import { NimblebitAuth } from "@tinyburg/nimblebit-sdk";
22
+ /**
23
+ * Requests a new player ("burnbot") from the Nimblebit servers. VERIFIED.
24
+ *
25
+ * @since 1.0.0
26
+ * @category SDK
27
+ */
28
+ export declare const device_newPlayer: Effect.Effect<{
29
+ readonly playerId: string & import("effect/Brand").Brand<"PlayerId">;
30
+ readonly playerSs: Redacted.Redacted<string> & import("effect/Brand").Brand<"PlayerAuthKey">;
31
+ }, import("effect/http-api/HttpApiError").BadRequest | import("effect/http-api/HttpApiError").Forbidden | import("effect/http/HttpClientError").HttpClientError | import("effect/http-api/HttpApiError").InternalServerError | import("@tinyburg/nimblebit-sdk/internal/Error").NimblebitError | import("effect/PlatformError").PlatformError | Schema.SchemaError | import("effect/http-api/HttpApiError").Unauthorized, HttpClient.HttpClient | NimblebitAuth.NimblebitAuth>;
32
+ /**
33
+ * Retrieves player details. VERIFIED.
34
+ *
35
+ * @since 1.0.0
36
+ * @category SDK
37
+ */
38
+ export declare const device_playerDetails: (args_0: {
39
+ readonly playerAuthKey: Redacted.Redacted<string> & import("effect/Brand").Brand<"PlayerAuthKey">;
40
+ readonly playerId: string & import("effect/Brand").Brand<"PlayerId">;
41
+ }) => Effect.Effect<{
42
+ readonly playerId: string & import("effect/Brand").Brand<"PlayerId">;
43
+ readonly playerEmail: Redacted.Redacted<string> & import("effect/Brand").Brand<"PlayerEmail">;
44
+ readonly registered: boolean;
45
+ readonly blacklisted: boolean;
46
+ readonly saveVersion: number;
47
+ readonly checksum: string;
48
+ }, import("effect/http-api/HttpApiError").BadRequest | import("effect/http-api/HttpApiError").Forbidden | import("effect/http/HttpClientError").HttpClientError | import("effect/http-api/HttpApiError").InternalServerError | import("@tinyburg/nimblebit-sdk/internal/Error").NimblebitError | import("effect/PlatformError").PlatformError | Schema.SchemaError | import("effect/http-api/HttpApiError").Unauthorized, HttpClient.HttpClient | NimblebitAuth.NimblebitAuth>;
49
+ /**
50
+ * Pulls the player's cloud save. Returns raw base64-decoded bytes (inflate +
51
+ * parse separately). Success envelope DERIVED from Tiny Tower.
52
+ *
53
+ * @since 1.0.0
54
+ * @category SDK
55
+ */
56
+ export declare const sync_pullSave: (args_0: {
57
+ readonly playerAuthKey: Redacted.Redacted<string> & import("effect/Brand").Brand<"PlayerAuthKey">;
58
+ readonly playerId: string & import("effect/Brand").Brand<"PlayerId">;
59
+ }) => Effect.Effect<{
60
+ readonly success: "NotFound";
61
+ } | {
62
+ readonly success: "Found";
63
+ readonly data: Uint8Array<ArrayBufferLike>;
64
+ readonly checksum: string;
65
+ readonly saveId: number;
66
+ }, import("effect/http-api/HttpApiError").BadRequest | import("effect/http-api/HttpApiError").Forbidden | import("effect/http/HttpClientError").HttpClientError | import("effect/http-api/HttpApiError").InternalServerError | import("@tinyburg/nimblebit-sdk/internal/Error").NimblebitError | import("effect/PlatformError").PlatformError | Schema.SchemaError | import("effect/http-api/HttpApiError").Unauthorized, HttpClient.HttpClient | NimblebitAuth.NimblebitAuth>;
67
+ /**
68
+ * Lists items (parts/gifts) waiting for the player. VERIFIED
69
+ * (`/get_items/pt/...` -> `{ success:"Found", gifts:[...] }`, no total).
70
+ *
71
+ * @since 1.0.0
72
+ * @category SDK
73
+ */
74
+ export declare const social_getItems: (args_0: {
75
+ readonly playerAuthKey: Redacted.Redacted<string> & import("effect/Brand").Brand<"PlayerAuthKey">;
76
+ readonly playerId: string & import("effect/Brand").Brand<"PlayerId">;
77
+ }) => Effect.Effect<{
78
+ readonly success: "NotFound";
79
+ } | {
80
+ readonly success: "Found";
81
+ readonly gifts: readonly unknown[];
82
+ }, import("effect/http-api/HttpApiError").BadRequest | import("effect/http-api/HttpApiError").Forbidden | import("effect/http/HttpClientError").HttpClientError | import("effect/http-api/HttpApiError").InternalServerError | import("@tinyburg/nimblebit-sdk/internal/Error").NimblebitError | import("effect/PlatformError").PlatformError | Schema.SchemaError | import("effect/http-api/HttpApiError").Unauthorized, HttpClient.HttpClient | NimblebitAuth.NimblebitAuth>;
83
+ //# sourceMappingURL=LegoTower.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LegoTower.d.ts","sourceRoot":"","sources":["../src/LegoTower.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAE7C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAI5C,OAAO,EAAE,aAAa,EAAkB,MAAM,yBAAyB,CAAC;AAIxE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;;8cA6B3B,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;8cA+B/B,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;8cA+BxB,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;;;;;;8cA+B1B,CAAC"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * LEGO Tower SDK: signed calls against Nimblebit's NBSync service.
3
+ *
4
+ * Signing reuses `@tinyburg/nimblebit-sdk` (`NimblebitAuth`): the game secret
5
+ * salt (from `NBSync._ss`) is provided as the auth key, and each request is
6
+ * `md5(<preimage> + <secret salt>)` with a random uint32 `salt` in the path.
7
+ * All method preimages below are the Tiny Tower formula with the `lt` game code.
8
+ *
9
+ * The methods that were exercised live against sync.nimblebit.com are marked
10
+ * VERIFIED; save-bearing / write paths follow the same pattern but were not
11
+ * exercised. Save bytes are returned raw (base64-decoded); inflating (pako) and
12
+ * parsing into a save schema is left to the caller.
13
+ *
14
+ * @since 1.0.0
15
+ * @category SDK
16
+ */
17
+ import * as Effect from "effect/Effect";
18
+ import * as Function from "effect/Function";
19
+ import { HttpClient, HttpClientRequest } from "effect/http";
20
+ import { HttpApiClient } from "effect/http-api";
21
+ import * as Redacted from "effect/Redacted";
22
+ import { NimblebitAuth, NimblebitError } from "@tinyburg/nimblebit-sdk";
23
+ import * as Endpoints from "./Endpoints.js";
24
+ /**
25
+ * Requests a new player ("burnbot") from the Nimblebit servers. VERIFIED.
26
+ *
27
+ * @since 1.0.0
28
+ * @category SDK
29
+ */
30
+ export const device_newPlayer = /*#__PURE__*/Effect.gen(function* () {
31
+ const nimblebitAuth = yield* NimblebitAuth.NimblebitAuth;
32
+ const httpClient = yield* HttpClient.HttpClient;
33
+ const maybeAddBearerToken = nimblebitAuth.host !== "https://sync.nimblebit.com" ? HttpClientRequest.bearerToken(nimblebitAuth.authKey) : Function.identity;
34
+ const endpoint = yield* HttpApiClient.endpoint(Endpoints.Api, {
35
+ baseUrl: nimblebitAuth.host,
36
+ group: "DeviceManagementGroup",
37
+ endpoint: "DeviceNewPlayer",
38
+ httpClient: HttpClient.mapRequest(httpClient, maybeAddBearerToken)
39
+ });
40
+ const salt1 = yield* nimblebitAuth.salt;
41
+ const salt2 = yield* nimblebitAuth.salt;
42
+ const hash = yield* nimblebitAuth.sign(`lt/${salt1}/${salt2}`);
43
+ const response = yield* endpoint({
44
+ params: {
45
+ salt1,
46
+ salt2,
47
+ hash
48
+ }
49
+ });
50
+ if ("error" in response) {
51
+ return yield* new NimblebitError.NimblebitError({
52
+ method: "DeviceNewPlayer",
53
+ module: "DeviceManagementGroup",
54
+ cause: response.error
55
+ });
56
+ }
57
+ return response;
58
+ });
59
+ /**
60
+ * Retrieves player details. VERIFIED.
61
+ *
62
+ * @since 1.0.0
63
+ * @category SDK
64
+ */
65
+ export const device_playerDetails = /*#__PURE__*/Effect.fn("device_playerDetails")(function* ({
66
+ playerAuthKey,
67
+ playerId
68
+ }) {
69
+ const nimblebitAuth = yield* NimblebitAuth.NimblebitAuth;
70
+ const httpClient = yield* HttpClient.HttpClient;
71
+ const maybeAddBearerToken = nimblebitAuth.host !== "https://sync.nimblebit.com" ? HttpClientRequest.bearerToken(nimblebitAuth.authKey) : Function.identity;
72
+ const endpoint = yield* HttpApiClient.endpoint(Endpoints.Api, {
73
+ baseUrl: nimblebitAuth.host,
74
+ group: "DeviceManagementGroup",
75
+ endpoint: "DevicePlayerDetails",
76
+ httpClient: HttpClient.mapRequest(httpClient, maybeAddBearerToken)
77
+ });
78
+ const salt = yield* nimblebitAuth.salt;
79
+ const hash = yield* nimblebitAuth.sign(`lt/${playerId}/${salt}${Redacted.value(playerAuthKey)}`);
80
+ const response = yield* endpoint({
81
+ params: {
82
+ playerId,
83
+ salt,
84
+ hash
85
+ }
86
+ });
87
+ if ("error" in response) {
88
+ return yield* new NimblebitError.NimblebitError({
89
+ method: "DevicePlayerDetails",
90
+ module: "DeviceManagementGroup",
91
+ cause: response.error
92
+ });
93
+ }
94
+ return response.player;
95
+ });
96
+ /**
97
+ * Pulls the player's cloud save. Returns raw base64-decoded bytes (inflate +
98
+ * parse separately). Success envelope DERIVED from Tiny Tower.
99
+ *
100
+ * @since 1.0.0
101
+ * @category SDK
102
+ */
103
+ export const sync_pullSave = /*#__PURE__*/Effect.fn("sync_pullSave")(function* ({
104
+ playerAuthKey,
105
+ playerId
106
+ }) {
107
+ const nimblebitAuth = yield* NimblebitAuth.NimblebitAuth;
108
+ const httpClient = yield* HttpClient.HttpClient;
109
+ const maybeAddBearerToken = nimblebitAuth.host !== "https://sync.nimblebit.com" ? HttpClientRequest.bearerToken(nimblebitAuth.authKey) : Function.identity;
110
+ const endpoint = yield* HttpApiClient.endpoint(Endpoints.Api, {
111
+ baseUrl: nimblebitAuth.host,
112
+ group: "SyncManagementGroup",
113
+ endpoint: "SyncPullSave",
114
+ httpClient: HttpClient.mapRequest(httpClient, maybeAddBearerToken)
115
+ });
116
+ const salt = yield* nimblebitAuth.salt;
117
+ const hash = yield* nimblebitAuth.sign(`lt/${playerId}/${salt}${Redacted.value(playerAuthKey)}`);
118
+ const response = yield* endpoint({
119
+ params: {
120
+ playerId,
121
+ salt,
122
+ hash
123
+ }
124
+ });
125
+ if ("error" in response) {
126
+ return yield* new NimblebitError.NimblebitError({
127
+ method: "SyncPullSave",
128
+ module: "SyncManagementGroup",
129
+ cause: response.error
130
+ });
131
+ }
132
+ return response;
133
+ });
134
+ /**
135
+ * Lists items (parts/gifts) waiting for the player. VERIFIED
136
+ * (`/get_items/pt/...` -> `{ success:"Found", gifts:[...] }`, no total).
137
+ *
138
+ * @since 1.0.0
139
+ * @category SDK
140
+ */
141
+ export const social_getItems = /*#__PURE__*/Effect.fn("social_getItems")(function* ({
142
+ playerAuthKey,
143
+ playerId
144
+ }) {
145
+ const nimblebitAuth = yield* NimblebitAuth.NimblebitAuth;
146
+ const httpClient = yield* HttpClient.HttpClient;
147
+ const maybeAddBearerToken = nimblebitAuth.host !== "https://sync.nimblebit.com" ? HttpClientRequest.bearerToken(nimblebitAuth.authKey) : Function.identity;
148
+ const endpoint = yield* HttpApiClient.endpoint(Endpoints.Api, {
149
+ baseUrl: nimblebitAuth.host,
150
+ group: "SocialGroup",
151
+ endpoint: "SocialGetItems",
152
+ httpClient: HttpClient.mapRequest(httpClient, maybeAddBearerToken)
153
+ });
154
+ const salt = yield* nimblebitAuth.salt;
155
+ const hash = yield* nimblebitAuth.sign(`lt/${playerId}/${salt}${Redacted.value(playerAuthKey)}`);
156
+ const response = yield* endpoint({
157
+ params: {
158
+ playerId,
159
+ salt,
160
+ hash
161
+ }
162
+ });
163
+ if ("error" in response) {
164
+ return yield* new NimblebitError.NimblebitError({
165
+ method: "SocialGetItems",
166
+ module: "SocialGroup",
167
+ cause: response.error
168
+ });
169
+ }
170
+ return response;
171
+ });
172
+ //# sourceMappingURL=LegoTower.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LegoTower.js","names":[],"sources":["../src/LegoTower.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * The scopes the LEGO Tower api is guarded by, as a game-rooted tree, built with
3
+ * `@tinyburg/nimblebit-sdk`'s `defineGame`. Only the endpoints this sdk defines
4
+ * are covered; areas without both a read and a write side are left out until
5
+ * their endpoints exist.
6
+ *
7
+ * @since 1.0.0
8
+ * @category Scopes
9
+ */
10
+ import { type Game, type ScopeDescription } from "@tinyburg/nimblebit-sdk/NimblebitScopes";
11
+ /**
12
+ * @since 1.0.0
13
+ * @category Games
14
+ */
15
+ export declare const LEGOTower: Game & {
16
+ readonly areas: {
17
+ readonly device: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Area & {
18
+ readonly read: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Branch & {
19
+ readonly player_details: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
20
+ };
21
+ readonly write: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Branch & {
22
+ readonly verify_device: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
23
+ };
24
+ };
25
+ readonly social: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Area & {
26
+ readonly read: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Branch & {
27
+ readonly get_items: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
28
+ readonly get_visits: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
29
+ readonly pull_friend_game: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
30
+ readonly pull_friend_meta: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
31
+ };
32
+ readonly write: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Branch & {
33
+ readonly send_item: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
34
+ };
35
+ };
36
+ };
37
+ };
38
+ /**
39
+ * The game's areas, by name, for annotating endpoints.
40
+ *
41
+ * @since 1.0.0
42
+ * @category Areas
43
+ */
44
+ export declare const Device: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Area & {
45
+ readonly read: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Branch & {
46
+ readonly player_details: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
47
+ };
48
+ readonly write: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Branch & {
49
+ readonly verify_device: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
50
+ };
51
+ }, Social: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Area & {
52
+ readonly read: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Branch & {
53
+ readonly get_items: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
54
+ readonly get_visits: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
55
+ readonly pull_friend_game: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
56
+ readonly pull_friend_meta: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
57
+ };
58
+ readonly write: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Branch & {
59
+ readonly send_item: import("@tinyburg/nimblebit-sdk/NimblebitScopes").Leaf;
60
+ };
61
+ };
62
+ /**
63
+ * @since 1.0.0
64
+ * @category Tree
65
+ */
66
+ export declare const Games: ReadonlyArray<Game>;
67
+ /**
68
+ * @since 1.0.0
69
+ * @category Tree
70
+ */
71
+ export declare const all: () => ReadonlyArray<ScopeDescription>;
72
+ //# sourceMappingURL=Scopes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Scopes.d.ts","sourceRoot":"","sources":["../src/Scopes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,gBAAgB,EAAc,MAAM,yCAAyC,CAAC;AAEvG;;;GAGG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;CAwCpB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAgB,MAAM;;;;;;;GAAU,MAAM;;;;;;;;;;CAAoB,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,aAAa,CAAC,IAAI,CAAe,CAAC;AAEtD;;;GAGG;AACH,eAAO,MAAM,GAAG,QAAO,aAAa,CAAC,gBAAgB,CAY/C,CAAC"}
package/dist/Scopes.js ADDED
@@ -0,0 +1,80 @@
1
+ /**
2
+ * The scopes the LEGO Tower api is guarded by, as a game-rooted tree, built with
3
+ * `@tinyburg/nimblebit-sdk`'s `defineGame`. Only the endpoints this sdk defines
4
+ * are covered; areas without both a read and a write side are left out until
5
+ * their endpoints exist.
6
+ *
7
+ * @since 1.0.0
8
+ * @category Scopes
9
+ */
10
+ import { defineGame } from "@tinyburg/nimblebit-sdk/NimblebitScopes";
11
+ /**
12
+ * @since 1.0.0
13
+ * @category Games
14
+ */
15
+ export const LEGOTower = /*#__PURE__*/defineGame({
16
+ name: "legotower",
17
+ description: "LEGO Tower",
18
+ read: {
19
+ description: "Everything in LEGO Tower that only looks"
20
+ },
21
+ write: {
22
+ description: "Everything in LEGO Tower that changes a player's game"
23
+ },
24
+ areas: {
25
+ device: {
26
+ description: "Player accounts and their devices",
27
+ read: {
28
+ description: "Look up player accounts",
29
+ leaves: {
30
+ player_details: "Look up a player's public profile details"
31
+ }
32
+ },
33
+ write: {
34
+ description: "Change a player's account or devices",
35
+ leaves: {
36
+ verify_device: "Complete a device verification code"
37
+ }
38
+ }
39
+ },
40
+ social: {
41
+ description: "Gifts, visits and friends",
42
+ read: {
43
+ description: "See gifts, visits and friends' games",
44
+ leaves: {
45
+ get_items: "See the items waiting for a player",
46
+ get_visits: "See who has visited a player",
47
+ pull_friend_game: "Download a friend's game data",
48
+ pull_friend_meta: "Fetch metadata about a player's friends"
49
+ }
50
+ },
51
+ write: {
52
+ description: "Send and accept gifts and items",
53
+ leaves: {
54
+ send_item: "Send items to another player"
55
+ }
56
+ }
57
+ }
58
+ }
59
+ });
60
+ /**
61
+ * The game's areas, by name, for annotating endpoints.
62
+ *
63
+ * @since 1.0.0
64
+ * @category Areas
65
+ */
66
+ export const {
67
+ device: Device,
68
+ social: Social
69
+ } = LEGOTower.areas;
70
+ /**
71
+ * @since 1.0.0
72
+ * @category Tree
73
+ */
74
+ export const Games = [LEGOTower];
75
+ /**
76
+ * @since 1.0.0
77
+ * @category Tree
78
+ */
79
+ export const all = () => Games.flatMap(game => [game, game.read, game.write, ...Object.values(game.areas).flatMap(area => [area, area.read, ...area.read.children, area.write, ...area.write.children])]);
80
+ //# sourceMappingURL=Scopes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Scopes.js","names":[],"sources":["../src/Scopes.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;;;;;AAUA,SAA2C,UAAU,QAAQ,yCAAyC;AAEtG;;;;AAIA,OAAO,MAAM,SAAS,gBAAG,UAAU,CAAC;EAChC,IAAI,EAAE,WAAW;EACjB,WAAW,EAAE,YAAY;EACzB,IAAI,EAAE;IAAE,WAAW,EAAE;EAA0C,CAAE;EACjE,KAAK,EAAE;IAAE,WAAW,EAAE;EAAuD,CAAE;EAC/E,KAAK,EAAE;IACH,MAAM,EAAE;MACJ,WAAW,EAAE,mCAAmC;MAChD,IAAI,EAAE;QACF,WAAW,EAAE,yBAAyB;QACtC,MAAM,EAAE;UACJ,cAAc,EAAE;;OAEvB;MACD,KAAK,EAAE;QACH,WAAW,EAAE,sCAAsC;QACnD,MAAM,EAAE;UACJ,aAAa,EAAE;;;KAG1B;IACD,MAAM,EAAE;MACJ,WAAW,EAAE,2BAA2B;MACxC,IAAI,EAAE;QACF,WAAW,EAAE,sCAAsC;QACnD,MAAM,EAAE;UACJ,SAAS,EAAE,oCAAoC;UAC/C,UAAU,EAAE,8BAA8B;UAC1C,gBAAgB,EAAE,+BAA+B;UACjD,gBAAgB,EAAE;;OAEzB;MACD,KAAK,EAAE;QACH,WAAW,EAAE,iCAAiC;QAC9C,MAAM,EAAE;UACJ,SAAS,EAAE;;;;;CAK9B,CAAC;AAEF;;;;;;AAMA,OAAO,MAAM;EAAE,MAAM,EAAE,MAAM;EAAE,MAAM,EAAE;AAAM,CAAE,GAAG,SAAS,CAAC,KAAK;AAEjE;;;;AAIA,OAAO,MAAM,KAAK,GAAwB,CAAC,SAAS,CAAC;AAErD;;;;AAIA,OAAO,MAAM,GAAG,GAAG,MACf,KAAK,CAAC,OAAO,CAAE,IAAI,IAAK,CACpB,IAAI,EACJ,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,KAAK,EACV,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAE,IAAI,IAAK,CAC3C,IAAI,EACJ,IAAI,CAAC,IAAI,EACT,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EACrB,IAAI,CAAC,KAAK,EACV,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CACzB,CAAC,CACL,CAAC","ignoreList":[]}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ /**
5
+ * LEGO Tower (game code `lt`) NBSync api endpoints.
6
+ *
7
+ * Signing: a random `salt` (signed int32) goes in the path, and `hash` is
8
+ * `md5(<preimage> + <game secret salt>)` with the preimage
9
+ * `lt/<playerId>/<salt><playerAuthKey>` (variants noted per endpoint). The
10
+ * secret salt is the value extracted from `NBSync._ss`.
11
+ *
12
+ * Verification (live server + Frida DTO inspection of the game, 2026-08-26):
13
+ * - Signing is MD5, server-validated (same scheme as Tiny Tower / Pocket
14
+ * Planes; the game computes SHA-256 only for the unauthenticated `register`).
15
+ * - Response envelopes VERIFIED by reading the game's DTO classes at runtime:
16
+ * register, player_details, sync/pull (NBSyncGameSaveResponse), current_version,
17
+ * verify_device, friend/pull_game, friend/pull_meta (meta is a flat
18
+ * Dictionary<String,Object> on pt), send_item (NBSyncItemsSendResponse),
19
+ * get_items (NBSyncItemsGetResponse: success/gifts, NO `total` unlike pp).
20
+ * `get_items` was also exercised live with a burnbot.
21
+ * - Rich endpoint set: adds snapshots, trades, mailbox, AG, and LL-friends.
22
+ * - LEGO Tower issues player ids longer than 5 chars (relaxed PlayerId schema).
23
+ *
24
+ * Game-specific save/meta schemas are left as `Schema.Unknown` placeholders.
25
+ *
26
+ * @since 1.0.0
27
+ * @category Endpoints
28
+ */
29
+ export * as Endpoints from "./Endpoints.ts";
30
+ /**
31
+ * LEGO Tower SDK: signed calls against Nimblebit's NBSync service.
32
+ *
33
+ * Signing reuses `@tinyburg/nimblebit-sdk` (`NimblebitAuth`): the game secret
34
+ * salt (from `NBSync._ss`) is provided as the auth key, and each request is
35
+ * `md5(<preimage> + <secret salt>)` with a random uint32 `salt` in the path.
36
+ * All method preimages below are the Tiny Tower formula with the `lt` game code.
37
+ *
38
+ * The methods that were exercised live against sync.nimblebit.com are marked
39
+ * VERIFIED; save-bearing / write paths follow the same pattern but were not
40
+ * exercised. Save bytes are returned raw (base64-decoded); inflating (pako) and
41
+ * parsing into a save schema is left to the caller.
42
+ *
43
+ * @since 1.0.0
44
+ * @category SDK
45
+ */
46
+ export * as LegoTower from "./LegoTower.ts";
47
+ /**
48
+ * The scopes the LEGO Tower api is guarded by, as a game-rooted tree, built with
49
+ * `@tinyburg/nimblebit-sdk`'s `defineGame`. Only the endpoints this sdk defines
50
+ * are covered; areas without both a read and a write side are left out until
51
+ * their endpoints exist.
52
+ *
53
+ * @since 1.0.0
54
+ * @category Scopes
55
+ */
56
+ export * as Scopes from "./Scopes.ts";
57
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAE3C;;;;;;;;GAQG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ /**
5
+ * LEGO Tower (game code `lt`) NBSync api endpoints.
6
+ *
7
+ * Signing: a random `salt` (signed int32) goes in the path, and `hash` is
8
+ * `md5(<preimage> + <game secret salt>)` with the preimage
9
+ * `lt/<playerId>/<salt><playerAuthKey>` (variants noted per endpoint). The
10
+ * secret salt is the value extracted from `NBSync._ss`.
11
+ *
12
+ * Verification (live server + Frida DTO inspection of the game, 2026-08-26):
13
+ * - Signing is MD5, server-validated (same scheme as Tiny Tower / Pocket
14
+ * Planes; the game computes SHA-256 only for the unauthenticated `register`).
15
+ * - Response envelopes VERIFIED by reading the game's DTO classes at runtime:
16
+ * register, player_details, sync/pull (NBSyncGameSaveResponse), current_version,
17
+ * verify_device, friend/pull_game, friend/pull_meta (meta is a flat
18
+ * Dictionary<String,Object> on pt), send_item (NBSyncItemsSendResponse),
19
+ * get_items (NBSyncItemsGetResponse: success/gifts, NO `total` unlike pp).
20
+ * `get_items` was also exercised live with a burnbot.
21
+ * - Rich endpoint set: adds snapshots, trades, mailbox, AG, and LL-friends.
22
+ * - LEGO Tower issues player ids longer than 5 chars (relaxed PlayerId schema).
23
+ *
24
+ * Game-specific save/meta schemas are left as `Schema.Unknown` placeholders.
25
+ *
26
+ * @since 1.0.0
27
+ * @category Endpoints
28
+ */
29
+ export * as Endpoints from "./Endpoints.js";
30
+ /**
31
+ * LEGO Tower SDK: signed calls against Nimblebit's NBSync service.
32
+ *
33
+ * Signing reuses `@tinyburg/nimblebit-sdk` (`NimblebitAuth`): the game secret
34
+ * salt (from `NBSync._ss`) is provided as the auth key, and each request is
35
+ * `md5(<preimage> + <secret salt>)` with a random uint32 `salt` in the path.
36
+ * All method preimages below are the Tiny Tower formula with the `lt` game code.
37
+ *
38
+ * The methods that were exercised live against sync.nimblebit.com are marked
39
+ * VERIFIED; save-bearing / write paths follow the same pattern but were not
40
+ * exercised. Save bytes are returned raw (base64-decoded); inflating (pako) and
41
+ * parsing into a save schema is left to the caller.
42
+ *
43
+ * @since 1.0.0
44
+ * @category SDK
45
+ */
46
+ export * as LegoTower from "./LegoTower.js";
47
+ /**
48
+ * The scopes the LEGO Tower api is guarded by, as a game-rooted tree, built with
49
+ * `@tinyburg/nimblebit-sdk`'s `defineGame`. Only the endpoints this sdk defines
50
+ * are covered; areas without both a read and a write side are left out until
51
+ * their endpoints exist.
52
+ *
53
+ * @since 1.0.0
54
+ * @category Scopes
55
+ */
56
+ export * as Scopes from "./Scopes.js";
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA;;;AAIA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,OAAO,KAAK,SAAS,MAAM,gBAAgB;AAE3C;;;;;;;;;;;;;;;;AAgBA,OAAO,KAAK,SAAS,MAAM,gBAAgB;AAE3C;;;;;;;;;AASA,OAAO,KAAK,MAAM,MAAM,aAAa","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,51 @@
1
1
  {
2
2
  "name": "@tinyburg/lego-tower-sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "api for the mobile game LEGO Tower by Nimblebit",
5
+ "keywords": [
6
+ "lego-tower-sdk",
7
+ "nimblebit"
8
+ ],
9
+ "homepage": "https://github.com/leonitousconforti/tinyburg",
10
+ "license": "GPL-3.0-only",
11
+ "author": "Leo Conforti <leo@leoconforti.us> (https://leoconforti.us)",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/leonitousconforti/tinyburg.git",
15
+ "directory": "packages/lego-tower-sdk"
16
+ },
17
+ "files": [
18
+ "src/**/*.ts",
19
+ "dist/**/*.js",
20
+ "dist/**/*.js.map",
21
+ "dist/**/*.d.ts",
22
+ "dist/**/*.d.ts.map"
23
+ ],
24
+ "type": "module",
25
+ "sideEffects": false,
26
+ "exports": {
27
+ "./package.json": "./package.json",
28
+ ".": "./dist/index.js",
29
+ "./*": "./dist/*.js",
30
+ "./internal/*": null
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "dependencies": {
36
+ "@tinyburg/nimblebit-sdk": "0.2.0"
37
+ },
38
+ "devDependencies": {
39
+ "@yielded/auth": "0.1.0-beta.47",
40
+ "effect": "4.1.1"
41
+ },
42
+ "peerDependencies": {
43
+ "@yielded/auth": "0.1.0-beta.47",
44
+ "effect": "4.1.1"
45
+ },
46
+ "scripts": {
47
+ "build": "tsc -b tsconfig.build.json && babel dist --plugins annotate-pure-calls --out-dir dist --source-maps",
48
+ "check": "tsc -b tsconfig.json",
49
+ "codegen": "build-utils prepare-v4"
50
+ }
6
51
  }