@gettersethya/mira-collection 0.1.0-alpha.2 → 0.1.0-alpha.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.
Files changed (2) hide show
  1. package/README.md +164 -0
  2. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # @gettersethya/mira-collection
2
+
3
+ > **Early pre-alpha.** Breaking changes may occur without notice.
4
+
5
+ Collection definitions, filter DSL, and access rule builder for [Mira](https://github.com/gettersethya/mira). Shared between server and client — isomorphic, no runtime dependencies beyond `effect`.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @gettersethya/mira-collection effect
11
+ # or
12
+ pnpm add @gettersethya/mira-collection effect
13
+ ```
14
+
15
+ ## Collection types
16
+
17
+ ### Base collection
18
+
19
+ Standard CRUD collection. System fields `id`, `seqId`, `created`, and `updated` are added automatically.
20
+
21
+ ```typescript
22
+ import { BaseCollection, Bytes, Field, Rule } from "@gettersethya/mira-collection"
23
+
24
+ const Posts = BaseCollection.define("posts", {
25
+ title: Field.text({ maxLength: 200 }),
26
+ slug: Field.text({ unique: true }),
27
+ content: Field.text(),
28
+ published: Field.boolean({ default: false }),
29
+ authorId: Field.relation(Users),
30
+ thumbnail: Field.file({ maxSize: Bytes.fromMB(5), mimeTypes: ["image/*"] }),
31
+ })
32
+ .indexes((I) => [
33
+ I.on("authorId"),
34
+ I.unique("slug"),
35
+ ])
36
+ .rules((R) => ({
37
+ list: R.field("published").eq(R.literal(true)),
38
+ view: Rule.or(R.field("published").eq(R.literal(true)), R.field("authorId").eq(R.authId(Users))),
39
+ create: R.authId(Users).neq(R.literal(null)),
40
+ update: R.field("authorId").eq(R.authId(Users)),
41
+ delete: R.field("authorId").eq(R.authId(Users)),
42
+ }))
43
+ ```
44
+
45
+ ### Auth collection
46
+
47
+ Adds `email`, `password` (hashed), and `emailVerified` system fields. Exposes an `authWithPassword` endpoint.
48
+
49
+ ```typescript
50
+ import { AuthCollection, Field, Rule } from "@gettersethya/mira-collection"
51
+
52
+ const Users = AuthCollection.define("users", {
53
+ displayName: Field.text(),
54
+ username: Field.text({ unique: true }),
55
+ role: Field.text({ default: "user" }),
56
+ })
57
+ .rules((R) => ({
58
+ list: Rule.public(),
59
+ view: Rule.public(),
60
+ create: Rule.public(),
61
+ update: R.selfId().eq(R.authId(Users)), // users can only edit themselves
62
+ }))
63
+ ```
64
+
65
+ ### View collection
66
+
67
+ Read-only, backed by a SQL `VIEW`. Supports `list` and `view` only. Every field must be marked `.view()`.
68
+
69
+ ```typescript
70
+ import { Field, Rule, ViewCollection } from "@gettersethya/mira-collection"
71
+
72
+ const PostsWithAuthors = ViewCollection.define(
73
+ "posts_with_authors",
74
+ `SELECT p.id, p.seqId, p.title, u.displayName AS authorName
75
+ FROM posts p LEFT JOIN users u ON p.authorId = u.id`,
76
+ {
77
+ id: Field.text().view(),
78
+ seqId: Field.integer().view(),
79
+ title: Field.text().view(),
80
+ authorName: Field.text().view(),
81
+ }
82
+ )
83
+ .rules((R) => ({ list: Rule.public(), view: Rule.public() }))
84
+ ```
85
+
86
+ ## Field types
87
+
88
+ ```typescript
89
+ Field.text({ minLength?, maxLength?, unique?, indexed?, required?, default? })
90
+ Field.email()
91
+ Field.integer({ min?, max?, unique?, indexed?, default? })
92
+ Field.number({ min?, max? })
93
+ Field.boolean({ default? })
94
+ Field.date()
95
+ Field.json()
96
+ Field.file({ maxSize?, mimeTypes?, protected? })
97
+ Field.relation(Collection)
98
+
99
+ // File size helpers
100
+ Bytes.fromKB(n)
101
+ Bytes.fromMB(n)
102
+ Bytes.fromGB(n)
103
+ ```
104
+
105
+ ## Indexes
106
+
107
+ ```typescript
108
+ // Field-level (single column)
109
+ Field.text({ unique: true }) // unique index
110
+ Field.text({ indexed: true }) // non-unique index
111
+
112
+ // Callback (composite or explicit)
113
+ .indexes((I) => [
114
+ I.on("authorId"), // non-unique
115
+ I.on("authorId", "published"), // composite
116
+ I.unique("slug"), // unique constraint
117
+ I.unique("teamId", "userId"), // composite unique
118
+ ])
119
+ ```
120
+
121
+ ## Rules
122
+
123
+ Rules are evaluated server-side on every request. A missing key means **deny all** for that action.
124
+
125
+ ```typescript
126
+ Rule.public() // allow all
127
+ R.authId(Users).neq(R.literal(null)) // logged-in users only
128
+ R.field("ownerId").eq(R.authId(Users)) // owner-only
129
+ R.field("role").in(R.literal(["admin", "mod"])) // role check
130
+ R.auth(Users, "role").eq(R.literal("admin")) // check a field on the auth record
131
+ Rule.not(R.field("archived").eq(R.literal(true))) // negation
132
+ Rule.or(R.field("isPublic").eq(R.literal(true)), R.field("ownerId").eq(R.authId(Users)))
133
+ Rule.and(R.field("published").eq(R.literal(true)), R.field("ownerId").eq(R.authId(Users)))
134
+
135
+ // Date arithmetic
136
+ R.field("created").gte(Rule.dateAdd(Rule.now(), -30, "day"))
137
+
138
+ // Request values (header, query param, or body field)
139
+ Rule.request("header", "x-api-key").eq(R.literal("secret"))
140
+
141
+ // Subquery membership check
142
+ Rule.subquery(Members, "teamId").where(R.field("userId").eq(R.authId(Users)))
143
+ ```
144
+
145
+ ## Filters
146
+
147
+ Used in client queries. Type-checked against the collection's field types.
148
+
149
+ ```typescript
150
+ f.field("published").eq(true)
151
+ f.field("viewCount").gte(100)
152
+ f.field("status").in(["draft", "published"])
153
+ f.field("title").like("%effect%")
154
+ f.field("deletedAt").null()
155
+ f.field("price").between(10, 100)
156
+
157
+ f.and(f.field("published").eq(true), f.field("viewCount").gte(100))
158
+ f.or(f.field("category").eq("tech"), f.field("category").eq("science"))
159
+ f.not(f.field("archived").eq(true))
160
+ ```
161
+
162
+ ## More
163
+
164
+ See the [Mira root README](https://github.com/gettersethya/mira) for full documentation.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gettersethya/mira-collection",
3
- "version": "0.1.0-alpha.2",
3
+ "version": "0.1.0-alpha.3",
4
4
  "type": "module",
5
5
  "description": "Collection definitions, filter DSL, and rule builder for Mira",
6
6
  "author": "Getter Sethya",