@genex-ai/embed-sdk 0.17.0 → 0.21.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,44 @@
1
+ import { RuntimeWorkflowInput, RuntimeGenerationView } from '@genex/embed-protocol';
2
+
3
+ /** Server-only benchmarks spend the authenticated creator's own coin wallet. */
4
+
5
+ interface DevelopmentGenerationConfig {
6
+ apiUrl: string;
7
+ /** Full creator bearer credential, kept only in your server or local script. */
8
+ creatorToken: string;
9
+ projectId: string;
10
+ }
11
+ interface DevelopmentGenerationOptions extends DevelopmentGenerationConfig {
12
+ /** Explicit maximum reservation in your own coins. Actual usage is charged. */
13
+ maxCoins: number;
14
+ request: {
15
+ modelId: string;
16
+ prompt: string;
17
+ outputFormat: 'text' | 'json';
18
+ schema?: Record<string, unknown>;
19
+ idempotencyKey?: string;
20
+ };
21
+ /** Waiting time only; timeout returns the last server view without canceling. */
22
+ timeoutMs?: number;
23
+ }
24
+ interface DevelopmentWorkflowOptions extends DevelopmentGenerationConfig {
25
+ workflowId: string;
26
+ maxCoins: number;
27
+ request: {
28
+ offeringId: string;
29
+ input: RuntimeWorkflowInput;
30
+ idempotencyKey?: string;
31
+ };
32
+ }
33
+ /** Create a generic benchmark and wait for execution and its actual-usage receipt. */
34
+ declare function developmentGenerate(options: DevelopmentGenerationOptions): Promise<RuntimeGenerationView>;
35
+ /** Returns the accepted workflow so its trusted executor can enqueue before waiting. */
36
+ declare function developmentRequestWorkflow(options: DevelopmentWorkflowOptions): Promise<RuntimeGenerationView>;
37
+ /** Recover a benchmark with the same creator and project; no play token is used. */
38
+ declare function getDevelopmentGeneration(config: DevelopmentGenerationConfig, generationId: string): Promise<RuntimeGenerationView>;
39
+ /** Acknowledges cancellation; the returned receipt determines the charge or remaining hold. */
40
+ declare function cancelDevelopmentGeneration(config: DevelopmentGenerationConfig, generationId: string): Promise<RuntimeGenerationView>;
41
+ /** Wait for execution and final billing; timeout preserves the latest pending receipt. */
42
+ declare function waitForDevelopmentGeneration(config: DevelopmentGenerationConfig, generationId: string, timeoutMs?: number): Promise<RuntimeGenerationView>;
43
+
44
+ export { type DevelopmentGenerationConfig, type DevelopmentGenerationOptions, type DevelopmentWorkflowOptions, cancelDevelopmentGeneration, developmentGenerate, developmentRequestWorkflow, getDevelopmentGeneration, waitForDevelopmentGeneration };
@@ -0,0 +1,99 @@
1
+ import {
2
+ isGenerationId,
3
+ isGenerationTerminal
4
+ } from "./chunk-Q476GJHI.js";
5
+
6
+ // src/development.ts
7
+ function assertIdentifier(value) {
8
+ if (!/^[A-Za-z0-9_.:-]{1,120}$/.test(value) || value === "." || value === "..") throw new Error("invalid_development_identifier");
9
+ }
10
+ function baseUrl(config) {
11
+ if (typeof window !== "undefined") throw new Error("development_server_only");
12
+ assertIdentifier(config.projectId);
13
+ if (!config.creatorToken || /\s/.test(config.creatorToken)) throw new Error("creator_token_required");
14
+ const url = new URL(config.apiUrl);
15
+ if (url.username || url.password || url.search || url.hash || url.pathname !== "/" || url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))) {
16
+ throw new Error("invalid_api_url");
17
+ }
18
+ return url.origin + "/api/runtime/development/projects/" + encodeURIComponent(config.projectId);
19
+ }
20
+ function validateMaximum(maxCoins) {
21
+ if (!Number.isSafeInteger(maxCoins) || maxCoins <= 0 || maxCoins > 1e6) throw new Error("invalid_max_coins");
22
+ }
23
+ async function request(config, path, body) {
24
+ const response = await fetch(baseUrl(config) + path, {
25
+ method: body === void 0 ? "GET" : "POST",
26
+ credentials: "omit",
27
+ cache: "no-store",
28
+ redirect: "error",
29
+ headers: { Authorization: "Bearer " + config.creatorToken, ...body === void 0 ? {} : { "Content-Type": "application/json" } },
30
+ ...body === void 0 ? {} : { body: JSON.stringify(body) }
31
+ });
32
+ const result = await response.json().catch(() => ({}));
33
+ if (!response.ok) throw new Error(typeof result.error === "string" ? result.error : "development_generation_unavailable");
34
+ const view = result;
35
+ if (!isGenerationId(view.id) || view.projectId !== config.projectId || view.development !== true || view.quote?.billingPolicy !== "consumed-v1" || view.funding !== "coins") throw new Error("invalid_development_response");
36
+ return view;
37
+ }
38
+ async function developmentGenerate(options) {
39
+ validateMaximum(options.maxCoins);
40
+ if (options.timeoutMs !== void 0 && (!Number.isFinite(options.timeoutMs) || options.timeoutMs < 0)) throw new Error("invalid_timeout");
41
+ const input = options.request;
42
+ const view = await request(options, "/generations", { maxCoins: options.maxCoins, request: {
43
+ modelId: input.modelId,
44
+ prompt: input.prompt,
45
+ outputFormat: input.outputFormat,
46
+ ...input.schema === void 0 ? {} : { schema: input.schema },
47
+ idempotencyKey: input.idempotencyKey ?? crypto.randomUUID()
48
+ } });
49
+ return wait(options, view, options.timeoutMs ?? 6e5);
50
+ }
51
+ async function developmentRequestWorkflow(options) {
52
+ validateMaximum(options.maxCoins);
53
+ assertIdentifier(options.workflowId);
54
+ assertIdentifier(options.request.offeringId);
55
+ const view = await request(options, "/workflows/" + encodeURIComponent(options.workflowId) + "/requests", {
56
+ maxCoins: options.maxCoins,
57
+ request: {
58
+ offeringId: options.request.offeringId,
59
+ input: options.request.input,
60
+ idempotencyKey: options.request.idempotencyKey ?? crypto.randomUUID()
61
+ }
62
+ });
63
+ if (view.kind !== "workflow" || view.workflow?.id !== options.workflowId || view.workflow.offeringId !== options.request.offeringId) {
64
+ throw new Error("invalid_development_response");
65
+ }
66
+ return view;
67
+ }
68
+ async function getDevelopmentGeneration(config, generationId) {
69
+ if (!isGenerationId(generationId)) throw new Error("invalid_generation_id");
70
+ const view = await request(config, "/generations/" + encodeURIComponent(generationId));
71
+ if (view.id !== generationId) throw new Error("invalid_development_response");
72
+ return view;
73
+ }
74
+ async function cancelDevelopmentGeneration(config, generationId) {
75
+ if (!isGenerationId(generationId)) throw new Error("invalid_generation_id");
76
+ const view = await request(config, "/generations/" + encodeURIComponent(generationId) + "/cancel", {});
77
+ if (view.id !== generationId) throw new Error("invalid_development_response");
78
+ return view;
79
+ }
80
+ async function wait(config, initial, timeoutMs) {
81
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) throw new Error("invalid_timeout");
82
+ const deadline = Date.now() + timeoutMs;
83
+ let view = initial;
84
+ while (!(isGenerationTerminal(view.status) && view.billingStatus === "final") && Date.now() < deadline) {
85
+ await new Promise((resolve) => setTimeout(resolve, Math.min(750, deadline - Date.now())));
86
+ view = await getDevelopmentGeneration(config, view.id);
87
+ }
88
+ return view;
89
+ }
90
+ async function waitForDevelopmentGeneration(config, generationId, timeoutMs = 6e5) {
91
+ return wait(config, await getDevelopmentGeneration(config, generationId), timeoutMs);
92
+ }
93
+ export {
94
+ cancelDevelopmentGeneration,
95
+ developmentGenerate,
96
+ developmentRequestWorkflow,
97
+ getDevelopmentGeneration,
98
+ waitForDevelopmentGeneration
99
+ };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { RuntimeWorkflowInput, RuntimeGenerationBilling, RuntimeGenerationFunding, RuntimeGenerationView, RuntimeGenerationModels, RuntimeWorkflowOfferings } from '@genex/embed-protocol';
2
+ export { RuntimeBillingPolicy, RuntimeExternalProvider, RuntimeGenerationBilling, RuntimeGenerationFunding, RuntimeGenerationModels, RuntimeGenerationStatus, RuntimeGenerationView, RuntimeWorkflowInput, RuntimeWorkflowOfferings } from '@genex/embed-protocol';
3
+
1
4
  /** A thing the game sells. Resolved server-side; the game never sets a price. */
