@sebspark/spanner-migrate 2.0.2 → 2.0.3

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.
@@ -350,3 +350,4 @@ export {
350
350
  down,
351
351
  status
352
352
  };
353
+ //# sourceMappingURL=chunk-UJTIK6KC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/apply.ts","../src/db.ts","../src/files.ts"],"sourcesContent":["import { type Database, Spanner } from '@google-cloud/spanner'\nimport { applyDown, applyUp } from './apply'\nimport { ensureMigrationTable, getAppliedMigrations } from './db'\nimport {\n createMigration,\n getMigration,\n getMigrationFiles,\n getNewMigrations,\n writeConfig,\n} from './files'\nimport type { Config, DatabaseConfig, DbPath } from './types'\n\nconst getDb = ({ projectId, databaseName, instanceName }: DbPath): Database => {\n const spanner = projectId ? new Spanner({ projectId }) : new Spanner()\n return spanner.instance(instanceName).database(databaseName)\n}\n\nexport const init = async (config: Config, configPath: string) => {\n await writeConfig(configPath, config)\n}\n\nexport const create = async (config: DatabaseConfig, description: string) => {\n await createMigration(config.migrationsPath, description)\n}\n\nexport const up = async (\n config: Config,\n database?: DatabaseConfig,\n max?: number\n) => {\n // Check arguments\n if (max && !database) {\n throw new Error('Max number of migrations requires specifying a database')\n }\n const databases = database ? [database] : config.instance.databases\n\n for (const databaseConfig of databases) {\n const path: DbPath = {\n projectId: config.projectId,\n instanceName: config.instance.name,\n databaseName: databaseConfig.name,\n }\n const db = getDb(path)\n\n await ensureMigrationTable(db)\n\n const appliedMigrations = await getAppliedMigrations(db)\n const migrationFiles = await getMigrationFiles(\n databaseConfig.migrationsPath\n )\n const newMigrations = getNewMigrations(appliedMigrations, migrationFiles)\n\n console.log(`Found ${newMigrations.length} new migrations.`)\n console.log(newMigrations.map((mig) => `\\t${mig}`).join('\\n'))\n\n // Limit number of migrations if specified\n const newMigrationsToApply = max\n ? newMigrations.slice(0, max)\n : newMigrations\n\n for (const id of newMigrationsToApply) {\n const migration = await getMigration(databaseConfig.migrationsPath, id)\n await applyUp(db, migration)\n }\n }\n}\n\nexport const down = async (config: Config, database: DatabaseConfig) => {\n const path: DbPath = {\n projectId: config.projectId,\n instanceName: config.instance.name,\n databaseName: database.name,\n }\n const db = getDb(path)\n\n await ensureMigrationTable(db)\n\n await applyDown(db)\n}\n\nexport const status = async (config: Config, databases?: DatabaseConfig[]) => {\n const statuses: string[] = []\n for (const databaseConfig of databases || config.instance.databases) {\n const path: DbPath = {\n projectId: config.projectId,\n instanceName: config.instance.name,\n databaseName: databaseConfig.name,\n }\n const db = getDb(path)\n\n await ensureMigrationTable(db)\n\n const appliedMigrations = await getAppliedMigrations(db)\n const migrationFiles = await getMigrationFiles(\n databaseConfig.migrationsPath\n )\n const newMigrations = getNewMigrations(appliedMigrations, migrationFiles)\n\n statuses.push(\n [\n `Migrations [${databaseConfig.name}]`,\n '',\n 'Applied',\n '--------------------------------------------------------------------------------',\n `${appliedMigrations.map((m) => m.id).join('\\n')}\\n`,\n 'New',\n '--------------------------------------------------------------------------------',\n `${newMigrations.join('\\n')}\\n`,\n ].join('\\n')\n )\n }\n\n return statuses.join('\\n\\n')\n}\n","import type { Database } from '@google-cloud/spanner'\nimport type { ExecuteSqlRequest, Migration } from './types'\n\nexport const applyUp = async (db: Database, migration: Migration) => {\n try {\n // Apply the up migration\n await runScript(db, migration.up)\n console.log(\n `Successfully applied migration script for: ${migration.description}`\n )\n\n // Record in the `migrations` table\n const req: ExecuteSqlRequest = {\n sql: `\n INSERT INTO migrations (id, description, applied_at, up, down)\n VALUES (@id, @description, CURRENT_TIMESTAMP(), @up, @down)\n `,\n params: migration,\n json: true,\n }\n\n await db.runTransactionAsync(async (transaction) => {\n await transaction.runUpdate(req)\n await transaction.commit()\n })\n console.log(`Migration recorded in the database: ${migration.id}`)\n } catch (error) {\n throw new Error(\n `Failed to apply migration ${migration.id}: ${(error as Error).message}`\n )\n }\n}\n\nexport const applyDown = async (db: Database) => {\n // Step 1: Get the last applied migration\n const req: ExecuteSqlRequest = {\n sql: `\n SELECT id, description, up, down\n FROM migrations\n ORDER BY applied_at DESC\n LIMIT 1\n `,\n json: true,\n }\n const [rows] = await db.run(req)\n const lastMigration = rows?.[0] as Migration\n\n if (!lastMigration) {\n throw new Error('No migrations found to roll back.')\n }\n\n // Step 2: Apply the down script\n try {\n await runScript(db, lastMigration.down)\n } catch (error) {\n throw new Error(\n `Failed to apply down script for migration ${lastMigration.id}: ${(error as Error).message}`\n )\n }\n\n // Step 3: Remove the migration record\n await db.runTransactionAsync(async (transaction) => {\n await transaction.runUpdate({\n sql: `\n DELETE FROM migrations\n WHERE id = @id\n `,\n params: { id: lastMigration.id },\n })\n await transaction.commit()\n })\n\n console.log(\n `Successfully rolled back migration: ${lastMigration.description}`\n )\n}\n\nconst runScript = async (db: Database, script: string): Promise<void> => {\n // Split the script into individual statements by ``\n const statements = script\n .split(';') // Split by `;`\n .filter(Boolean) // Remove empty statements\n .map((stmt) => stmt.trim()) // Remove leading/trailing whitespace\n .filter(Boolean) // Remove empty statements\n\n if (statements.length === 0) {\n throw new Error('No valid SQL statements found in the script.')\n }\n\n // Loop over statements (since schema changes cannot be run in a transaction)\n for (const statement of statements) {\n console.log(`Executing statement: ${statement}`)\n\n if (isSchemaChange(statement)) {\n await db.updateSchema(statement)\n } else {\n await db.runTransactionAsync(async (transaction) => {\n await transaction.runUpdate(statement)\n await transaction.commit()\n })\n }\n }\n}\n\nconst isSchemaChange = (sql: string) =>\n /^\\s*(CREATE|ALTER|DROP|TRUNCATE)\\b/i.test(sql)\n","import type { Database } from '@google-cloud/spanner'\nimport type { ExecuteSqlRequest, Migration } from './types'\n\nexport const SQL_SELECT_TABLE_MIGRATIONS = `\n SELECT\n t.TABLE_NAME,\n c.COLUMN_NAME,\n c.SPANNER_TYPE\n FROM\n information_schema.TABLES t\n INNER JOIN\n \tinformation_schema.COLUMNS c\n ON t.TABLE_NAME = c.TABLE_NAME\n WHERE\n t.TABLE_NAME = 'migrations'\n`\n\nexport const SQL_CREATE_TABLE_MIGRATIONS = `\n CREATE TABLE migrations (\n id STRING(128) NOT NULL,\n description STRING(256) NOT NULL,\n applied_at TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp = true),\n up STRING(MAX),\n down STRING(MAX)\n ) PRIMARY KEY (id)\n`\n\nexport const ensureMigrationTable = async (db: Database) => {\n // Check if table exists\n const [rows] = await db.run({ sql: SQL_SELECT_TABLE_MIGRATIONS, json: true })\n\n if (rows.length === 0) {\n // Create migration table\n console.log('Creating migration table')\n try {\n await db.updateSchema(SQL_CREATE_TABLE_MIGRATIONS)\n } catch (err) {\n console.error('Failed to create migrations table')\n throw err\n }\n } else {\n const typedRows = rows as {\n TABLE_NAME: string\n COLUMN_NAME: string\n SPANNER_TYPE: string\n }[]\n const upType = typedRows.find((r) => r.COLUMN_NAME === 'up')\n const downType = typedRows.find((r) => r.COLUMN_NAME === 'down')\n const expectedType = 'STRING(MAX)'\n\n if (upType?.SPANNER_TYPE !== expectedType) {\n try {\n console.log(\n `Updating 'up' column of migration table to ${expectedType}`\n )\n await db.updateSchema(\n `ALTER TABLE migrations ALTER COLUMN up ${expectedType}`\n )\n } catch (err) {\n console.error('Failed to update migrations table')\n throw err\n }\n }\n\n if (downType?.SPANNER_TYPE !== expectedType) {\n try {\n console.log(\n `Updating 'down' column of migration table to ${expectedType}`\n )\n await db.updateSchema(\n `ALTER TABLE migrations ALTER COLUMN down ${expectedType}`\n )\n } catch (err) {\n console.error('Failed to update migrations table')\n throw err\n }\n }\n }\n}\n\nexport const getAppliedMigrations = async (\n db: Database\n): Promise<Migration[]> => {\n try {\n // Query the database for all applied migrations, ordered by applied_at\n const req: ExecuteSqlRequest = {\n sql: `\n SELECT id, description, up, down, applied_at as appliedAt\n FROM migrations\n ORDER BY applied_at ASC\n `,\n json: true,\n }\n const [rows] = await db.run(req)\n\n return rows as Migration[]\n } catch (error) {\n throw new Error(\n `Failed to get applied migrations: ${(error as Error).message}`\n )\n }\n}\n","import { access, mkdir, readdir, readFile, writeFile } from 'node:fs/promises'\nimport { join, resolve } from 'node:path'\nimport type { Config, Migration } from './types'\n\nexport const getMigrationFiles = async (path: string): Promise<string[]> => {\n try {\n // Read the directory contents\n const files = await readdir(path)\n\n // Filter and map files to extract the `id` (file name without extension)\n const migrationFileIds = files\n .filter((file) => file.endsWith('.sql')) // Only include .sql files\n .map((file) => file.replace(/\\.sql$/, '')) // Remove file extension to use as `id`\n\n return migrationFileIds\n } catch (error) {\n throw new Error(\n `Failed to get migration files: ${(error as Error).message}`\n )\n }\n}\n\nexport const getMigration = async (\n path: string,\n id: string\n): Promise<Migration> => {\n try {\n // Construct the full file path\n const filePath = resolve(process.cwd(), join(path, `${id}.sql`))\n\n // Check if the file exists\n try {\n await access(filePath)\n } catch {\n throw new Error(`Migration file not found: ${filePath}`)\n }\n\n // Dynamically import the migration file\n const migrationText = await readFile(filePath, 'utf8')\n\n const up = getSql(migrationText, 'up')\n const down = getSql(migrationText, 'down')\n const description = getDescription(migrationText)\n\n // Validate that the required exports (`up` and `down`) exist\n if (!up || !down) {\n throw new Error(\n `Migration file ${filePath} does not export required scripts (up, down).`\n )\n }\n\n // Return the migration as a `Migration` object\n return { id, description, up, down }\n } catch (error) {\n throw new Error(\n `Failed to get migration ${id}: ${(error as Error).message}`\n )\n }\n}\n\nconst getDescription = (text: string | undefined) =>\n text?.match(/^--\\s*Description:\\s*(.+)$/m)?.[1]?.trim() || ''\n\nconst getSql = (text: string | undefined, direction: 'up' | 'down') => {\n const rx = {\n up: /---- UP ----\\n([\\s\\S]*?)\\n---- DOWN ----/,\n down: /---- DOWN ----\\n([\\s\\S]*)$/,\n }\n return text?.match(rx[direction])?.[1]?.replace(/--.*$/gm, '').trim()\n}\n\nexport const getNewMigrations = (\n applied: Migration[],\n files: string[]\n): string[] => {\n // Ensure files are sorted to match applied sequence\n const sortedFiles = files.sort()\n\n // Check for interlacing or missing migrations\n for (let ix = 0; ix < applied.length; ix++) {\n if (sortedFiles[ix] !== applied[ix].id) {\n throw new Error(\n `Mismatch between applied migrations and files. Found '${sortedFiles[ix]}' but expected '${applied[ix].id}' at position ${ix}.`\n )\n }\n }\n\n // Return new migrations (files not already applied)\n const newMigrations = sortedFiles.slice(applied.length)\n\n return newMigrations\n}\n\nexport const createMigration = async (\n path: string,\n description: string\n): Promise<void> => {\n // Generate timestamp and parse description to create the migration ID/filename\n const timestamp = new Date().toISOString()\n const compactTimestamp = timestamp.replace(/[-:.TZ]/g, '')\n const parsedDescription = description.replace(/\\s+/g, '_').toLowerCase()\n const filename = `${compactTimestamp}_${parsedDescription}.sql`\n\n // Full file path\n const filePath = join(path, filename)\n\n // Template migration content\n const template = `-- Created: ${timestamp}\n-- Description: ${description}\n\n---- UP ----\n\n\n\n---- DOWN ----\n\n\n`\n\n try {\n // Ensure the directory exists\n await mkdir(path, { recursive: true })\n\n // Write the migration file\n await writeFile(filePath, template.trim(), 'utf8')\n\n console.log(`Migration created: ${filePath}`)\n } catch (error) {\n throw new Error(`Error creating migration: ${(error as Error).message}`)\n }\n}\n\nexport const writeConfig = async (\n path: string,\n config: Config\n): Promise<void> => {\n try {\n // Serialize the config object into a pretty JSON format\n const configContent = JSON.stringify(config, null, 2)\n\n // Write the config to the specified path\n await writeFile(path, configContent, 'utf8')\n\n console.log(`Configuration written to ${path}`)\n } catch (error) {\n throw new Error(\n `Error writing configuration to ${path}: ${(error as Error).message}`\n )\n }\n}\n"],"mappings":"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","names":["up","down"]}
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  init,
6
6
  status,
