swallowkit 1.0.0-beta.7 → 1.0.0-beta.8

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.
@@ -5,6 +5,8 @@ import * as fs from 'fs';
5
5
  import * as os from 'os';
6
6
  import { CosmosClient, PartitionKeyKind } from '@azure/cosmos';
7
7
  import { ensureSwallowKitProject, getBackendLanguage } from '../../core/config';
8
+ import { ModelInfo } from '../../core/scaffold/model-parser';
9
+ import { applyDevSeedEnvironment, getContainerNameForModel, loadProjectModels } from './dev-seeds';
8
10
  import { BackendLanguage } from '../../types';
9
11
  import { detectFromProject, getCommands } from '../../utils/package-manager';
10
12
 
@@ -15,6 +17,7 @@ interface DevOptions {
15
17
  open?: boolean;
16
18
  verbose?: boolean;
17
19
  noFunctions?: boolean;
20
+ seedEnv?: string;
18
21
  }
19
22
 
20
23
  export function buildFunctionsStartArgs(functionsPort: string): string[] {
@@ -319,7 +322,8 @@ export const devCommand = new Command()
319
322
  .option('--open', 'Open browser automatically', false)
320
323
  .option('--verbose', 'Show verbose logs', false)
321
324
  .option('--no-functions', 'Skip Azure Functions startup', false)
322
- .action(async (options: DevOptions & { functionsPort?: string; noFunctions?: boolean }) => {
325
+ .option('--seed-env <environment>', 'Replace Cosmos DB Emulator data from dev-seeds/<environment> before startup')
326
+ .action(async (options: DevOptions & { functionsPort?: string; noFunctions?: boolean; seedEnv?: string }) => {
323
327
  // SwallowKit プロジェクトディレクトリかどうかを検証
324
328
  ensureSwallowKitProject("dev");
325
329
 
@@ -331,7 +335,14 @@ export const devCommand = new Command()
331
335
  await startDevEnvironment(options);
332
336
  });
333
337
 
334
- async function initializeCosmosDB(databaseName: string): Promise<void> {
338
+ interface CosmosInitializationResult {
339
+ endpoint: string;
340
+ key: string;
341
+ databaseName: string;
342
+ models: ModelInfo[];
343
+ }
344
+
345
+ async function initializeCosmosDB(databaseName: string): Promise<CosmosInitializationResult | null> {
335
346
  try {
336
347
  // Read local.settings.json from functions directory
337
348
  const functionsDir = path.join(process.cwd(), 'functions');
@@ -339,7 +350,7 @@ async function initializeCosmosDB(databaseName: string): Promise<void> {
339
350
 
340
351
  if (!fs.existsSync(localSettingsPath)) {
341
352
  console.log('⚠️ local.settings.json not found. Skipping Cosmos DB initialization.');
342
- return;
353
+ return null;
343
354
  }
344
355
 
345
356
  const localSettings = JSON.parse(fs.readFileSync(localSettingsPath, 'utf-8'));
@@ -348,7 +359,7 @@ async function initializeCosmosDB(databaseName: string): Promise<void> {
348
359
 
349
360
  if (!connectionString) {
350
361
  console.log('⚠️ CosmosDBConnection not found in local.settings.json. Skipping Cosmos DB initialization.');
351
- return;
362
+ return null;
352
363
  }
353
364
 
354
365
  console.log('🗄️ Initializing Cosmos DB...');
@@ -359,7 +370,7 @@ async function initializeCosmosDB(databaseName: string): Promise<void> {
359
370
 
360
371
  if (!endpointMatch || !keyMatch) {
361
372
  console.log('⚠️ Invalid CosmosDB connection string format.');
362
- return;
373
+ return null;
363
374
  }
364
375
 
365
376
  const endpoint = endpointMatch[1];
@@ -373,72 +384,61 @@ async function initializeCosmosDB(databaseName: string): Promise<void> {
373
384
  const { database } = await client.databases.createIfNotExists({ id: dbName });
374
385
  console.log(`✅ Database "${dbName}" ready`);
375
386
 
376
- // Read lib/scaffold-config.ts to get list of models
377
- const scaffoldConfigPath = path.join(process.cwd(), 'lib', 'scaffold-config.ts');
378
- if (fs.existsSync(scaffoldConfigPath)) {
379
- const scaffoldConfigContent = fs.readFileSync(scaffoldConfigPath, 'utf-8');
387
+ const models = await loadProjectModels();
388
+ for (const model of models) {
389
+ const containerName = getContainerNameForModel(model);
380
390
 
381
- // Parse TypeScript file to extract models array
382
- const modelsMatch = scaffoldConfigContent.match(/models:\s*\[([\s\S]*?)\]\s*as\s*ScaffoldModel\[\]/);
383
- if (modelsMatch) {
384
- const modelsArrayContent = modelsMatch[1];
385
- // Extract model names from objects like { name: 'Task', path: '/task', label: 'Task' }
386
- const modelMatches = modelsArrayContent.matchAll(/\{\s*name:\s*['"](\w+)['"]/g);
387
- const models = Array.from(modelMatches, m => m[1]);
388
-
389
- for (const modelName of models) {
390
- const containerName = `${modelName}s`; // Pluralize model name
391
-
392
- // Try creating container with full partition key definition first
393
- let containerCreated = false;
394
-
395
- try {
396
- console.log(`🔧 Creating container "${containerName}" with partition key /id...`);
397
- const containerResponse = await database.containers.createIfNotExists({
398
- id: containerName,
399
- partitionKey: {
400
- paths: ['/id'],
401
- kind: PartitionKeyKind.Hash,
402
- version: 2
403
- }
404
- });
405
- console.log(`✅ Container "${containerName}" ready (status: ${containerResponse.statusCode})`);
406
- containerCreated = true;
407
- } catch (error: any) {
408
- console.log(`⚠️ Failed with full partition key definition: ${error.message}`);
409
- console.log(`🔄 Retrying with simple partition key...`);
391
+ // Try creating container with full partition key definition first
392
+ let containerCreated = false;
393
+
394
+ try {
395
+ console.log(`🔧 Creating container "${containerName}" with partition key /id...`);
396
+ const containerResponse = await database.containers.createIfNotExists({
397
+ id: containerName,
398
+ partitionKey: {
399
+ paths: ['/id'],
400
+ kind: PartitionKeyKind.Hash,
401
+ version: 2
410
402
  }
411
-
412
- // If first attempt failed, try with simple partition key definition
413
- if (!containerCreated) {
414
- try {
415
- const containerResponse = await database.containers.createIfNotExists({
416
- id: containerName,
417
- partitionKey: {
418
- paths: ['/id']
419
- }
420
- });
421
- console.log(`✅ Container "${containerName}" ready (status: ${containerResponse.statusCode})`);
422
- } catch (containerError: any) {
423
- console.error(`❌ Failed to create container "${containerName}":`, containerError.message);
424
- console.error(`Error code: ${containerError.code}`);
425
- if (containerError.body) {
426
- console.error(`Response body:`, JSON.stringify(containerError.body, null, 2));
427
- }
428
- // Continue with other containers
403
+ });
404
+ console.log(`✅ Container "${containerName}" ready (status: ${containerResponse.statusCode})`);
405
+ containerCreated = true;
406
+ } catch (error: unknown) {
407
+ const message = error instanceof Error ? error.message : String(error);
408
+ console.log(`⚠️ Failed with full partition key definition: ${message}`);
409
+ console.log(`🔄 Retrying with simple partition key...`);
410
+ }
411
+
412
+ // If first attempt failed, try with simple partition key definition
413
+ if (!containerCreated) {
414
+ try {
415
+ const containerResponse = await database.containers.createIfNotExists({
416
+ id: containerName,
417
+ partitionKey: {
418
+ paths: ['/id']
429
419
  }
420
+ });
421
+ console.log(`✅ Container "${containerName}" ready (status: ${containerResponse.statusCode})`);
422
+ } catch (containerError: any) {
423
+ console.error(`❌ Failed to create container "${containerName}":`, containerError.message);
424
+ console.error(`Error code: ${containerError.code}`);
425
+ if (containerError.body) {
426
+ console.error(`Response body:`, JSON.stringify(containerError.body, null, 2));
430
427
  }
428
+ // Continue with other containers
431
429
  }
432
430
  }
433
431
  }
434
432
 
435
433
  console.log('✅ Cosmos DB initialization complete\n');
434
+ return { endpoint, key: keyMatch[1], databaseName: dbName, models };
436
435
  } catch (error: any) {
437
436
  console.error('⚠️ Cosmos DB initialization failed:', error.message);
438
437
  if (error.stack) {
439
438
  console.error('Stack trace:', error.stack);
440
439
  }
441
440
  console.log('💡 Make sure Cosmos DB Emulator is running');
441
+ return null;
442
442
  }
443
443
  }
444
444
 
@@ -563,7 +563,18 @@ async function startDevEnvironment(options: DevOptions) {
563
563
  const appName = packageJson.name || 'App';
564
564
  const databaseName = `${appName.charAt(0).toUpperCase() + appName.slice(1)}Database`;
565
565
 
566
- await initializeCosmosDB(databaseName);
566
+ const cosmosInitialization = await initializeCosmosDB(databaseName);
567
+ if (options.seedEnv && cosmosInitialization) {
568
+ await applyDevSeedEnvironment({
569
+ client: new CosmosClient({
570
+ endpoint: cosmosInitialization.endpoint,
571
+ key: cosmosInitialization.key,
572
+ }),
573
+ databaseName: cosmosInitialization.databaseName,
574
+ environment: options.seedEnv,
575
+ models: cosmosInitialization.models,
576
+ });
577
+ }
567
578
 
568
579
  console.log('');
569
580
  console.log('🚀 Starting Azure Functions...');
@@ -4,5 +4,6 @@
4
4
 
5
5
  export { initCommand } from "./init";
6
6
  export { devCommand } from "./dev";
7
+ export { devSeedsCommand } from "./dev-seeds";
7
8
  export { scaffoldCommand } from "./scaffold";
8
9
  export { createModelCommand } from "./create-model";
package/src/cli/index.ts CHANGED
@@ -8,7 +8,7 @@ if (process.platform === 'win32') {
8
8
  }
9
9
 
10
10
  import { Command } from "commander";
11
- import { initCommand, devCommand, scaffoldCommand, createModelCommand } from "./commands";
11
+ import { initCommand, devCommand, devSeedsCommand, scaffoldCommand, createModelCommand } from "./commands";
12
12
  import { provisionCommand } from "./commands/provision";
13
13
 
14
14
  const program = new Command();
@@ -16,7 +16,7 @@ const program = new Command();
16
16
  program
17
17
  .name("swallowkit")
18
18
  .description("Next.js framework optimized for Azure deployment - Automatically splits SSR into individual Azure Functions")
19
- .version("1.0.0-beta.5");
19
+ .version("1.0.0-beta.8");
20
20
 
21
21
  // Register commands
22
22
  program
@@ -41,6 +41,7 @@ program
41
41
  });
42
42
 
43
43
  program.addCommand(devCommand);
44
+ program.addCommand(devSeedsCommand);
44
45
 
45
46
  program.addCommand(provisionCommand);
46
47