egaki 0.0.2 → 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,64 @@
1
+ // Generated by scripts/generate-gateway-model-candidates.ts
2
+ // Snapshot date: 2026-03-11T21:30:42.406Z
3
+ // Purpose: candidates available in Vercel AI Gateway but missing in src/model-catalog.ts
4
+ export const GATEWAY_MODEL_CANDIDATES = [
5
+ {
6
+ "fullId": "google/gemini-3-pro-image",
7
+ "provider": "google",
8
+ "modelId": "gemini-3-pro-image",
9
+ "type": "language",
10
+ "tags": [
11
+ "image-generation"
12
+ ],
13
+ "reason": "tag-image-generation"
14
+ },
15
+ {
16
+ "fullId": "openai/gpt-5",
17
+ "provider": "openai",
18
+ "modelId": "gpt-5",
19
+ "type": "language",
20
+ "tags": [
21
+ "file-input",
22
+ "reasoning",
23
+ "tool-use",
24
+ "vision",
25
+ "image-generation",
26
+ "implicit-caching"
27
+ ],
28
+ "reason": "tag-image-generation"
29
+ },
30
+ {
31
+ "fullId": "openai/gpt-5-nano",
32
+ "provider": "openai",
33
+ "modelId": "gpt-5-nano",
34
+ "type": "language",
35
+ "tags": [
36
+ "file-input",
37
+ "reasoning",
38
+ "tool-use",
39
+ "vision",
40
+ "image-generation",
41
+ "implicit-caching"
42
+ ],
43
+ "reason": "tag-image-generation"
44
+ },
45
+ {
46
+ "fullId": "openai/gpt-5-pro",
47
+ "provider": "openai",
48
+ "modelId": "gpt-5-pro",
49
+ "type": "language",
50
+ "tags": [
51
+ "file-input",
52
+ "implicit-caching",
53
+ "reasoning",
54
+ "tool-use",
55
+ "vision",
56
+ "image-generation"
57
+ ],
58
+ "reason": "tag-image-generation"
59
+ }
60
+ ];
61
+ export const GATEWAY_MODEL_CANDIDATE_PROVIDERS = [
62
+ "google",
63
+ "openai"
64
+ ];
@@ -1 +1 @@
1
- {"version":3,"file":"model-catalog.d.ts","sourceRoot":"","sources":["../src/model-catalog.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,WAAW,CAAA;IACjB,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,WAAW,CAAA;IACjB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,YAAY,CAAA;AAEnD,MAAM,MAAM,aAAa,GAAG;IAC1B,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAA;IAChB,mCAAmC;IACnC,UAAU,EAAE,OAAO,CAAA;IACnB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,kCAAkC;IAClC,IAAI,EAAE,OAAO,CAAA;IACb,uCAAuC;IACvC,cAAc,EAAE,OAAO,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAA;IAC1B,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,SAAS,CAAA;IACf,QAAQ,EAAE,aAAa,CAAA;CACxB,CAAA;AAgDD,eAAO,MAAM,OAAO,EAAE,UAAU,EA4qB/B,CAAA;AAMD,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAE5D"}
1
+ {"version":3,"file":"model-catalog.d.ts","sourceRoot":"","sources":["../src/model-catalog.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,WAAW,CAAA;IACjB,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,WAAW,CAAA;IACjB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,YAAY,CAAA;AAEnD,MAAM,MAAM,aAAa,GAAG;IAC1B,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAA;IAChB,mCAAmC;IACnC,UAAU,EAAE,OAAO,CAAA;IACnB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,kCAAkC;IAClC,IAAI,EAAE,OAAO,CAAA;IACb,uCAAuC;IACvC,cAAc,EAAE,OAAO,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAA;IAC1B,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,SAAS,CAAA;IACf,QAAQ,EAAE,aAAa,CAAA;CACxB,CAAA;AA+DD,eAAO,MAAM,OAAO,EAAE,UAAU,EA40B/B,CAAA;AAMD,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAE5D"}
@@ -41,6 +41,18 @@ const falImage = {
41
41
  provider: 'fal',
42
42
  strategy: 'image',
43
43
  };
44
+ const bflImage = {
45
+ provider: 'bfl',
46
+ strategy: 'image',
47
+ };
48
+ const recraftImage = {
49
+ provider: 'recraft',
50
+ strategy: 'image',
51
+ };
52
+ const xaiImage = {
53
+ provider: 'xai',
54
+ strategy: 'image',
55
+ };
44
56
  const fluxAspectRatios = ['1:1', '3:4', '4:3', '9:16', '16:9', '9:21', '21:9'];
45
57
  // ─── catalog ─────────────────────────────────────────────────────────────────
46
58
  export const CATALOG = [
@@ -122,6 +134,163 @@ export const CATALOG = [
122
134
  },
123
135
  cost: { type: 'per-token', inputPerM: 0.5, outputPerM: 3.0 },
124
136
  },
137
+ // ── BFL (AI Gateway) ───────────────────────────────────────────────────
138
+ {
139
+ id: 'flux-kontext-max',
140
+ name: 'FLUX Kontext Max',
141
+ released: '2025-06-12',
142
+ ...bflImage,
143
+ cost: { type: 'per-image', perImage: 0.08 },
144
+ features: {
145
+ editing: true,
146
+ inpainting: false,
147
+ aspectRatios: fluxAspectRatios,
148
+ seed: true,
149
+ multipleImages: false,
150
+ },
151
+ },
152
+ {
153
+ id: 'flux-kontext-pro',
154
+ name: 'FLUX Kontext Pro',
155
+ released: '2025-06-12',
156
+ ...bflImage,
157
+ cost: { type: 'per-image', perImage: 0.04 },
158
+ features: {
159
+ editing: true,
160
+ inpainting: false,
161
+ aspectRatios: fluxAspectRatios,
162
+ seed: true,
163
+ multipleImages: false,
164
+ },
165
+ },
166
+ {
167
+ id: 'flux-pro-1.0-fill',
168
+ name: 'FLUX Pro 1.0 Fill',
169
+ released: '2024-10-15',
170
+ ...bflImage,
171
+ cost: { type: 'per-image', perImage: 0.05 },
172
+ features: {
173
+ editing: true,
174
+ inpainting: true,
175
+ aspectRatios: fluxAspectRatios,
176
+ seed: true,
177
+ multipleImages: false,
178
+ },
179
+ },
180
+ {
181
+ id: 'flux-pro-1.1',
182
+ name: 'FLUX Pro 1.1',
183
+ released: '2024-10-01',
184
+ ...bflImage,
185
+ cost: { type: 'per-image', perImage: 0.04 },
186
+ features: {
187
+ editing: false,
188
+ inpainting: false,
189
+ aspectRatios: fluxAspectRatios,
190
+ seed: true,
191
+ multipleImages: false,
192
+ },
193
+ },
194
+ {
195
+ id: 'flux-pro-1.1-ultra',
196
+ name: 'FLUX Pro 1.1 Ultra',
197
+ released: '2024-11-06',
198
+ ...bflImage,
199
+ cost: { type: 'per-image', perImage: 0.06 },
200
+ features: {
201
+ editing: false,
202
+ inpainting: false,
203
+ aspectRatios: fluxAspectRatios,
204
+ seed: true,
205
+ multipleImages: false,
206
+ },
207
+ },
208
+ // ── Recraft (AI Gateway) ───────────────────────────────────────────────
209
+ {
210
+ id: 'recraft-v2',
211
+ name: 'Recraft v2',
212
+ released: '2024-08-19',
213
+ ...recraftImage,
214
+ cost: { type: 'per-image', perImage: 0.04 },
215
+ features: {
216
+ editing: false,
217
+ inpainting: false,
218
+ aspectRatios: ['1:1', '3:4', '4:3', '9:16', '16:9'],
219
+ seed: false,
220
+ multipleImages: false,
221
+ },
222
+ },
223
+ {
224
+ id: 'recraft-v3',
225
+ name: 'Recraft v3 (AI Gateway)',
226
+ released: '2024-10-29',
227
+ ...recraftImage,
228
+ cost: { type: 'per-image', perImage: 0.04 },
229
+ features: {
230
+ editing: false,
231
+ inpainting: false,
232
+ aspectRatios: ['1:1', '3:4', '4:3', '9:16', '16:9'],
233
+ seed: false,
234
+ multipleImages: false,
235
+ },
236
+ },
237
+ {
238
+ id: 'recraft-v4',
239
+ name: 'Recraft v4',
240
+ released: '2025-10-08',
241
+ ...recraftImage,
242
+ cost: { type: 'per-image', perImage: 0.04 },
243
+ features: {
244
+ editing: false,
245
+ inpainting: false,
246
+ aspectRatios: ['1:1', '3:4', '4:3', '9:16', '16:9'],
247
+ seed: false,
248
+ multipleImages: false,
249
+ },
250
+ },
251
+ {
252
+ id: 'recraft-v4-pro',
253
+ name: 'Recraft v4 Pro',
254
+ released: '2025-10-08',
255
+ ...recraftImage,
256
+ cost: { type: 'per-image', perImage: 0.25 },
257
+ features: {
258
+ editing: false,
259
+ inpainting: false,
260
+ aspectRatios: ['1:1', '3:4', '4:3', '9:16', '16:9'],
261
+ seed: false,
262
+ multipleImages: false,
263
+ },
264
+ },
265
+ // ── xAI (AI Gateway) ────────────────────────────────────────────────────
266
+ {
267
+ id: 'grok-imagine-image',
268
+ name: 'Grok Imagine Image',
269
+ released: '2026-03',
270
+ ...xaiImage,
271
+ cost: { type: 'per-image', perImage: 0.02 },
272
+ features: {
273
+ editing: true,
274
+ inpainting: false,
275
+ aspectRatios: ['1:1', '3:4', '4:3', '9:16', '16:9'],
276
+ seed: false,
277
+ multipleImages: true,
278
+ },
279
+ },
280
+ {
281
+ id: 'grok-imagine-image-pro',
282
+ name: 'Grok Imagine Image Pro',
283
+ released: '2026-03',
284
+ ...xaiImage,
285
+ cost: { type: 'per-image', perImage: 0.07 },
286
+ features: {
287
+ editing: true,
288
+ inpainting: false,
289
+ aspectRatios: ['1:1', '3:4', '4:3', '9:16', '16:9'],
290
+ seed: false,
291
+ multipleImages: true,
292
+ },
293
+ },
125
294
  // ── OpenAI ─────────────────────────────────────────────────────────────
126
295
  {
127
296
  id: 'dall-e-2',
package/dist/models.d.ts CHANGED
@@ -1,10 +1,15 @@
1
1
  import type { ImageModel, LanguageModel } from 'ai';
2
2
  import type { ModelEntry } from './model-catalog.js';
3
- export type { ModelEntry };
3
+ import type { VideoModelEntry } from './video-model-catalog.js';
4
+ export type AnyModelEntry = ModelEntry | VideoModelEntry;
5
+ export type { ModelEntry, VideoModelEntry };
4
6
  export declare const IMAGE_MODELS: [string, ...string[]];
7
+ export declare const VIDEO_MODELS: [string, ...string[]];
5
8
  export declare const DEFAULT_MODEL = "nano-banana-pro-preview";
6
- export declare function getModelConfig(modelId: string): ModelEntry;
9
+ export declare const DEFAULT_VIDEO_MODEL = "veo-3.1-fast-generate-001";
10
+ export declare function getModelConfig(modelId: string): AnyModelEntry;
7
11
  export declare function ensureProviderKey(providerName: string): void;
8
12
  export declare function createImageModel(modelId: string): Promise<ImageModel>;
9
13
  export declare function createTextModel(modelId: string): Promise<LanguageModel>;
14
+ export declare function createVideoModel(modelId: string): Promise<any>;
10
15
  //# sourceMappingURL=models.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;AAInD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B,eAAO,MAAM,YAAY,EAA+B,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAA;AAE7E,eAAO,MAAM,aAAa,4BAA4B,CAAA;AAEtD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAO1D;AAuBD,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAmC5D;AAmCD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAkC3E;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,CAAC,CA6BxB"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;AAInD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAE/D,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,eAAe,CAAA;AACxD,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,CAAA;AAE3C,eAAO,MAAM,YAAY,EAA+B,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAA;AAC7E,eAAO,MAAM,YAAY,EAAqC,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAA;AAEnF,eAAO,MAAM,aAAa,4BAA4B,CAAA;AACtD,eAAO,MAAM,mBAAmB,8BAA8B,CAAA;AAE9D,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAO7D;AAuBD,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAmC5D;AAgDD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAkC3E;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,aAAa,CAAC,CAiCxB;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAqCpE"}
package/dist/models.js CHANGED
@@ -1,10 +1,13 @@
1
1
  import pc from 'picocolors';
2
2
  import { PROVIDERS, EGAKI_GATEWAY_URL } from './credentials.js';
3
3
  import { CATALOG, findModel } from './model-catalog.js';
4
+ import { VIDEO_CATALOG, findVideoModel } from './video-model-catalog.js';
4
5
  export const IMAGE_MODELS = CATALOG.map((m) => m.id);
6
+ export const VIDEO_MODELS = VIDEO_CATALOG.map((m) => m.id);
5
7
  export const DEFAULT_MODEL = 'nano-banana-pro-preview';
8
+ export const DEFAULT_VIDEO_MODEL = 'veo-3.1-fast-generate-001';
6
9
  export function getModelConfig(modelId) {
7
- const entry = findModel(modelId);
10
+ const entry = findModel(modelId) ?? findVideoModel(modelId);
8
11
  if (!entry) {
9
12
  console.error(pc.red(`Unknown model: ${modelId}`));
10
13
  process.exit(1);
@@ -85,6 +88,18 @@ async function createGatewayTextModel(modelId, provider) {
85
88
  const gatewayModelId = `${provider}/${modelId}`;
86
89
  return gateway(gatewayModelId);
87
90
  }
91
+ /**
92
+ * Create a gateway-backed video model using createGateway from the AI SDK.
93
+ */
94
+ async function createGatewayVideoModel(modelId, provider) {
95
+ const { createGateway } = await import('ai');
96
+ const gateway = createGateway({
97
+ apiKey: process.env['EGAKI_API_KEY'],
98
+ baseURL: EGAKI_GATEWAY_URL,
99
+ });
100
+ const gatewayModelId = `${provider}/${modelId}`;
101
+ return gateway.video(gatewayModelId);
102
+ }
88
103
  // Lazily import the provider and create the right model instance.
89
104
  // This avoids loading all provider SDKs upfront — only the one needed
90
105
  // for the selected model gets imported.
@@ -124,6 +139,10 @@ export async function createImageModel(modelId) {
124
139
  }
125
140
  export async function createTextModel(modelId) {
126
141
  const config = getModelConfig(modelId);
142
+ if (config.strategy !== 'text') {
143
+ console.error(pc.red(`Model ${modelId} is not a text model`));
144
+ process.exit(1);
145
+ }
127
146
  ensureProviderKey(config.provider);
128
147
  // Direct provider key takes priority
129
148
  if (hasDirectProviderKey(config.provider)) {
@@ -145,3 +164,33 @@ export async function createTextModel(modelId) {
145
164
  console.error(pc.red(`No API key available for provider: ${config.provider}`));
146
165
  process.exit(1);
147
166
  }
167
+ export async function createVideoModel(modelId) {
168
+ const config = getModelConfig(modelId);
169
+ if (config.strategy !== 'video') {
170
+ console.error(pc.red(`Model ${modelId} is not a video model`));
171
+ process.exit(1);
172
+ }
173
+ ensureProviderKey(config.provider);
174
+ // Direct provider key takes priority
175
+ if (hasDirectProviderKey(config.provider)) {
176
+ switch (config.provider) {
177
+ case 'google': {
178
+ const { google } = await import('@ai-sdk/google');
179
+ return google.video(modelId);
180
+ }
181
+ case 'fal': {
182
+ const { fal } = await import('@ai-sdk/fal');
183
+ return fal.video(modelId);
184
+ }
185
+ default:
186
+ console.error(pc.red(`Direct video generation is only supported for Google and Fal keys, got provider: ${config.provider}`));
187
+ process.exit(1);
188
+ }
189
+ }
190
+ // Fall back to egaki gateway
191
+ if (hasEgakiKey()) {
192
+ return createGatewayVideoModel(modelId, config.provider);
193
+ }
194
+ console.error(pc.red(`No API key available for provider: ${config.provider}`));
195
+ process.exit(1);
196
+ }
@@ -0,0 +1,2 @@
1
+ export declare function openUrlInBrowser(url: string): boolean;
2
+ //# sourceMappingURL=open-browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-browser.d.ts","sourceRoot":"","sources":["../src/open-browser.ts"],"names":[],"mappings":"AAyBA,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAsBrD"}
@@ -0,0 +1,37 @@
1
+ // Cross-platform browser opener for URLs used by CLI flows.
2
+ // Never throws: missing OS commands are handled gracefully.
3
+ import { spawnSync } from 'node:child_process';
4
+ function getOpenCommands(url) {
5
+ if (process.platform === 'darwin') {
6
+ return [{ command: 'open', args: [url] }];
7
+ }
8
+ if (process.platform === 'win32') {
9
+ // `start` is a cmd builtin, so invoke through cmd.exe.
10
+ return [{ command: 'cmd', args: ['/c', 'start', '', url] }];
11
+ }
12
+ return [
13
+ { command: 'xdg-open', args: [url] },
14
+ { command: 'gio', args: ['open', url] },
15
+ ];
16
+ }
17
+ export function openUrlInBrowser(url) {
18
+ // Avoid launching browser commands in non-interactive contexts (CI/pipes).
19
+ if (!process.stdout.isTTY || !process.stdin.isTTY) {
20
+ return false;
21
+ }
22
+ for (const candidate of getOpenCommands(url)) {
23
+ try {
24
+ const result = spawnSync(candidate.command, candidate.args, {
25
+ stdio: 'ignore',
26
+ windowsHide: true,
27
+ });
28
+ if (!result.error && result.status === 0) {
29
+ return true;
30
+ }
31
+ }
32
+ catch {
33
+ // Keep trying fallback commands. This helper must never crash the CLI.
34
+ }
35
+ }
36
+ return false;
37
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../src/subscription.ts"],"names":[],"mappings":"AAqDA,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAqG1D;AAED,wBAAgB,uBAAuB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CA4B3E;AAID,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAgCjD;AAID,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CA8C/C"}
1
+ {"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../src/subscription.ts"],"names":[],"mappings":"AAsDA,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CA8H1D;AAED,wBAAgB,uBAAuB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CA6B3E;AAID,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAgCjD;AAID,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CA8C/C"}
@@ -4,8 +4,9 @@
4
4
  import pc from 'picocolors';
5
5
  import { intro, outro, text, select, confirm, isCancel, cancel, log, note, spinner, } from '@clack/prompts';
6
6
  import { EGAKI_GATEWAY_URL, saveProviderKey, getProviderKey } from './credentials.js';
7
- // Strip /v1/ai suffix to get the base URL for non-proxy endpoints (/buy, /api/*)
8
- const GATEWAY_BASE = EGAKI_GATEWAY_URL.replace(/\/v1\/ai$/, '');
7
+ import { openUrlInBrowser } from './open-browser.js';
8
+ // Strip /vN/ai suffix to get the base URL for non-proxy endpoints (/buy, /api/*)
9
+ const GATEWAY_BASE = EGAKI_GATEWAY_URL.replace(/\/v\d+\/ai$/, '');
9
10
  // ── Subscribe ─────────────────────────────────────────────────────────────
10
11
  export async function subscribeInteractive() {
11
12
  intro(pc.bold('egaki subscribe'));
@@ -39,22 +40,37 @@ export async function subscribeInteractive() {
39
40
  cancel('Subscribe cancelled.');
40
41
  process.exit(0);
41
42
  }
42
- // Get email
43
- const email = await text({
44
- message: 'Email for the subscription',
45
- placeholder: 'you@example.com',
46
- validate: (value) => {
47
- if (!value || !value.includes('@')) {
48
- return 'Please enter a valid email';
49
- }
50
- },
43
+ // Optional email prefill for checkout
44
+ const prefillEmail = await confirm({
45
+ message: 'Prefill your email in checkout URL? (optional)',
51
46
  });
52
- if (isCancel(email)) {
47
+ if (isCancel(prefillEmail)) {
53
48
  cancel('Subscribe cancelled.');
54
49
  process.exit(0);
55
50
  }
51
+ let email;
52
+ if (prefillEmail) {
53
+ const enteredEmail = await text({
54
+ message: 'Email for the subscription',
55
+ placeholder: 'you@example.com',
56
+ validate: (value) => {
57
+ if (!value || !value.includes('@')) {
58
+ return 'Please enter a valid email';
59
+ }
60
+ },
61
+ });
62
+ if (isCancel(enteredEmail)) {
63
+ cancel('Subscribe cancelled.');
64
+ process.exit(0);
65
+ }
66
+ email = enteredEmail;
67
+ }
56
68
  // Show checkout URL
57
- const checkoutUrl = `${GATEWAY_BASE}/buy?plan=${planId}&email=${encodeURIComponent(email)}`;
69
+ const params = new URLSearchParams({ plan: planId });
70
+ if (email) {
71
+ params.set('email', email);
72
+ }
73
+ const checkoutUrl = `${GATEWAY_BASE}/buy?${params.toString()}`;
58
74
  log.info('');
59
75
  note([
60
76
  `Open this URL to complete payment:`,
@@ -66,6 +82,13 @@ export async function subscribeInteractive() {
66
82
  '',
67
83
  ` ${pc.cyan('egaki login --provider egaki --key egaki_...')}`,
68
84
  ].join('\n'), 'Checkout');
85
+ const opened = openUrlInBrowser(checkoutUrl);
86
+ if (opened) {
87
+ log.success('Opened checkout URL in your browser');
88
+ }
89
+ else if (process.stdout.isTTY && process.stdin.isTTY) {
90
+ log.info('Could not auto-open a browser. Open the URL above manually.');
91
+ }
69
92
  // Ask if they want to enter the key now
70
93
  const hasKey = await confirm({
71
94
  message: 'Do you already have your API key?',
@@ -117,7 +140,8 @@ export function subscribeNonInteractive(email, plan) {
117
140
  console.log(` ${pc.bold('Pro')} $99/mo ${pc.cyan(`${GATEWAY_BASE}/buy?plan=pro${emailParam}`)}`);
118
141
  }
119
142
  console.log('');
120
- console.log('After payment, you\'ll receive your API key via email.');
143
+ console.log('After payment, your API key is shown on the success page.');
144
+ console.log('If an email was provided to Stripe checkout, a copy is also sent by email.');
121
145
  console.log(`Then run: ${pc.cyan('egaki login --provider egaki --key egaki_...')}`);
122
146
  console.log('');
123
147
  console.log('Tip: egaki supports both BYOK and subscription mode.');
@@ -0,0 +1,52 @@
1
+ export type VideoDurationPricingTier = {
2
+ /** USD per second for this variant */
3
+ costPerSecond: number;
4
+ /** Optional resolution discriminator (e.g. 720p, 1080p, 4k) */
5
+ resolution?: string;
6
+ /** Optional mode discriminator (e.g. std, pro) */
7
+ mode?: string;
8
+ /** Optional audio discriminator */
9
+ audio?: boolean;
10
+ };
11
+ export type PerVideoSecondCost = {
12
+ type: 'per-video-second';
13
+ /** Fallback duration when request does not specify one (seconds) */
14
+ defaultDurationSec: number;
15
+ tiers: VideoDurationPricingTier[];
16
+ };
17
+ export type UnknownVideoCost = {
18
+ type: 'unknown';
19
+ };
20
+ export type VideoModelCost = PerVideoSecondCost | UnknownVideoCost;
21
+ export type VideoModelFeatures = {
22
+ /** Supports text prompt to video generation */
23
+ textToVideo: boolean;
24
+ /** Supports image-to-video prompt object ({ image, text }) */
25
+ imageToVideo: boolean;
26
+ /** Optional capabilities exposed by provider */
27
+ capabilities: Array<'t2v' | 'i2v' | 'r2v' | 'motion-control' | 'editing'>;
28
+ /** Optional supported aspect ratios */
29
+ aspectRatios?: string[];
30
+ /** Optional supported resolutions */
31
+ resolutions?: string[];
32
+ /** Optional duration range in seconds */
33
+ durationRangeSec?: {
34
+ min: number;
35
+ max: number;
36
+ };
37
+ seed: boolean;
38
+ multipleVideos: boolean;
39
+ };
40
+ export type VideoModelEntry = {
41
+ id: string;
42
+ name: string;
43
+ description?: string;
44
+ provider: string;
45
+ strategy: 'video';
46
+ released: string;
47
+ cost: VideoModelCost;
48
+ features: VideoModelFeatures;
49
+ };
50
+ export declare const VIDEO_CATALOG: VideoModelEntry[];
51
+ export declare function findVideoModel(id: string): VideoModelEntry | undefined;
52
+ //# sourceMappingURL=video-model-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video-model-catalog.d.ts","sourceRoot":"","sources":["../src/video-model-catalog.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,wBAAwB,GAAG;IACrC,sCAAsC;IACtC,aAAa,EAAE,MAAM,CAAA;IACrB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,mCAAmC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,kBAAkB,CAAA;IACxB,oEAAoE;IACpE,kBAAkB,EAAE,MAAM,CAAA;IAC1B,KAAK,EAAE,wBAAwB,EAAE,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,SAAS,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG,gBAAgB,CAAA;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,+CAA+C;IAC/C,WAAW,EAAE,OAAO,CAAA;IACpB,8DAA8D;IAC9D,YAAY,EAAE,OAAO,CAAA;IACrB,gDAAgD;IAChD,YAAY,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,gBAAgB,GAAG,SAAS,CAAC,CAAA;IACzE,uCAAuC;IACvC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,yCAAyC;IACzC,gBAAgB,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/C,IAAI,EAAE,OAAO,CAAA;IACb,cAAc,EAAE,OAAO,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,cAAc,CAAA;IACpB,QAAQ,EAAE,kBAAkB,CAAA;CAC7B,CAAA;AAID,eAAO,MAAM,aAAa,EAAE,eAAe,EA6O1C,CAAA;AAID,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAEtE"}