@aurios/mizzling 1.0.0 → 1.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.
- package/CHANGELOG.md +18 -0
- package/dist/chunk-SNI5EXF5.js +2 -0
- package/dist/cli.js +23 -0
- package/dist/index.js +1 -22
- package/package.json +5 -2
- package/src/cli.ts +88 -0
- package/src/commands/push.ts +1 -1
- package/src/config.ts +24 -1
- package/src/index.ts +1 -88
- package/tsup.config.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# mizzling
|
|
2
2
|
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 5dd0c9f: rename packages to @aurios scope
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 114efb9: Completed 100% JSDoc/TSDoc coverage for all public APIs and improved internal type safety.
|
|
12
|
+
|
|
13
|
+
- **@aurios/mizzle**: Added comprehensive documentation to Query Builders, Schema Definitions, and the main entry point. Resolved numerous linting issues by replacing `any` with safer alternatives.
|
|
14
|
+
- **@aurios/mizzling**: Fixed CLI entry point in E2E and integration tests, ensuring CI stability.
|
|
15
|
+
- **@mizzle/shared**: Enhanced utility type safety.
|
|
16
|
+
- **Infrastructure**: Updated Turbo configuration to handle new environment variables.
|
|
17
|
+
|
|
18
|
+
- Updated dependencies [114efb9]
|
|
19
|
+
- @mizzle/shared@0.0.2
|
|
20
|
+
|
|
3
21
|
## 1.0.2
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{join as s}from"path";import{existsSync as c}from"fs";import{DynamoDBClient as a}from"@aws-sdk/client-dynamodb";import{fromIni as f}from"@aws-sdk/credential-provider-ini";import{NodeHttpHandler as p}from"@smithy/node-http-handler";import l from"http";import m from"https";function Z(e){return e}function w(e){let r={keepAlive:!0,maxSockets:1/0},t={region:e.region||"us-east-1",endpoint:e.endpoint,maxAttempts:e.maxAttempts,requestHandler:new p({httpAgent:new l.Agent(r),httpsAgent:new m.Agent(r)})};return e.credentials?t.credentials=e.credentials:e.profile?t.credentials=f({profile:e.profile}):e.endpoint&&(e.endpoint.includes("localhost")||e.endpoint.includes("127.0.0.1"))&&(t.credentials={accessKeyId:"local",secretAccessKey:"local"}),new a(t)}async function M(e="mizzle.config.ts"){let t=process.env.MIZZLE_CONFIG||s(process.cwd(),e);if(!c(t))throw new Error(`Could not find ${e} in current directory.`);try{let n=await import(t),o=n.default||n;if(!o||typeof o!="object")throw new Error("Invalid config: default export must be an object");if(!o.schema)throw new Error("Invalid config: missing 'schema' path");if(!o.out)throw new Error("Invalid config: missing 'out' directory");let i={...o};return process.env.MIZZLE_REGION&&(i.region=process.env.MIZZLE_REGION),process.env.MIZZLE_ENDPOINT&&(i.endpoint=process.env.MIZZLE_ENDPOINT),process.env.MIZZLE_SCHEMA&&(i.schema=process.env.MIZZLE_SCHEMA),process.env.MIZZLE_OUT&&(i.out=process.env.MIZZLE_OUT),i}catch(n){if(n instanceof Error&&n.message.startsWith("Invalid config"))throw n;let o=n instanceof Error?n.message:String(n);throw new Error(`Failed to load config: ${o}`)}}export{Z as a,w as b,M as c};
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{b as g,c as N}from"./chunk-SNI5EXF5.js";import{Command as Re}from"commander";import*as b from"@clack/prompts";var f={COLUMNS:Symbol.for("mizzle:Columns"),INDEXES:Symbol.for("mizzle:Indexes"),SORT_KEY:Symbol.for("mizzle:SortKey"),TABLE_NAME:Symbol.for("mizzle:TableName"),PARTITION_KEY:Symbol.for("mizzle:PartitionKey")},p={ENTITY_NAME:Symbol.for("mizzle:EntityName"),ENTITY_STRATEGY:Symbol.for("mizzle:EntityStrategy"),PHYSICAL_TABLE:Symbol.for("mizzle:PhysicalTable"),COLUMNS:Symbol.for("mizzle:Columns"),ENTITY_KIND:Symbol.for("mizzle:EntityKind")};var O=class{[f.TABLE_NAME]="";[f.INDEXES]=void 0;[f.PARTITION_KEY]={};[f.SORT_KEY]=void 0;static Symbol=f;constructor(e,n){this[f.TABLE_NAME]=e,this[f.PARTITION_KEY]=n.pk.build(this),this[f.SORT_KEY]=n.sk?n.sk.build(this):void 0,this[f.INDEXES]=n.indexes}},v=class{[p.ENTITY_NAME]="";[p.PHYSICAL_TABLE]={};[p.COLUMNS]={};[p.ENTITY_STRATEGY]={};static Symbol=p;constructor(e,n,t,o){this[p.ENTITY_NAME]=e,this[p.PHYSICAL_TABLE]=n,this[p.COLUMNS]=t,this[p.ENTITY_STRATEGY]=o}};var M={COLUMNS:Symbol.for("mizzle:Columns"),INDEXES:Symbol.for("mizzle:Indexes"),SORT_KEY:Symbol.for("mizzle:SortKey"),TABLE_NAME:Symbol.for("mizzle:TableName"),PARTITION_KEY:Symbol.for("mizzle:PartitionKey")},K={ENTITY_NAME:Symbol.for("mizzle:EntityName"),ENTITY_STRATEGY:Symbol.for("mizzle:EntityStrategy"),PHYSICAL_TABLE:Symbol.for("mizzle:PhysicalTable"),COLUMNS:Symbol.for("mizzle:Columns"),ENTITY_KIND:Symbol.for("mizzle:EntityKind")};import Q from"fast-glob";import{stat as Z}from"fs/promises";import{resolve as ee}from"path";async function A(e){let n=Array.isArray(e.schema)?e.schema:[e.schema],t=[],o=[],a=new Set,i=async r=>{let s=ee(process.cwd(),r);if(!a.has(s)){a.add(s);try{let l=await import(s);for(let m in l){let c=l[m];!c||typeof c!="object"||(c instanceof O||c[M.TABLE_NAME]!==void 0?t.push(c):(c instanceof v||c[K.ENTITY_NAME]!==void 0)&&o.push(c))}}catch(l){console.warn(`Failed to import schema file: ${s}`,l)}}};for(let r of n){let s=r,l=!1;try{let c=await Z(r);c.isDirectory()?s=`${r}/**/*.{ts,js,tsx,jsx}`:c.isFile()&&(l=!0)}catch{}if(l){await i(r);continue}let m=await Q(s,{absolute:!0});for(let c of m)await i(c)}return{tables:t,entities:o}}import{join as $}from"path";import{writeFile as te,readFile as ne,mkdir as oe,readdir as ae}from"fs/promises";import{existsSync as k}from"fs";var j="snapshot.json";async function Y(e,n){k(e)||await oe(e,{recursive:!0});let t=$(e,j);await te(t,JSON.stringify(n,null,2),"utf-8")}async function P(e){let n=$(e,j);if(!k(n))return null;let t=await ne(n,"utf-8");return JSON.parse(t)}function E(e){let n={};for(let t of e.tables){let o=e.entities.filter(i=>i[p.PHYSICAL_TABLE]===t),a=ie(t,o);n[a.TableName]=a}return{version:"1",tables:n}}async function R(e){if(!k(e))return"0000";let n=await ae(e),t=-1;for(let o of n){if(!o.endsWith(".ts"))continue;let a=o.match(/^(\d{4})_/);if(a){let i=parseInt(a[1],10);i>t&&(t=i)}}return t===-1?"0000":(t+1).toString().padStart(4,"0")}function ie(e,n){let t=e[f.TABLE_NAME],o=new Map,a=e[f.PARTITION_KEY];o.set(a.name,a.getDynamoType());let i=e[f.SORT_KEY];i&&o.set(i.name,i.getDynamoType());let r=[{AttributeName:a.name,KeyType:"HASH"}];i&&r.push({AttributeName:i.name,KeyType:"RANGE"});let s=[],l=[],m=e[f.INDEXES]||{};for(let[d,y]of Object.entries(m)){let B=y.type,u=y.config;if(B==="gsi"){if(u.pk){let T=_(u.pk,e,n);o.set(u.pk,T)}if(u.sk){let T=_(u.sk,e,n);o.set(u.sk,T)}let x={IndexName:d,KeySchema:[{AttributeName:u.pk,KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}};u.sk&&x.KeySchema.push({AttributeName:u.sk,KeyType:"RANGE"}),s.push(x)}else if(B==="lsi"){if(u.sk){let T=_(u.sk,e,n);o.set(u.sk,T)}let x={IndexName:d,KeySchema:[{AttributeName:a.name,KeyType:"HASH"},{AttributeName:u.sk,KeyType:"RANGE"}],Projection:{ProjectionType:"ALL"}};l.push(x)}}let c=Array.from(o.entries()).map(([d,y])=>({AttributeName:d,AttributeType:y})).sort((d,y)=>d.AttributeName.localeCompare(y.AttributeName));s.sort((d,y)=>(d.IndexName||"").localeCompare(y.IndexName||"")),l.sort((d,y)=>(d.IndexName||"").localeCompare(y.IndexName||""));let S={TableName:t,AttributeDefinitions:c,KeySchema:r};return s.length>0&&(S.GlobalSecondaryIndexes=s),l.length>0&&(S.LocalSecondaryIndexes=l),S}function _(e,n,t){let o=n[f.PARTITION_KEY];if(o.name===e)return o.getDynamoType();let a=n[f.SORT_KEY];if(a&&a.name===e)return a.getDynamoType();for(let i of t){let r=i[p.COLUMNS];if(r){let s=r[e];if(s)return s.getDynamoType()}}throw new Error(`Could not resolve type for column '${e}' in table '${n[f.TABLE_NAME]}'. Ensure it is defined in an Entity.`)}function w(e,n){let t=[],o=E(e).tables,a=n.tables||{},i=new Set([...Object.keys(o),...Object.keys(a)]);for(let r of i){let s=o[r],l=a[r];s&&!l?t.push({type:"create",table:s}):!s&&l?t.push({type:"delete",tableName:r}):s&&l&&(re(s,l)||t.push({type:"update",tableName:r,changes:["Changed"]}))}return t}function re(e,n){let t=o=>{let a={...o};return a.AttributeDefinitions=[...a.AttributeDefinitions||[]].sort((i,r)=>(i.AttributeName||"").localeCompare(r.AttributeName||"")),a.GlobalSecondaryIndexes&&(a.GlobalSecondaryIndexes=[...a.GlobalSecondaryIndexes].sort((i,r)=>(i.IndexName||"").localeCompare(r.IndexName||""))),a.LocalSecondaryIndexes&&(a.LocalSecondaryIndexes=[...a.LocalSecondaryIndexes].sort((i,r)=>(i.IndexName||"").localeCompare(r.IndexName||""))),a};return JSON.stringify(t(e))===JSON.stringify(t(n))}import{join as se}from"path";import{writeFile as le,mkdir as ce}from"fs/promises";import{existsSync as me}from"fs";import{text as fe,isCancel as ue,cancel as pe,intro as de,outro as U}from"@clack/prompts";async function F(e){de("Mizzle Generate");let{config:n}=e,t=e.discoverSchema||A;try{let o=await t(n),a=n.out,i=await P(a)||{version:"0",tables:{}},r=E(o),s=w(o,i);if(s.length===0){U("No changes detected.");return}console.log(`Detected ${s.length} changes.`);let l=await R(a),m=e.name;if(m||(m=await fe({message:"Enter migration name",placeholder:"init",initialValue:"migration",validate(y){if(y.length===0)return"Name is required"}})),ue(m)){pe("Operation cancelled.");return}let c=`${l}_${m}.ts`;me(a)||await ce(a,{recursive:!0});let S=se(a,c),d=ye(s);await le(S,d),console.log(`Created migration: ${c}`),await Y(a,r),U("Updated snapshot.json")}catch(o){console.error("Error generating migration:",o),process.exit(1)}}function ye(e){let n=[],t=[];for(let o of e)o.type==="create"?(n.push(`// Create Table: ${o.table.TableName}`),n.push(`await db.createTable("${o.table.TableName}", ${JSON.stringify(o.table,null,2)});
|
|
3
|
+
`),t.unshift(`// Drop Table: ${o.table.TableName}`),t.unshift(`await db.deleteTable("${o.table.TableName}");
|
|
4
|
+
`)):o.type==="delete"?(n.push(`// Drop Table: ${o.tableName}`),n.push(`await db.deleteTable("${o.tableName}");
|
|
5
|
+
`),t.unshift(`// Create Table: ${o.tableName}`),t.unshift(`// TODO: Restore table definition for rollback
|
|
6
|
+
`)):o.type==="update"&&(n.push(`// Update Table: ${o.tableName}`),t.unshift(`// Revert Update Table: ${o.tableName}`));return`import { Mizzle } from "@aurios/mizzle";
|
|
7
|
+
|
|
8
|
+
export async function up(db: Mizzle) {
|
|
9
|
+
${n.join(" ")}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function down(db: Mizzle) {
|
|
13
|
+
${t.join(" ")}
|
|
14
|
+
}
|
|
15
|
+
`}import{existsSync as he,writeFileSync as ge}from"fs";import{join as be}from"path";import{intro as Se,outro as Te,text as I,isCancel as C,cancel as z}from"@clack/prompts";async function G(){let e=be(process.cwd(),"mizzle.config.ts");if(he(e)){console.log("mizzle.config.ts already exists in the current directory. Aborting.");return}Se("Mizzle Initialization");let n=await I({message:"Where is your schema file or directory located?",placeholder:"./src/schema.ts",initialValue:"./src/schema.ts",validate:r=>{if(!r)return"Schema path is required"}});if(C(n)){z("Operation cancelled.");return}let t=await I({message:"Where should Mizzle store migrations and snapshots?",placeholder:"./migrations",initialValue:"./migrations",validate:r=>{if(!r)return"Output directory is required"}});if(C(t)){z("Operation cancelled.");return}let o=await I({message:"Which AWS region do you want to use?",placeholder:"us-east-1",initialValue:"us-east-1"});if(C(o)){z("Operation cancelled.");return}let a=await I({message:"Do you want to use a custom endpoint (e.g., for local development)?",placeholder:"http://localhost:8000 (optional)"});if(C(a)){z("Operation cancelled.");return}let i=`import { defineConfig } from "@aurios/mizzle";
|
|
16
|
+
|
|
17
|
+
export default defineConfig({
|
|
18
|
+
schema: "${n}",
|
|
19
|
+
out: "${t}",
|
|
20
|
+
region: "${o}",
|
|
21
|
+
${a?`endpoint: "${a}",`:'// endpoint: "http://localhost:8000",'}
|
|
22
|
+
});
|
|
23
|
+
`;ge(e,i),Te("mizzle.config.ts created successfully!")}import{ListTablesCommand as Ne,DescribeTableCommand as Ee}from"@aws-sdk/client-dynamodb";async function D(e){let n={},t,o=[];do{let a=await e.send(new Ne({ExclusiveStartTableName:t}));a.TableNames&&o.push(...a.TableNames),t=a.LastEvaluatedTableName}while(t);for(let a of o)try{let i=await e.send(new Ee({TableName:a}));if(i.Table){let r=xe(i.Table);n[a]=r}}catch(i){console.warn(`Failed to describe table ${a}:`,i)}return{version:"remote",tables:n}}function xe(e){let n={TableName:e.TableName,AttributeDefinitions:e.AttributeDefinitions?.map(t=>({AttributeName:t.AttributeName,AttributeType:t.AttributeType})).sort((t,o)=>t.AttributeName.localeCompare(o.AttributeName))||[],KeySchema:e.KeySchema?.map(t=>({AttributeName:t.AttributeName,KeyType:t.KeyType}))||[]};return e.GlobalSecondaryIndexes&&e.GlobalSecondaryIndexes.length>0&&(n.GlobalSecondaryIndexes=e.GlobalSecondaryIndexes.map(t=>({IndexName:t.IndexName,KeySchema:t.KeySchema?.map(o=>({AttributeName:o.AttributeName,KeyType:o.KeyType})),Projection:t.Projection?{ProjectionType:t.Projection.ProjectionType}:void 0})).sort((t,o)=>t.IndexName.localeCompare(o.IndexName))),e.LocalSecondaryIndexes&&e.LocalSecondaryIndexes.length>0&&(n.LocalSecondaryIndexes=e.LocalSecondaryIndexes.map(t=>({IndexName:t.IndexName,KeySchema:t.KeySchema?.map(o=>({AttributeName:o.AttributeName,KeyType:o.KeyType})),Projection:t.Projection?{ProjectionType:t.Projection.ProjectionType}:void 0})).sort((t,o)=>t.IndexName.localeCompare(o.IndexName))),n}import{CreateTableCommand as Ae}from"@aws-sdk/client-dynamodb";import{confirm as we,isCancel as Ie,cancel as Ce,intro as ze,outro as H,spinner as De}from"@clack/prompts";async function V(e){ze("Mizzle Push");let{config:n,force:t}=e,o=e.discoverSchema||A,a=e.client||g(n);try{let i=await o(n),r=await D(a),s=w(i,r);if(s.length===0){H("Remote is up to date.");return}console.log(`Pushing ${s.length} changes to remote...`);let l=t;if(l||(l=await we({message:"Do you want to apply these changes?"})),Ie(l)||!l){Ce("Operation cancelled.");return}let m=De();m.start("Pushing changes...");for(let c of s)c.type==="create"?(m.message(`Creating table: ${c.table.TableName}`),await a.send(new Ae({TableName:c.table.TableName,AttributeDefinitions:c.table.AttributeDefinitions,KeySchema:c.table.KeySchema,GlobalSecondaryIndexes:c.table.GlobalSecondaryIndexes,LocalSecondaryIndexes:c.table.LocalSecondaryIndexes,BillingMode:"PAY_PER_REQUEST"}))):c.type==="delete"?console.log(`Untracked table found: ${c.tableName} (Skipping deletion)`):c.type==="update"&&m.message(`Updating table: ${c.tableName} (Not fully implemented)`);m.stop("Push complete."),H("Done")}catch(i){console.error("Error pushing changes:",i),process.exit(1)}}import"@aws-sdk/client-dynamodb";import{intro as Le,outro as J,spinner as Oe}from"@clack/prompts";async function W(e){Le("Mizzle List Tables");let n=e.client||g(e.config),t=Oe();t.start("Fetching remote tables...");try{let o=await D(n);t.stop("Fetched remote tables.");let a=Object.values(o.tables);if(a.length===0){console.log("No tables found in the remote environment."),J("Done");return}console.log(`Found ${a.length} tables:`);for(let i of a){console.log(`- ${i.TableName}`);let r=i.KeySchema.find(l=>l.KeyType==="HASH")?.AttributeName,s=i.KeySchema.find(l=>l.KeyType==="RANGE")?.AttributeName;console.log(` PK: ${r}, SK: ${s||"(none)"}`),i.GlobalSecondaryIndexes&&i.GlobalSecondaryIndexes.length>0&&console.log(` GSIs: ${i.GlobalSecondaryIndexes.map(l=>l.IndexName).join(", ")}`)}J("Done")}catch(o){t.stop("Failed to fetch tables."),console.error("Error listing tables:",o),process.exit(1)}}import{ListTablesCommand as ve,DeleteTableCommand as Me}from"@aws-sdk/client-dynamodb";import{intro as Ke,outro as L,multiselect as _e,confirm as ke,isCancel as q,cancel as Ye,spinner as Pe}from"@clack/prompts";async function X(e){Ke("Mizzle Drop Tables");let n=e.client||g(e.config);try{let t=new ve({}),a=(await n.send(t)).TableNames||[];if(a.length===0){console.log("No tables found in the remote environment."),L("Done");return}let i=await _e({message:"Select tables to DELETE (This action is irreversible!)",options:a.map(m=>({value:m,label:m}))});if(q(i)){Ye("Operation cancelled.");return}let r=i;if(r.length===0){console.log("No tables selected."),L("Done");return}let s=await ke({message:`Are you SURE you want to delete ${r.length} table(s)?`});if(q(s)||!s){console.log("Operation cancelled."),L("Done");return}let l=Pe();l.start("Deleting tables...");for(let m of r)l.message(`Deleting ${m}...`),await n.send(new Me({TableName:m}));l.stop("All selected tables deleted."),L("Done")}catch(t){console.error("Error dropping tables:",t),process.exit(1)}}var h=new Re;h.name("mizzle").description("Mizzle Migration CLI").version("0.0.1");h.command("init").description("Initialize Mizzle configuration").action(async()=>{try{await G()}catch(e){let n=e instanceof Error?e.message:String(e);b.log.error(n),process.exit(1)}});h.command("generate").description("Generate a new migration snapshot and script").option("-n, --name <name>","Migration name").action(async e=>{try{let n=await N();await F({config:n,name:e.name})}catch(n){let t=n instanceof Error?n.message:String(n);b.log.error(t),process.exit(1)}});h.command("push").description("Directly apply schema changes to the target DynamoDB environment").option("-y, --yes","Skip confirmation").action(async e=>{try{let n=await N();await V({config:n,force:e.yes})}catch(n){let t=n instanceof Error?n.message:String(n);b.log.error(t),process.exit(1)}});h.command("list").description("List all existing DynamoDB tables in the environment").action(async()=>{try{let e=await N();await W({config:e})}catch(e){let n=e instanceof Error?e.message:String(e);b.log.error(n),process.exit(1)}});h.command("drop").description("Interactive command to select and delete DynamoDB tables").action(async()=>{try{let e=await N();await X({config:e})}catch(e){let n=e instanceof Error?e.message:String(e);b.log.error(n),process.exit(1)}});h.parse();
|
package/dist/index.js
CHANGED
|
@@ -1,23 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
3
|
-
`),t.unshift(`// Drop Table: ${o.table.TableName}`),t.unshift(`await db.deleteTable("${o.table.TableName}");
|
|
4
|
-
`)):o.type==="delete"?(n.push(`// Drop Table: ${o.tableName}`),n.push(`await db.deleteTable("${o.tableName}");
|
|
5
|
-
`),t.unshift(`// Create Table: ${o.tableName}`),t.unshift(`// TODO: Restore table definition for rollback
|
|
6
|
-
`)):o.type==="update"&&(n.push(`// Update Table: ${o.tableName}`),t.unshift(`// Revert Update Table: ${o.tableName}`));return`import { Mizzle } from "@auri/mizzle";
|
|
7
|
-
|
|
8
|
-
export async function up(db: Mizzle) {
|
|
9
|
-
${n.join(" ")}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export async function down(db: Mizzle) {
|
|
13
|
-
${t.join(" ")}
|
|
14
|
-
}
|
|
15
|
-
`}import{existsSync as xe,writeFileSync as we}from"fs";import{join as Ie}from"path";import{intro as Ae,outro as Ce,text as A,isCancel as C,cancel as z}from"@clack/prompts";async function G(){let e=Ie(process.cwd(),"mizzle.config.ts");if(xe(e)){console.log("mizzle.config.ts already exists in the current directory. Aborting.");return}Ae("Mizzle Initialization");let n=await A({message:"Where is your schema file or directory located?",placeholder:"./src/schema.ts",initialValue:"./src/schema.ts",validate:r=>{if(!r)return"Schema path is required"}});if(C(n)){z("Operation cancelled.");return}let t=await A({message:"Where should Mizzle store migrations and snapshots?",placeholder:"./migrations",initialValue:"./migrations",validate:r=>{if(!r)return"Output directory is required"}});if(C(t)){z("Operation cancelled.");return}let o=await A({message:"Which AWS region do you want to use?",placeholder:"us-east-1",initialValue:"us-east-1"});if(C(o)){z("Operation cancelled.");return}let a=await A({message:"Do you want to use a custom endpoint (e.g., for local development)?",placeholder:"http://localhost:8000 (optional)"});if(C(a)){z("Operation cancelled.");return}let i=`import { defineConfig } from "@auri/mizzle";
|
|
16
|
-
|
|
17
|
-
export default defineConfig({
|
|
18
|
-
schema: "${n}",
|
|
19
|
-
out: "${t}",
|
|
20
|
-
region: "${o}",
|
|
21
|
-
${a?`endpoint: "${a}",`:'// endpoint: "http://localhost:8000",'}
|
|
22
|
-
});
|
|
23
|
-
`;we(e,i),Ce("mizzle.config.ts created successfully!")}import{ListTablesCommand as ze,DescribeTableCommand as De}from"@aws-sdk/client-dynamodb";async function D(e){let n={},t,o=[];do{let a=await e.send(new ze({ExclusiveStartTableName:t}));a.TableNames&&o.push(...a.TableNames),t=a.LastEvaluatedTableName}while(t);for(let a of o)try{let i=await e.send(new De({TableName:a}));if(i.Table){let r=Le(i.Table);n[a]=r}}catch(i){console.warn(`Failed to describe table ${a}:`,i)}return{version:"remote",tables:n}}function Le(e){let n={TableName:e.TableName,AttributeDefinitions:e.AttributeDefinitions?.map(t=>({AttributeName:t.AttributeName,AttributeType:t.AttributeType})).sort((t,o)=>t.AttributeName.localeCompare(o.AttributeName))||[],KeySchema:e.KeySchema?.map(t=>({AttributeName:t.AttributeName,KeyType:t.KeyType}))||[]};return e.GlobalSecondaryIndexes&&e.GlobalSecondaryIndexes.length>0&&(n.GlobalSecondaryIndexes=e.GlobalSecondaryIndexes.map(t=>({IndexName:t.IndexName,KeySchema:t.KeySchema?.map(o=>({AttributeName:o.AttributeName,KeyType:o.KeyType})),Projection:t.Projection?{ProjectionType:t.Projection.ProjectionType}:void 0})).sort((t,o)=>t.IndexName.localeCompare(o.IndexName))),e.LocalSecondaryIndexes&&e.LocalSecondaryIndexes.length>0&&(n.LocalSecondaryIndexes=e.LocalSecondaryIndexes.map(t=>({IndexName:t.IndexName,KeySchema:t.KeySchema?.map(o=>({AttributeName:o.AttributeName,KeyType:o.KeyType})),Projection:t.Projection?{ProjectionType:t.Projection.ProjectionType}:void 0})).sort((t,o)=>t.IndexName.localeCompare(o.IndexName))),n}import{CreateTableCommand as ve}from"@aws-sdk/client-dynamodb";import{confirm as Oe,isCancel as Me,cancel as _e,intro as Ke,outro as H,spinner as ke}from"@clack/prompts";async function Z(e){Ke("Mizzle Push");let{config:n,force:t}=e,o=e.discoverSchema||w,a=e.client||h(n);try{let i=await o(n),r=await D(a),s=I(i,r);if(s.length===0){H("Remote is up to date.");return}console.log(`Pushing ${s.length} changes to remote...`);let l=t;if(l||(l=await Oe({message:"Do you want to apply these changes?"})),Me(l)||!l){_e("Operation cancelled.");return}let m=ke();m.start("Pushing changes...");for(let c of s)c.type==="create"?(m.message(`Creating table: ${c.table.TableName}`),await a.send(new ve({TableName:c.table.TableName,AttributeDefinitions:c.table.AttributeDefinitions,KeySchema:c.table.KeySchema,GlobalSecondaryIndexes:c.table.GlobalSecondaryIndexes,LocalSecondaryIndexes:c.table.LocalSecondaryIndexes,BillingMode:"PAY_PER_REQUEST"}))):c.type==="delete"?console.log(`Untracked table found: ${c.tableName} (Skipping deletion)`):c.type==="update"&&m.message(`Updating table: ${c.tableName} (Not fully implemented)`);m.stop("Push complete."),H("Done")}catch(i){console.error("Error pushing changes:",i),process.exit(1)}}import"@aws-sdk/client-dynamodb";import{intro as Pe,outro as V,spinner as Ye}from"@clack/prompts";async function W(e){Pe("Mizzle List Tables");let n=e.client||h(e.config),t=Ye();t.start("Fetching remote tables...");try{let o=await D(n);t.stop("Fetched remote tables.");let a=Object.values(o.tables);if(a.length===0){console.log("No tables found in the remote environment."),V("Done");return}console.log(`Found ${a.length} tables:`);for(let i of a){console.log(`- ${i.TableName}`);let r=i.KeySchema.find(l=>l.KeyType==="HASH")?.AttributeName,s=i.KeySchema.find(l=>l.KeyType==="RANGE")?.AttributeName;console.log(` PK: ${r}, SK: ${s||"(none)"}`),i.GlobalSecondaryIndexes&&i.GlobalSecondaryIndexes.length>0&&console.log(` GSIs: ${i.GlobalSecondaryIndexes.map(l=>l.IndexName).join(", ")}`)}V("Done")}catch(o){t.stop("Failed to fetch tables."),console.error("Error listing tables:",o),process.exit(1)}}import{ListTablesCommand as Re,DeleteTableCommand as Be}from"@aws-sdk/client-dynamodb";import{intro as $e,outro as L,multiselect as je,confirm as Ue,isCancel as q,cancel as Fe,spinner as Ge}from"@clack/prompts";async function J(e){$e("Mizzle Drop Tables");let n=e.client||h(e.config);try{let t=new Re({}),a=(await n.send(t)).TableNames||[];if(a.length===0){console.log("No tables found in the remote environment."),L("Done");return}let i=await je({message:"Select tables to DELETE (This action is irreversible!)",options:a.map(m=>({value:m,label:m}))});if(q(i)){Fe("Operation cancelled.");return}let r=i;if(r.length===0){console.log("No tables selected."),L("Done");return}let s=await Ue({message:`Are you SURE you want to delete ${r.length} table(s)?`});if(q(s)||!s){console.log("Operation cancelled."),L("Done");return}let l=Ge();l.start("Deleting tables...");for(let m of r)l.message(`Deleting ${m}...`),await n.send(new Be({TableName:m}));l.stop("All selected tables deleted."),L("Done")}catch(t){console.error("Error dropping tables:",t),process.exit(1)}}var g=new He;g.name("mizzle").description("Mizzle Migration CLI").version("0.0.1");g.command("init").description("Initialize Mizzle configuration").action(async()=>{try{await G()}catch(e){let n=e instanceof Error?e.message:String(e);b.log.error(n),process.exit(1)}});g.command("generate").description("Generate a new migration snapshot and script").option("-n, --name <name>","Migration name").action(async e=>{try{let n=await N();await F({config:n,name:e.name})}catch(n){let t=n instanceof Error?n.message:String(n);b.log.error(t),process.exit(1)}});g.command("push").description("Directly apply schema changes to the target DynamoDB environment").option("-y, --yes","Skip confirmation").action(async e=>{try{let n=await N();await Z({config:n,force:e.yes})}catch(n){let t=n instanceof Error?n.message:String(n);b.log.error(t),process.exit(1)}});g.command("list").description("List all existing DynamoDB tables in the environment").action(async()=>{try{let e=await N();await W({config:e})}catch(e){let n=e instanceof Error?e.message:String(e);b.log.error(n),process.exit(1)}});g.command("drop").description("Interactive command to select and delete DynamoDB tables").action(async()=>{try{let e=await N();await J({config:e})}catch(e){let n=e instanceof Error?e.message:String(e);b.log.error(n),process.exit(1)}});g.parse();
|
|
2
|
+
import{a as e}from"./chunk-SNI5EXF5.js";export{e as defineConfig};
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aurios/mizzling",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"mizzling": "./dist/
|
|
7
|
+
"mizzling": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/index.js"
|
|
8
11
|
},
|
|
9
12
|
"author": {
|
|
10
13
|
"name": "Lucas",
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
import { loadConfig } from "./config";
|
|
4
|
+
import { generateCommand } from "./commands/generate";
|
|
5
|
+
import { initCommand } from "./commands/init";
|
|
6
|
+
import { pushCommand } from "./commands/push";
|
|
7
|
+
import { listCommand } from "./commands/list";
|
|
8
|
+
import { dropCommand } from "./commands/drop";
|
|
9
|
+
|
|
10
|
+
const program = new Command();
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.name("mizzle")
|
|
14
|
+
.description("Mizzle Migration CLI")
|
|
15
|
+
.version("0.0.1");
|
|
16
|
+
|
|
17
|
+
program
|
|
18
|
+
.command("init")
|
|
19
|
+
.description("Initialize Mizzle configuration")
|
|
20
|
+
.action(async () => {
|
|
21
|
+
try {
|
|
22
|
+
await initCommand();
|
|
23
|
+
} catch (e) {
|
|
24
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
25
|
+
p.log.error(message);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
program
|
|
31
|
+
.command("generate")
|
|
32
|
+
.description("Generate a new migration snapshot and script")
|
|
33
|
+
.option("-n, --name <name>", "Migration name")
|
|
34
|
+
.action(async (options) => {
|
|
35
|
+
try {
|
|
36
|
+
const config = await loadConfig();
|
|
37
|
+
await generateCommand({ config, name: options.name });
|
|
38
|
+
} catch (e) {
|
|
39
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
40
|
+
p.log.error(message);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
program
|
|
46
|
+
.command("push")
|
|
47
|
+
.description("Directly apply schema changes to the target DynamoDB environment")
|
|
48
|
+
.option("-y, --yes", "Skip confirmation")
|
|
49
|
+
.action(async (options) => {
|
|
50
|
+
try {
|
|
51
|
+
const config = await loadConfig();
|
|
52
|
+
await pushCommand({ config, force: options.yes });
|
|
53
|
+
} catch (e) {
|
|
54
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
55
|
+
p.log.error(message);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
program
|
|
61
|
+
.command("list")
|
|
62
|
+
.description("List all existing DynamoDB tables in the environment")
|
|
63
|
+
.action(async () => {
|
|
64
|
+
try {
|
|
65
|
+
const config = await loadConfig();
|
|
66
|
+
await listCommand({ config });
|
|
67
|
+
} catch (e) {
|
|
68
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
69
|
+
p.log.error(message);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
program
|
|
75
|
+
.command("drop")
|
|
76
|
+
.description("Interactive command to select and delete DynamoDB tables")
|
|
77
|
+
.action(async () => {
|
|
78
|
+
try {
|
|
79
|
+
const config = await loadConfig();
|
|
80
|
+
await dropCommand({ config });
|
|
81
|
+
} catch (e) {
|
|
82
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
83
|
+
p.log.error(message);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
program.parse();
|
package/src/commands/push.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type MizzleConfig, getClient } from "../config";
|
|
|
2
2
|
import { discoverSchema } from "../discovery";
|
|
3
3
|
import { compareSchema } from "@aurios/mizzle/diff";
|
|
4
4
|
import { getRemoteSnapshot } from "@aurios/mizzle/introspection";
|
|
5
|
-
import { DynamoDBClient, CreateTableCommand
|
|
5
|
+
import { DynamoDBClient, CreateTableCommand } from "@aws-sdk/client-dynamodb";
|
|
6
6
|
import { confirm, isCancel, cancel, intro, outro, spinner } from "@clack/prompts";
|
|
7
7
|
|
|
8
8
|
interface PushOptions {
|
package/src/config.ts
CHANGED
|
@@ -54,10 +54,31 @@ export interface MizzleConfig {
|
|
|
54
54
|
* Maximum number of retry attempts for DynamoDB requests.
|
|
55
55
|
*/
|
|
56
56
|
maxAttempts?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Print all SQL statements (or DynamoDB commands) and their execution time.
|
|
59
|
+
*/
|
|
60
|
+
verbose?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Require user confirmation before pushing any changes to the database.
|
|
63
|
+
*/
|
|
64
|
+
strict?: boolean;
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
/**
|
|
60
|
-
* Helper function to define the configuration with type safety.
|
|
68
|
+
* Helper function to define the Mizzle CLI configuration with type safety and autocompletion.
|
|
69
|
+
*
|
|
70
|
+
* Typically used in a `mizzle.config.ts` file at the root of your project.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* import { defineConfig } from "@aurios/mizzling";
|
|
75
|
+
*
|
|
76
|
+
* export default defineConfig({
|
|
77
|
+
* schema: "./src/schema.ts",
|
|
78
|
+
* out: "./mizzle",
|
|
79
|
+
* region: "us-east-1",
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
61
82
|
*
|
|
62
83
|
* @param config The Mizzle configuration object.
|
|
63
84
|
* @returns The same configuration object, validated by TypeScript.
|
|
@@ -151,6 +172,8 @@ export async function loadConfig(configName = "mizzle.config.ts"): Promise<Mizzl
|
|
|
151
172
|
if (process.env.MIZZLE_ENDPOINT) finalConfig.endpoint = process.env.MIZZLE_ENDPOINT;
|
|
152
173
|
if (process.env.MIZZLE_SCHEMA) finalConfig.schema = process.env.MIZZLE_SCHEMA;
|
|
153
174
|
if (process.env.MIZZLE_OUT) finalConfig.out = process.env.MIZZLE_OUT;
|
|
175
|
+
if (process.env.MIZZLE_VERBOSE) finalConfig.verbose = process.env.MIZZLE_VERBOSE === "true";
|
|
176
|
+
if (process.env.MIZZLE_STRICT) finalConfig.strict = process.env.MIZZLE_STRICT === "true";
|
|
154
177
|
|
|
155
178
|
return finalConfig;
|
|
156
179
|
} catch (error) {
|
package/src/index.ts
CHANGED
|
@@ -1,88 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import * as p from "@clack/prompts";
|
|
3
|
-
import { loadConfig } from "./config";
|
|
4
|
-
import { generateCommand } from "./commands/generate";
|
|
5
|
-
import { initCommand } from "./commands/init";
|
|
6
|
-
import { pushCommand } from "./commands/push";
|
|
7
|
-
import { listCommand } from "./commands/list";
|
|
8
|
-
import { dropCommand } from "./commands/drop";
|
|
9
|
-
|
|
10
|
-
const program = new Command();
|
|
11
|
-
|
|
12
|
-
program
|
|
13
|
-
.name("mizzle")
|
|
14
|
-
.description("Mizzle Migration CLI")
|
|
15
|
-
.version("0.0.1");
|
|
16
|
-
|
|
17
|
-
program
|
|
18
|
-
.command("init")
|
|
19
|
-
.description("Initialize Mizzle configuration")
|
|
20
|
-
.action(async () => {
|
|
21
|
-
try {
|
|
22
|
-
await initCommand();
|
|
23
|
-
} catch (e) {
|
|
24
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
25
|
-
p.log.error(message);
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
program
|
|
31
|
-
.command("generate")
|
|
32
|
-
.description("Generate a new migration snapshot and script")
|
|
33
|
-
.option("-n, --name <name>", "Migration name")
|
|
34
|
-
.action(async (options) => {
|
|
35
|
-
try {
|
|
36
|
-
const config = await loadConfig();
|
|
37
|
-
await generateCommand({ config, name: options.name });
|
|
38
|
-
} catch (e) {
|
|
39
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
40
|
-
p.log.error(message);
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
program
|
|
46
|
-
.command("push")
|
|
47
|
-
.description("Directly apply schema changes to the target DynamoDB environment")
|
|
48
|
-
.option("-y, --yes", "Skip confirmation")
|
|
49
|
-
.action(async (options) => {
|
|
50
|
-
try {
|
|
51
|
-
const config = await loadConfig();
|
|
52
|
-
await pushCommand({ config, force: options.yes });
|
|
53
|
-
} catch (e) {
|
|
54
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
55
|
-
p.log.error(message);
|
|
56
|
-
process.exit(1);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
program
|
|
61
|
-
.command("list")
|
|
62
|
-
.description("List all existing DynamoDB tables in the environment")
|
|
63
|
-
.action(async () => {
|
|
64
|
-
try {
|
|
65
|
-
const config = await loadConfig();
|
|
66
|
-
await listCommand({ config });
|
|
67
|
-
} catch (e) {
|
|
68
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
69
|
-
p.log.error(message);
|
|
70
|
-
process.exit(1);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
program
|
|
75
|
-
.command("drop")
|
|
76
|
-
.description("Interactive command to select and delete DynamoDB tables")
|
|
77
|
-
.action(async () => {
|
|
78
|
-
try {
|
|
79
|
-
const config = await loadConfig();
|
|
80
|
-
await dropCommand({ config });
|
|
81
|
-
} catch (e) {
|
|
82
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
83
|
-
p.log.error(message);
|
|
84
|
-
process.exit(1);
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
program.parse();
|
|
1
|
+
export { defineConfig, type MizzleConfig } from "./config";
|