7
7
  up
8
- } from "./chunk-XP6DPC5R.js";
8
+ } from "./chunk-UJTIK6KC.js";
9
9
 
10
10
  // src/cli.ts
11
11
  import fs from "fs/promises";
@@ -214,3 +214,4 @@ var getDatabaseConfig = async (required) => {
214
214
  migrationsPath
215
215
  };
216
216
  };
217
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { input, select } from '@inquirer/prompts'\nimport yargs from 'yargs'\nimport { hideBin } from 'yargs/helpers'\nimport { create, down, init, status, up } from './index'\nimport type { Config, DatabaseConfig } from './types'\n\nconst CONFIG_FILE = './.spanner-migrate.config.json'\n\nyargs(hideBin(process.argv))\n .scriptName('spanner-migrate')\n .usage('$0 <command>')\n\n /**\n * Handles the `init` command, which initializes a `.spanner-migrate.config.json` file.\n *\n * - Prompts the user to enter a Spanner instance name.\n * - Collects database configurations interactively.\n * - Allows an optional Google Cloud project name.\n * - Writes the generated configuration to the `CONFIG_FILE`.\n *\n * @throws {Error} If required input (e.g., instance name) is not provided.\n */\n .command(\n 'init',\n 'Initialize a .spanner-migrate.config.json file',\n async () => {\n // Ask for instance name\n const instanceName = await input({\n message: 'Enter Spanner instance name',\n required: true,\n })\n\n // Ask for database name\n const databases: DatabaseConfig[] = [\n (await getDatabaseConfig(true)) as DatabaseConfig,\n ]\n\n // Loop to allow adding multiple databases\n while (true) {\n const dbConfig = await getDatabaseConfig(false)\n if (!dbConfig) break\n databases.push(dbConfig)\n }\n\n // Ask for project name\n const projectId = await input({\n message: 'Enter Google Cloud project name',\n required: false,\n })\n\n // Construct the final configuration\n const config: Config = {\n instance: {\n name: instanceName,\n databases,\n },\n }\n if (projectId) config.projectId = projectId\n\n await init(config, CONFIG_FILE)\n }\n )\n\n /**\n * Handles the `create` command, which generates a new migration file.\n *\n * - If `--database` (`-d`) is provided, it uses the specified database.\n * - If multiple databases exist and none is specified, it prompts the user to select one.\n * - The migration filename is constructed by joining `description` words with `_`.\n *\n * @param {string} [database] - (Optional) The name of the database to use. Must match an existing database.\n * @param {string[]} description - The words describing the migration. These will be joined with `_` in the filename.\n *\n * @throws {Error} If the specified database does not exist or if no valid database is found.\n */\n .command<{ database?: string; description: string[] }>(\n 'create <description ...>',\n 'Create a new migration file',\n (yargs) => {\n yargs\n .option('database', {\n alias: 'd',\n type: 'string',\n describe: 'Database name',\n })\n .positional('description', {\n type: 'string',\n describe: 'Description of the migration',\n demandOption: true,\n })\n },\n async (args) => {\n const config = await loadConfig()\n const fullDescription = args.description.join(' ')\n\n let databaseConfig: DatabaseConfig | undefined\n\n if (args.database) {\n // Look for the specified database in the config\n databaseConfig = config.instance.databases.find(\n (db) => db.name === args.database\n )\n if (!databaseConfig) {\n throw new Error(`Unknown database name \"${args.database}\"`)\n }\n } else {\n // Auto-select if there's only one database, otherwise prompt user\n if (config.instance.databases.length === 1) {\n databaseConfig = config.instance.databases[0]\n } else {\n databaseConfig = await select<DatabaseConfig>({\n message: 'Select database',\n choices: config.instance.databases.map((dbConfig) => ({\n name: dbConfig.name,\n value: dbConfig,\n })),\n })\n }\n }\n\n if (!databaseConfig) throw new Error('No database config found')\n\n await create(databaseConfig, fullDescription)\n console.log(\n `Migration file created: '${join(databaseConfig.migrationsPath, args.description.join('_'))}.sql'`\n )\n }\n )\n\n /**\n * Applies pending migrations to one or more databases.\n *\n * - If no `--database` and no `--max` are provided, applies all migrations to all databases.\n * - If `--max` is specified, `--database` is required.\n * - If `--max` is provided, it must be an integer greater than 0.\n * - If a non-existing database is specified, the command throws an error.\n * - If a valid database is specified without `--max`, applies all migrations for that database.\n * - Calls `up` with either all databases (`up(config)`) or a specific one (`up(config, database, max?)`).\n *\n * @throws {Error} If `--max` is used without `--database`, or if `--max` is invalid.\n * @throws {Error} If the specified database does not exist.\n */\n .command<{ database?: string; max?: number }>(\n 'up',\n 'Apply migrations',\n (yargs) => {\n yargs\n .option('database', {\n alias: 'd',\n type: 'string',\n describe: 'Database name',\n requiresArg: false,\n })\n .option('max', {\n alias: 'm',\n type: 'number',\n describe:\n 'Maximum number of migrations to apply (requires --database)',\n requiresArg: false,\n })\n },\n async (args) => {\n const config = await loadConfig()\n\n if (args.max !== undefined) {\n if (!args.database) {\n throw new Error('The --max option requires a specified --database')\n }\n if (!Number.isInteger(args.max) || args.max <= 0) {\n throw new Error('The --max option must be an integer greater than 0')\n }\n }\n\n if (args.database) {\n // Validate database\n const databaseConfig = config.instance.databases.find(\n (db) => db.name === args.database\n )\n if (!databaseConfig) {\n throw new Error(`Unknown database name \"${args.database}\"`)\n }\n\n // Call `up(config, database, max?)`\n if (args.max !== undefined) {\n await up(config, databaseConfig, args.max)\n } else {\n await up(config, databaseConfig)\n }\n } else {\n // No database specified, apply to all\n await up(config)\n }\n\n console.log('Migrations applied successfully.')\n }\n )\n\n /**\n * Handles the `down` command, which rolls back the last applied migration.\n *\n * - If a single database exists, it is automatically selected.\n * - If multiple databases exist, `--database` is **required**.\n * - If `--database` is specified, it must match an existing database.\n *\n * @throws {Error} If multiple databases exist and `--database` is not provided.\n * @throws {Error} If the specified `database` does not exist in the configuration.\n */\n .command<{ database?: string }>(\n 'down',\n 'Roll back the last applied migration',\n (yargs) => {\n yargs.option('database', {\n alias: 'd',\n type: 'string',\n describe:\n 'Specify the database to roll back (required if multiple databases exist)',\n })\n },\n async (args) => {\n const config = await loadConfig()\n\n let databaseConfig: DatabaseConfig | undefined\n if (args.database) {\n databaseConfig = config.instance.databases.find(\n (dbConfig) => dbConfig.name === args.database\n )\n if (!databaseConfig) {\n throw new Error(`Unknown database name \"${args.database}\"`)\n }\n } else if (config.instance.databases.length === 1) {\n databaseConfig = config.instance.databases[0]\n } else {\n throw new Error(\n 'Multiple databases detected. Use --database to specify which one to roll back.'\n )\n }\n\n if (!databaseConfig) throw new Error('No database config found')\n\n await down(config, databaseConfig)\n console.log('Last migration rolled back successfully.')\n }\n )\n\n /**\n * Handles the `status` command, which displays the migration status.\n *\n * - If `--database` is specified, it must match an existing database.\n * - If no `--database` is provided, `status` runs for all databases in the config.\n *\n * @throws {Error} If the specified `database` does not exist in the configuration.\n */\n .command<{ database?: string }>(\n 'status',\n 'Show the migration status',\n (yargs) => {\n yargs.option('database', {\n alias: 'd',\n type: 'string',\n describe:\n 'Specify a database to check status (optional, runs on all databases if omitted)',\n })\n },\n async (args) => {\n const config = await loadConfig()\n\n let migrationStatus: string\n\n if (args.database) {\n const databaseConfig = config.instance.databases.find(\n (db) => db.name === args.database\n )\n if (!databaseConfig) {\n throw new Error(`Unknown database name \"${args.database}\"`)\n }\n migrationStatus = await status(config, [databaseConfig])\n } else {\n migrationStatus = await status(config)\n }\n\n console.log(migrationStatus)\n }\n )\n\n .demandCommand()\n .help()\n .parse()\n\n//#region Helper functions\n\n/**\n * Loads the migration configuration from the config file.\n *\n * @returns {Promise<Config>} The parsed configuration object.\n * @throws {Error} If the config file is missing or invalid.\n */\nasync function loadConfig(): Promise<Config> {\n try {\n const configContent = await fs.readFile(CONFIG_FILE, 'utf8')\n return JSON.parse(configContent)\n } catch {\n console.error('Config file not found. Run \"spanner-migrate init\" first.')\n process.exit(1)\n }\n}\n\n/**\n * Prompts the user for database configuration details.\n *\n * @param {boolean} required - Whether the database entry is required.\n * @returns {Promise<DatabaseConfig | undefined>} The database configuration or undefined if skipped.\n */\nconst getDatabaseConfig = async (required: boolean) => {\n const message = required\n ? 'Enter Spanner database name'\n : 'Enter another Spanner database name [Enter to continue]'\n const name = await input({\n message,\n required,\n })\n if (!name) return\n\n const migrationsPath = await input({\n message: 'Enter the path for your migrations',\n required: true,\n default: `./migrations/${name}`,\n })\n return {\n name,\n migrationsPath,\n } as DatabaseConfig\n}\n\n//#endregion\n"],"mappings":"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","names":["yargs"]}
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  init,
5
5
  status,
6
6
  up
7
- } from "./chunk-XP6DPC5R.js";
7
+ } from "./chunk-UJTIK6KC.js";
8
8
  export {
9
9
  create,
10
10
  down,
@@ -12,3 +12,4 @@ export {
12
12
  status,
13
13
  up
14
14
  };
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,16 +1,22 @@
1
1
  {
2
2
  "name": "@sebspark/spanner-migrate",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
8
14
  "files": [
9
15
  "dist"
10
16
  ],
11
17
  "bin": "./dist/cli.js",
12
18
  "scripts": {
13
- "build": "tsup-node src/index.ts src/cli.ts --format esm --target node22 --dts",
19
+ "build": "tsup src/index.ts src/cli.ts --config ./tsup.config.ts",
14
20
  "dev": "tsc --watch --noEmit",
15
21
  "lint": "biome check .",
16
22
  "test": "vitest run --passWithNoTests --coverage",