@donkeylabs/cli 1.1.16 → 1.1.18
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/package.json +1 -1
- package/src/commands/generate.ts +153 -3
- package/templates/sveltekit-app/package.json +3 -3
- package/templates/sveltekit-app/src/lib/permissions.ts +213 -0
- package/templates/sveltekit-app/src/routes/+page.server.ts +1 -1
- package/templates/sveltekit-app/src/routes/workflows/+page.server.ts +1 -1
- package/templates/sveltekit-app/src/server/index.ts +46 -1
- package/templates/sveltekit-app/src/server/plugins/auth/auth.test.ts +377 -0
- package/templates/sveltekit-app/src/server/plugins/auth/index.ts +7 -7
- package/templates/sveltekit-app/src/server/plugins/auth/schema.ts +65 -0
- package/templates/sveltekit-app/src/server/plugins/email/email.test.ts +369 -0
- package/templates/sveltekit-app/src/server/plugins/email/schema.ts +24 -0
- package/templates/sveltekit-app/src/server/plugins/permissions/index.ts +1048 -0
- package/templates/sveltekit-app/src/server/plugins/permissions/migrations/001_create_tenants.ts +63 -0
- package/templates/sveltekit-app/src/server/plugins/permissions/migrations/002_create_roles.ts +90 -0
- package/templates/sveltekit-app/src/server/plugins/permissions/migrations/003_create_resource_grants.ts +50 -0
- package/templates/sveltekit-app/src/server/plugins/permissions/permissions.test.ts +566 -0
- package/templates/sveltekit-app/src/server/plugins/permissions/schema.ts +67 -0
- package/templates/sveltekit-app/src/server/plugins/workflow-demo/index.ts +3 -2
- package/templates/sveltekit-app/src/server/routes/auth/handlers/login.handler.ts +4 -6
- package/templates/sveltekit-app/src/server/routes/auth/handlers/logout.handler.ts +5 -8
- package/templates/sveltekit-app/src/server/routes/auth/handlers/me.handler.ts +4 -7
- package/templates/sveltekit-app/src/server/routes/auth/handlers/refresh.handler.ts +4 -6
- package/templates/sveltekit-app/src/server/routes/auth/handlers/register.handler.ts +4 -6
- package/templates/sveltekit-app/src/server/routes/auth/handlers/update-profile.handler.ts +5 -8
- package/templates/sveltekit-app/src/server/routes/auth/index.ts +6 -7
- package/templates/sveltekit-app/src/server/routes/example/handlers/greet.handler.ts +3 -5
- package/templates/sveltekit-app/src/server/routes/permissions/index.ts +248 -0
- package/templates/sveltekit-app/src/server/routes/tenants/index.ts +339 -0
package/templates/sveltekit-app/src/server/plugins/permissions/migrations/001_create_tenants.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
export async function up(db: Kysely<any>): Promise<void> {
|
|
4
|
+
// Tenants table
|
|
5
|
+
await db.schema
|
|
6
|
+
.createTable("tenants")
|
|
7
|
+
.ifNotExists()
|
|
8
|
+
.addColumn("id", "text", (col) => col.primaryKey())
|
|
9
|
+
.addColumn("name", "text", (col) => col.notNull())
|
|
10
|
+
.addColumn("slug", "text", (col) => col.notNull().unique())
|
|
11
|
+
.addColumn("settings", "text") // JSON
|
|
12
|
+
.addColumn("created_at", "text", (col) => col.notNull().defaultTo("CURRENT_TIMESTAMP"))
|
|
13
|
+
.addColumn("updated_at", "text", (col) => col.notNull())
|
|
14
|
+
.execute();
|
|
15
|
+
|
|
16
|
+
await db.schema
|
|
17
|
+
.createIndex("idx_tenants_slug")
|
|
18
|
+
.ifNotExists()
|
|
19
|
+
.on("tenants")
|
|
20
|
+
.column("slug")
|
|
21
|
+
.execute();
|
|
22
|
+
|
|
23
|
+
// Tenant members table
|
|
24
|
+
await db.schema
|
|
25
|
+
.createTable("tenant_members")
|
|
26
|
+
.ifNotExists()
|
|
27
|
+
.addColumn("id", "text", (col) => col.primaryKey())
|
|
28
|
+
.addColumn("tenant_id", "text", (col) =>
|
|
29
|
+
col.notNull().references("tenants.id").onDelete("cascade")
|
|
30
|
+
)
|
|
31
|
+
.addColumn("user_id", "text", (col) =>
|
|
32
|
+
col.notNull().references("users.id").onDelete("cascade")
|
|
33
|
+
)
|
|
34
|
+
.addColumn("created_at", "text", (col) => col.notNull().defaultTo("CURRENT_TIMESTAMP"))
|
|
35
|
+
.execute();
|
|
36
|
+
|
|
37
|
+
await db.schema
|
|
38
|
+
.createIndex("idx_tenant_members_tenant_id")
|
|
39
|
+
.ifNotExists()
|
|
40
|
+
.on("tenant_members")
|
|
41
|
+
.column("tenant_id")
|
|
42
|
+
.execute();
|
|
43
|
+
|
|
44
|
+
await db.schema
|
|
45
|
+
.createIndex("idx_tenant_members_user_id")
|
|
46
|
+
.ifNotExists()
|
|
47
|
+
.on("tenant_members")
|
|
48
|
+
.column("user_id")
|
|
49
|
+
.execute();
|
|
50
|
+
|
|
51
|
+
await db.schema
|
|
52
|
+
.createIndex("idx_tenant_members_unique")
|
|
53
|
+
.ifNotExists()
|
|
54
|
+
.on("tenant_members")
|
|
55
|
+
.columns(["tenant_id", "user_id"])
|
|
56
|
+
.unique()
|
|
57
|
+
.execute();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function down(db: Kysely<any>): Promise<void> {
|
|
61
|
+
await db.schema.dropTable("tenant_members").ifExists().execute();
|
|
62
|
+
await db.schema.dropTable("tenants").ifExists().execute();
|
|
63
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
export async function up(db: Kysely<any>): Promise<void> {
|
|
4
|
+
// Roles table
|
|
5
|
+
await db.schema
|
|
6
|
+
.createTable("roles")
|
|
7
|
+
.ifNotExists()
|
|
8
|
+
.addColumn("id", "text", (col) => col.primaryKey())
|
|
9
|
+
.addColumn("tenant_id", "text", (col) =>
|
|
10
|
+
col.references("tenants.id").onDelete("cascade")
|
|
11
|
+
) // null = global role
|
|
12
|
+
.addColumn("name", "text", (col) => col.notNull())
|
|
13
|
+
.addColumn("description", "text")
|
|
14
|
+
.addColumn("permissions", "text", (col) => col.notNull().defaultTo("[]")) // JSON array
|
|
15
|
+
.addColumn("inherits_from", "text", (col) =>
|
|
16
|
+
col.references("roles.id").onDelete("set null")
|
|
17
|
+
)
|
|
18
|
+
.addColumn("is_default", "integer", (col) => col.notNull().defaultTo(0))
|
|
19
|
+
.addColumn("created_at", "text", (col) => col.notNull().defaultTo("CURRENT_TIMESTAMP"))
|
|
20
|
+
.addColumn("updated_at", "text", (col) => col.notNull())
|
|
21
|
+
.execute();
|
|
22
|
+
|
|
23
|
+
await db.schema
|
|
24
|
+
.createIndex("idx_roles_tenant_id")
|
|
25
|
+
.ifNotExists()
|
|
26
|
+
.on("roles")
|
|
27
|
+
.column("tenant_id")
|
|
28
|
+
.execute();
|
|
29
|
+
|
|
30
|
+
await db.schema
|
|
31
|
+
.createIndex("idx_roles_name_tenant")
|
|
32
|
+
.ifNotExists()
|
|
33
|
+
.on("roles")
|
|
34
|
+
.columns(["tenant_id", "name"])
|
|
35
|
+
.execute();
|
|
36
|
+
|
|
37
|
+
// User roles table
|
|
38
|
+
await db.schema
|
|
39
|
+
.createTable("user_roles")
|
|
40
|
+
.ifNotExists()
|
|
41
|
+
.addColumn("id", "text", (col) => col.primaryKey())
|
|
42
|
+
.addColumn("user_id", "text", (col) =>
|
|
43
|
+
col.notNull().references("users.id").onDelete("cascade")
|
|
44
|
+
)
|
|
45
|
+
.addColumn("role_id", "text", (col) =>
|
|
46
|
+
col.notNull().references("roles.id").onDelete("cascade")
|
|
47
|
+
)
|
|
48
|
+
.addColumn("tenant_id", "text", (col) =>
|
|
49
|
+
col.notNull().references("tenants.id").onDelete("cascade")
|
|
50
|
+
)
|
|
51
|
+
.addColumn("assigned_by", "text", (col) =>
|
|
52
|
+
col.references("users.id").onDelete("set null")
|
|
53
|
+
)
|
|
54
|
+
.addColumn("created_at", "text", (col) => col.notNull().defaultTo("CURRENT_TIMESTAMP"))
|
|
55
|
+
.execute();
|
|
56
|
+
|
|
57
|
+
await db.schema
|
|
58
|
+
.createIndex("idx_user_roles_user_id")
|
|
59
|
+
.ifNotExists()
|
|
60
|
+
.on("user_roles")
|
|
61
|
+
.column("user_id")
|
|
62
|
+
.execute();
|
|
63
|
+
|
|
64
|
+
await db.schema
|
|
65
|
+
.createIndex("idx_user_roles_role_id")
|
|
66
|
+
.ifNotExists()
|
|
67
|
+
.on("user_roles")
|
|
68
|
+
.column("role_id")
|
|
69
|
+
.execute();
|
|
70
|
+
|
|
71
|
+
await db.schema
|
|
72
|
+
.createIndex("idx_user_roles_tenant_id")
|
|
73
|
+
.ifNotExists()
|
|
74
|
+
.on("user_roles")
|
|
75
|
+
.column("tenant_id")
|
|
76
|
+
.execute();
|
|
77
|
+
|
|
78
|
+
await db.schema
|
|
79
|
+
.createIndex("idx_user_roles_unique")
|
|
80
|
+
.ifNotExists()
|
|
81
|
+
.on("user_roles")
|
|
82
|
+
.columns(["user_id", "role_id", "tenant_id"])
|
|
83
|
+
.unique()
|
|
84
|
+
.execute();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function down(db: Kysely<any>): Promise<void> {
|
|
88
|
+
await db.schema.dropTable("user_roles").ifExists().execute();
|
|
89
|
+
await db.schema.dropTable("roles").ifExists().execute();
|
|
90
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Kysely } from "kysely";
|
|
2
|
+
|
|
3
|
+
export async function up(db: Kysely<any>): Promise<void> {
|
|
4
|
+
await db.schema
|
|
5
|
+
.createTable("resource_grants")
|
|
6
|
+
.ifNotExists()
|
|
7
|
+
.addColumn("id", "text", (col) => col.primaryKey())
|
|
8
|
+
.addColumn("tenant_id", "text", (col) =>
|
|
9
|
+
col.notNull().references("tenants.id").onDelete("cascade")
|
|
10
|
+
)
|
|
11
|
+
.addColumn("resource_type", "text", (col) => col.notNull())
|
|
12
|
+
.addColumn("resource_id", "text", (col) => col.notNull())
|
|
13
|
+
.addColumn("grantee_type", "text", (col) => col.notNull()) // "user" | "role"
|
|
14
|
+
.addColumn("grantee_id", "text", (col) => col.notNull())
|
|
15
|
+
.addColumn("permissions", "text", (col) => col.notNull().defaultTo("[]")) // JSON array
|
|
16
|
+
.addColumn("granted_by", "text", (col) =>
|
|
17
|
+
col.references("users.id").onDelete("set null")
|
|
18
|
+
)
|
|
19
|
+
.addColumn("created_at", "text", (col) => col.notNull().defaultTo("CURRENT_TIMESTAMP"))
|
|
20
|
+
.execute();
|
|
21
|
+
|
|
22
|
+
// Index for looking up grants by resource
|
|
23
|
+
await db.schema
|
|
24
|
+
.createIndex("idx_resource_grants_resource")
|
|
25
|
+
.ifNotExists()
|
|
26
|
+
.on("resource_grants")
|
|
27
|
+
.columns(["tenant_id", "resource_type", "resource_id"])
|
|
28
|
+
.execute();
|
|
29
|
+
|
|
30
|
+
// Index for looking up grants by grantee
|
|
31
|
+
await db.schema
|
|
32
|
+
.createIndex("idx_resource_grants_grantee")
|
|
33
|
+
.ifNotExists()
|
|
34
|
+
.on("resource_grants")
|
|
35
|
+
.columns(["tenant_id", "grantee_type", "grantee_id"])
|
|
36
|
+
.execute();
|
|
37
|
+
|
|
38
|
+
// Unique constraint: one grant per resource+grantee combination
|
|
39
|
+
await db.schema
|
|
40
|
+
.createIndex("idx_resource_grants_unique")
|
|
41
|
+
.ifNotExists()
|
|
42
|
+
.on("resource_grants")
|
|
43
|
+
.columns(["tenant_id", "resource_type", "resource_id", "grantee_type", "grantee_id"])
|
|
44
|
+
.unique()
|
|
45
|
+
.execute();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function down(db: Kysely<any>): Promise<void> {
|
|
49
|
+
await db.schema.dropTable("resource_grants").ifExists().execute();
|
|
50
|
+
}
|