2
5
  interface ShopItem {
3
6
  id: string;
@@ -118,6 +121,75 @@ declare function buy(opts: {
118
121
  timeoutMs?: number;
119
122
  }): Promise<PurchaseResult>;
120
123
 
124
+ interface GenerateOptions {
125
+ /** Fixed coin price of a started attempt. Zero is accepted only for server-authorized free options. */
126
+ estimateCoins: number;
127
+ modelId: string;
128
+ prompt: string;
129
+ outputFormat: 'text' | 'json';
130
+ schema?: Record<string, unknown>;
131
+ /** Allow player-supplied results through their own configured Claude or ChatGPT account. Defaults off. */
132
+ allowExternal?: boolean;
133
+ /** Reuse for retries of the same operation, including after a game reload. */
134
+ idempotencyKey?: string;
135
+ /** Waiting time only. Reaching it does not cancel an accepted generation. */
136
+ timeoutMs?: number;
137
+ }
138
+ interface RuntimeGenerationResult extends RuntimeGenerationBilling {
139
+ status: 'succeeded' | 'failed' | 'unknown' | 'canceled' | 'expired' | 'pending';
140
+ generationId?: string;
141
+ output?: unknown;
142
+ /** External output is user-supplied; never use it as authority for rewards or money. */
143
+ source?: 'openrouter' | 'external';
144
+ modelProvenance?: 'unverified';
145
+ error?: string;
146
+ }
147
+ interface RequestWorkflowOptions {
148
+ /** Fixed coin price of a started attempt, including failed or canceled work. */
149
+ estimateCoins: number;
150
+ /** Offer configured personal Claude/ChatGPT funding on the same quote. Defaults off. */
151
+ allowExternal?: boolean;
152
+ workflowId: string;
153
+ offeringId: string;
154
+ input: RuntimeWorkflowInput;
155
+ /** Reuse for the exact same operation after sign-in, cancellation or reload. */
156
+ idempotencyKey?: string;
157
+ /** Approval waiting time only. A timeout does not cancel an accepted request. */
158
+ timeoutMs?: number;
159
+ }
160
+ interface RuntimeWorkflowAuthorization extends RuntimeGenerationBilling {
161
+ status: 'authorized' | 'canceled' | 'expired' | 'failed' | 'pending';
162
+ generationId?: string;
163
+ funding?: RuntimeGenerationFunding;
164
+ error?: string;
165
+ }
166
+ /** Available models and pricing; the confirmation always uses a fresh server quote. */
167
+ declare function getGenerationModels(): Promise<RuntimeGenerationModels>;
168
+ /** Server-owned estimates, reservation maxima and availability. Confirmation seals the quote. */
169
+ declare function getWorkflowOfferings(workflowId: string): Promise<RuntimeWorkflowOfferings>;
170
+ /** Recover an operation by ID after a reload. Scoped to this player AND this game. */
171
+ declare function getGeneration(generationId: string): Promise<RuntimeGenerationView>;
172
+ /** Resume waiting for execution. A terminal result can still carry pending billing; read getGeneration() for settlement. */
173
+ declare function waitForGeneration(generationId: string, timeoutMs?: number): Promise<RuntimeGenerationResult>;
174
+ /**
175
+ * Call directly from a click handler. The trusted popup is reserved BEFORE any
176
+ * asynchronous work, so standalone games retain the browser's user gesture.
177
+ * The player approves on Genex. Cancellation resolves normally; only API state
178
+ * can return an output. Store generationId to recover a pending result on boot.
179
+ */
180
+ declare function generate(options: GenerateOptions): Promise<RuntimeGenerationResult>;
181
+ /**
182
+ * Call directly from the player's click, before awaiting anything. Returns when
183
+ * Genex authorizes the entire workflow, so the game can enqueue its executor.
184
+ * Personal-provider instructions stay open after authorization. Store the ID;
185
+ * getGeneration()/waitForGeneration() recover the eventual result without a new charge.
186
+ */
187
+ declare function requestWorkflow(options: RequestWorkflowOptions): Promise<RuntimeWorkflowAuthorization>;
188
+ /** Reopen a saved approval without repricing or submitting a new request. Call directly from a click. */
189
+ declare function resumeWorkflow(generationId: string, options?: {
190
+ timeoutMs?: number;
191
+ }): Promise<RuntimeWorkflowAuthorization>;
192
+
121
193
  interface EmbedConfig {
122
194
  /** This game's own slug (GENEX.slug) — identifies the project to /play/authorize. */
123
195
  slug: string;
@@ -357,4 +429,4 @@ declare function __resetForTests(overrides?: {
357
429
  heartbeatIntervalMs?: number;
358
430
  }): void;
359
431
 
360
- export { type AuthState, type EmbedConfig, type EmbedEvent, type EmbedUser, type Entitlement, type Leaderboard, type LeaderboardEntry, type PlayerStateResult, type PurchaseResult, type PurchaseStatus, type SaveStateResult, type ShopItem, type SubmitScoreResult, type WorldStateResult, __resetForTests, _stashTicketFromUrl, buy, consumeEntitlement, getAuthState, getColyseusAuth, getColyseusUrls, getEmbedToken, getEntitlements, getLeaderboard, getShop, getUser, initEmbed, isEmbedded, loadPlayerState, loadWorldState, on, savePlayerState, saveWorldState, submitScore, waitForAuth, waitForPlayer };
432
+ export { type AuthState, type EmbedConfig, type EmbedEvent, type EmbedUser, type Entitlement, type GenerateOptions, type Leaderboard, type LeaderboardEntry, type PlayerStateResult, type PurchaseResult, type PurchaseStatus, type RequestWorkflowOptions, type RuntimeGenerationResult, type RuntimeWorkflowAuthorization, type SaveStateResult, type ShopItem, type SubmitScoreResult, type WorldStateResult, __resetForTests, _stashTicketFromUrl, buy, consumeEntitlement, generate, getAuthState, getColyseusAuth, getColyseusUrls, getEmbedToken, getEntitlements, getGeneration, getGenerationModels, getLeaderboard, getShop, getUser, getWorkflowOfferings, initEmbed, isEmbedded, loadPlayerState, loadWorldState, on, requestWorkflow, resumeWorkflow, savePlayerState, saveWorldState, submitScore, waitForAuth, waitForGeneration, waitForPlayer };
package/dist/index.js CHANGED
@@ -3,46 +3,61 @@ import {
3
3
  _stashTicketFromUrl,
4
4
  buy,
5
5
  consumeEntitlement,
6
+ generate,
6
7
  getAuthState,
7
8
  getColyseusAuth,
8
9
  getColyseusUrls,
9
10
  getEmbedToken,
10
11
  getEntitlements,
12
+ getGeneration,
13
+ getGenerationModels,
11
14
  getLeaderboard,
12
15
  getShop,
13
16
  getUser,
17
+ getWorkflowOfferings,
14
18
  initEmbed,
15
19
  isEmbedded,
16
20
  loadPlayerState,
17
21
  loadWorldState,
18
22
  on,
23
+ requestWorkflow,
24
+ resumeWorkflow,
19
25
  savePlayerState,
20
26
  saveWorldState,
21
27
  submitScore,
22
28
  waitForAuth,
29
+ waitForGeneration,
23
30
  waitForPlayer
24
- } from "./chunk-DNLXNEPL.js";
31
+ } from "./chunk-WJ4KFQLC.js";
32
+ import "./chunk-Q476GJHI.js";
25
33
  export {
26
34
  __resetForTests,
27
35
  _stashTicketFromUrl,
28
36
  buy,
29
37
  consumeEntitlement,
38
+ generate,
30
39
  getAuthState,
31
40
  getColyseusAuth,
32
41
  getColyseusUrls,
33
42
  getEmbedToken,
34
43
  getEntitlements,
44
+ getGeneration,
45
+ getGenerationModels,
35
46
  getLeaderboard,
36
47
  getShop,
37
48
  getUser,
49
+ getWorkflowOfferings,
38
50
  initEmbed,
39
51
  isEmbedded,
40
52
  loadPlayerState,
41
53
  loadWorldState,
42
54
  on,
55
+ requestWorkflow,
56
+ resumeWorkflow,
43
57
  savePlayerState,
44
58
  saveWorldState,
45
59
  submitScore,
46
60
  waitForAuth,
61
+ waitForGeneration,
47
62
  waitForPlayer
48
63
  };
package/dist/sentry.js CHANGED
@@ -2,7 +2,8 @@ import {
2
2
  _stashTicketFromUrl,
3
3
  getUser,
4
4
  on
5
- } from "./chunk-DNLXNEPL.js";
5
+ } from "./chunk-WJ4KFQLC.js";
6
+ import "./chunk-Q476GJHI.js";
6
7
 
7
8
  // src/sentry.ts
8
9
  import * as Sentry from "@sentry/browser";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@genex-ai/embed-sdk",
3
- "version": "0.17.0",
4
- "description": "Player identity + durable game state for genex games \u2014 signed-in or guest play, per-player save slots, shared world state, and soft-trust leaderboards.",
3
+ "version": "0.21.0",
4
+ "description": "Player identity + durable game state for genex games signed-in or guest play, per-player save slots, shared world state, and soft-trust leaderboards.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -15,6 +15,12 @@
15
15
  "@genex-ai/source": "./src/sentry.ts",
16
16
  "types": "./dist/sentry.d.ts",
17
17
  "import": "./dist/sentry.js"
18
+ },
19
+ "./development": {
20
+ "types": "./dist/development.d.ts",
21
+ "browser": null,
22
+ "@genex-ai/source": "./src/development.ts",
23
+ "import": "./dist/development.js"
18
24
  }
19
25
  },
20
26
  "files": [