@stacksjs/orm 0.75.318 → 0.75.321
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/dist/auto-crud.d.ts +13 -0
- package/dist/auto-crud.js +1 -1
- package/dist/define-model.js +1 -1
- package/dist/models/Activity.ts +1 -0
- package/dist/models/AnalyticsEvent.ts +1 -0
- package/dist/models/AutomationRun.ts +1 -1
- package/dist/models/BoardColumn.ts +0 -1
- package/dist/models/Campaign.ts +1 -1
- package/dist/models/CampaignSend.ts +3 -3
- package/dist/models/Card.ts +0 -1
- package/dist/models/CardComment.ts +0 -2
- package/dist/models/Content/Author.ts +2 -0
- package/dist/models/Content/Categorizable.ts +1 -0
- package/dist/models/Content/Menu.ts +2 -0
- package/dist/models/Content/MenuItem.ts +2 -0
- package/dist/models/Content/PageRevision.ts +2 -0
- package/dist/models/Content/Post.ts +2 -0
- package/dist/models/Content/Redirect.ts +2 -0
- package/dist/models/EmailListSubscriber.ts +2 -2
- package/dist/models/Error.ts +5 -0
- package/dist/models/Forms/Form.ts +2 -0
- package/dist/models/Forms/FormField.ts +2 -0
- package/dist/models/Forms/FormSubmission.ts +2 -0
- package/dist/models/Label.ts +0 -1
- package/dist/models/Log.ts +3 -1
- package/dist/models/MagicLinkToken.ts +0 -7
- package/dist/models/PaymentProduct.ts +1 -0
- package/dist/models/PaymentTransaction.ts +1 -0
- package/dist/models/Release.ts +3 -0
- package/dist/models/Request.ts +1 -0
- package/dist/models/SenderDomain.ts +2 -0
- package/dist/models/SmsOptOut.ts +0 -7
- package/dist/models/Subscription.ts +2 -0
- package/dist/models/commerce/Auction.ts +1 -0
- package/dist/models/commerce/AuctionItem.ts +1 -0
- package/dist/models/commerce/Cart.ts +83 -2
- package/dist/models/commerce/Category.ts +5 -1
- package/dist/models/commerce/Coupon.ts +4 -1
- package/dist/models/commerce/DigitalDelivery.ts +1 -0
- package/dist/models/commerce/GiftCard.ts +1 -0
- package/dist/models/commerce/LoyaltyPoint.ts +1 -0
- package/dist/models/commerce/LoyaltyReward.ts +3 -1
- package/dist/models/commerce/Order.ts +4 -1
- package/dist/models/commerce/OrderItem.ts +1 -0
- package/dist/models/commerce/Payment.ts +1 -0
- package/dist/models/commerce/Product.ts +15 -0
- package/dist/models/commerce/ProductVariant.ts +2 -0
- package/dist/models/commerce/Receipt.ts +1 -0
- package/dist/models/commerce/Review.ts +3 -1
- package/dist/models/commerce/Transaction.ts +1 -0
- package/dist/models/realtime/Websocket.ts +4 -1
- package/dist/native.d.ts +29 -0
- package/dist/native.js +1 -0
- package/package.json +24 -24
package/dist/models/Error.ts
CHANGED
|
@@ -15,6 +15,8 @@ export default defineModel({
|
|
|
15
15
|
],
|
|
16
16
|
|
|
17
17
|
traits: {
|
|
18
|
+
// So a fresh seed fills its dashboard page (stacksjs/stacks#3000).
|
|
19
|
+
useSeeder: { count: 10 },
|
|
18
20
|
useTimestamps: true,
|
|
19
21
|
},
|
|
20
22
|
|
|
@@ -32,6 +34,7 @@ export default defineModel({
|
|
|
32
34
|
|
|
33
35
|
message: {
|
|
34
36
|
fillable: true,
|
|
37
|
+
type: 'text',
|
|
35
38
|
validation: {
|
|
36
39
|
rule: schema.string().required(),
|
|
37
40
|
message: {
|
|
@@ -43,6 +46,7 @@ export default defineModel({
|
|
|
43
46
|
|
|
44
47
|
stack: {
|
|
45
48
|
fillable: true,
|
|
49
|
+
type: 'text',
|
|
46
50
|
validation: {
|
|
47
51
|
rule: schema.string(),
|
|
48
52
|
message: {
|
|
@@ -86,6 +90,7 @@ export default defineModel({
|
|
|
86
90
|
|
|
87
91
|
additional_info: {
|
|
88
92
|
fillable: true,
|
|
93
|
+
type: 'text',
|
|
89
94
|
validation: {
|
|
90
95
|
rule: schema.string(),
|
|
91
96
|
message: {
|
|
@@ -18,6 +18,8 @@ export default defineModel({
|
|
|
18
18
|
autoIncrement: true,
|
|
19
19
|
|
|
20
20
|
traits: {
|
|
21
|
+
// So a fresh seed fills its dashboard page (stacksjs/stacks#3000).
|
|
22
|
+
useSeeder: { count: 10 },
|
|
21
23
|
gdpr: { subject: { email: 'email' }, erasure: 'anonymize', basis: 'consent', purpose: 'Form submissions' },
|
|
22
24
|
useUuid: true,
|
|
23
25
|
useTimestamps: true,
|
package/dist/models/Label.ts
CHANGED
package/dist/models/Log.ts
CHANGED
|
@@ -49,7 +49,9 @@ export default defineModel({
|
|
|
49
49
|
order: 1,
|
|
50
50
|
fillable: true,
|
|
51
51
|
validation: {
|
|
52
|
-
|
|
52
|
+
// Milliseconds since the epoch, so a bigint column, as on Websocket.time
|
|
53
|
+
// (stacksjs/stacks#2996).
|
|
54
|
+
rule: schema.unix().required(),
|
|
53
55
|
message: {
|
|
54
56
|
date: 'Timestamp must be a valid date',
|
|
55
57
|
},
|
|
@@ -15,13 +15,6 @@ export default defineModel({
|
|
|
15
15
|
primaryKey: 'id',
|
|
16
16
|
autoIncrement: true,
|
|
17
17
|
|
|
18
|
-
indexes: [
|
|
19
|
-
{
|
|
20
|
-
name: 'magic_link_tokens_token_unique',
|
|
21
|
-
columns: ['token'],
|
|
22
|
-
unique: true,
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
18
|
|
|
26
19
|
traits: {
|
|
27
20
|
gdpr: { erasure: 'delete', basis: 'contract', purpose: 'Passwordless sign-in links' },
|
package/dist/models/Release.ts
CHANGED
|
@@ -8,6 +8,8 @@ export default defineModel({
|
|
|
8
8
|
autoIncrement: true,
|
|
9
9
|
|
|
10
10
|
traits: {
|
|
11
|
+
// So a fresh seed fills its dashboard page (stacksjs/stacks#3000).
|
|
12
|
+
useSeeder: { count: 5 },
|
|
11
13
|
useUuid: true,
|
|
12
14
|
useTimestamps: true,
|
|
13
15
|
useSearch: {
|
|
@@ -59,6 +61,7 @@ export default defineModel({
|
|
|
59
61
|
notes: {
|
|
60
62
|
order: 4,
|
|
61
63
|
fillable: true,
|
|
64
|
+
type: 'text',
|
|
62
65
|
validation: {
|
|
63
66
|
rule: schema.string(),
|
|
64
67
|
},
|
package/dist/models/Request.ts
CHANGED
|
@@ -6,6 +6,8 @@ export default defineModel({
|
|
|
6
6
|
table: 'sender_domains',
|
|
7
7
|
belongsTo: ['Team'],
|
|
8
8
|
traits: {
|
|
9
|
+
// So a fresh seed fills its dashboard page (stacksjs/stacks#3000).
|
|
10
|
+
useSeeder: { count: 3 },
|
|
9
11
|
useUuid: true,
|
|
10
12
|
useTimestamps: true,
|
|
11
13
|
useApi: { uri: 'sender-domains', routes: ['index', 'store', 'show', 'update', 'destroy'], middleware: ['auth', 'team'] },
|
package/dist/models/SmsOptOut.ts
CHANGED
|
@@ -13,13 +13,6 @@ export default defineModel({
|
|
|
13
13
|
primaryKey: 'id',
|
|
14
14
|
autoIncrement: true,
|
|
15
15
|
|
|
16
|
-
indexes: [
|
|
17
|
-
{
|
|
18
|
-
name: 'sms_opt_outs_phone_unique',
|
|
19
|
-
columns: ['phone'],
|
|
20
|
-
unique: true,
|
|
21
|
-
},
|
|
22
|
-
],
|
|
23
16
|
|
|
24
17
|
traits: {
|
|
25
18
|
gdpr: { erasure: 'keep', basis: 'legal_obligation', purpose: 'Honouring SMS STOP replies, keyed by phone number' },
|
|
@@ -8,6 +8,8 @@ export default defineModel({
|
|
|
8
8
|
autoIncrement: true, // defaults to true
|
|
9
9
|
belongsTo: ['User'],
|
|
10
10
|
traits: {
|
|
11
|
+
// So a fresh seed fills its dashboard page (stacksjs/stacks#3000).
|
|
12
|
+
useSeeder: { count: 10 },
|
|
11
13
|
gdpr: { erasure: 'keep', basis: 'legal_obligation', purpose: 'Billing records' },
|
|
12
14
|
useUuid: true,
|
|
13
15
|
},
|
|
@@ -136,9 +136,90 @@ export default defineModel({
|
|
|
136
136
|
order: 10,
|
|
137
137
|
fillable: true,
|
|
138
138
|
validation: {
|
|
139
|
-
|
|
139
|
+
// Optional: a cart without a coupon is the common case.
|
|
140
|
+
rule: schema.string(),
|
|
141
|
+
},
|
|
142
|
+
// Stored and shown, never resolved: nothing redeems or joins on it yet,
|
|
143
|
+
// so what it holds is left to the feature that does. No factory, so a
|
|
144
|
+
// seed does not invent one (stacksjs/stacks#3002).
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
// The storefront's anonymous cart: the shopper's signed stacks_cart cookie
|
|
148
|
+
// carries this token, checkout records its progress and the address, and
|
|
149
|
+
// the order is placed from them (stacksjs/stacks#3017). A cart made any
|
|
150
|
+
// other way has none of them.
|
|
151
|
+
|
|
152
|
+
/** Bearer for an anonymous cart, so never returned by the API. No factory: a seeded cart is no shopper's. */
|
|
153
|
+
sessionToken: {
|
|
154
|
+
order: 11,
|
|
155
|
+
unique: true,
|
|
156
|
+
hidden: true,
|
|
157
|
+
validation: {
|
|
158
|
+
rule: schema.string().max(255),
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
checkoutStep: {
|
|
163
|
+
default: 'cart',
|
|
164
|
+
order: 12,
|
|
165
|
+
fillable: true,
|
|
166
|
+
validation: {
|
|
167
|
+
rule: schema.enum(['cart', 'shipping', 'payment', 'placed']),
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
email: {
|
|
172
|
+
personal: true,
|
|
173
|
+
order: 13,
|
|
174
|
+
fillable: true,
|
|
175
|
+
validation: {
|
|
176
|
+
rule: schema.string().email().max(255),
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
shippingName: {
|
|
181
|
+
personal: true,
|
|
182
|
+
order: 14,
|
|
183
|
+
fillable: true,
|
|
184
|
+
validation: {
|
|
185
|
+
rule: schema.string().max(255),
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
shippingAddress: {
|
|
190
|
+
personal: true,
|
|
191
|
+
order: 15,
|
|
192
|
+
fillable: true,
|
|
193
|
+
validation: {
|
|
194
|
+
rule: schema.string().max(255),
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
shippingCity: {
|
|
199
|
+
personal: true,
|
|
200
|
+
order: 16,
|
|
201
|
+
fillable: true,
|
|
202
|
+
validation: {
|
|
203
|
+
rule: schema.string().max(255),
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
shippingState: {
|
|
208
|
+
personal: true,
|
|
209
|
+
order: 17,
|
|
210
|
+
fillable: true,
|
|
211
|
+
validation: {
|
|
212
|
+
rule: schema.string().max(100),
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
shippingZip: {
|
|
217
|
+
personal: true,
|
|
218
|
+
order: 18,
|
|
219
|
+
fillable: true,
|
|
220
|
+
validation: {
|
|
221
|
+
rule: schema.string().max(20),
|
|
140
222
|
},
|
|
141
|
-
factory: () => 'test-coupon-id',
|
|
142
223
|
},
|
|
143
224
|
},
|
|
144
225
|
|
|
@@ -64,6 +64,7 @@ export default defineModel({
|
|
|
64
64
|
description: {
|
|
65
65
|
order: 2,
|
|
66
66
|
fillable: true,
|
|
67
|
+
type: 'text',
|
|
67
68
|
validation: {
|
|
68
69
|
rule: schema.string(),
|
|
69
70
|
},
|
|
@@ -101,7 +102,10 @@ export default defineModel({
|
|
|
101
102
|
order: 5,
|
|
102
103
|
fillable: true,
|
|
103
104
|
validation: {
|
|
104
|
-
|
|
105
|
+
// Another category's id, so a number like the id it points at. As a
|
|
106
|
+
// string it was a text column, and joining it to categories.id failed
|
|
107
|
+
// on PostgreSQL with "text = bigint" (stacksjs/stacks#3002).
|
|
108
|
+
rule: schema.number(),
|
|
105
109
|
},
|
|
106
110
|
factory: () => null, // Most categories won't have a parent
|
|
107
111
|
},
|
|
@@ -55,6 +55,7 @@ export default defineModel({
|
|
|
55
55
|
description: {
|
|
56
56
|
order: 2,
|
|
57
57
|
fillable: true,
|
|
58
|
+
type: 'text',
|
|
58
59
|
validation: {
|
|
59
60
|
rule: schema.string(),
|
|
60
61
|
},
|
|
@@ -145,7 +146,9 @@ export default defineModel({
|
|
|
145
146
|
validation: {
|
|
146
147
|
rule: schema.string(),
|
|
147
148
|
},
|
|
148
|
-
|
|
149
|
+
// Stored and shown, never resolved: nothing redeems or joins on it yet,
|
|
150
|
+
// so what it holds is left to the feature that does. No factory, so a
|
|
151
|
+
// seed does not invent one (stacksjs/stacks#3002).
|
|
149
152
|
},
|
|
150
153
|
|
|
151
154
|
usageLimit: {
|
|
@@ -98,7 +98,9 @@ export default defineModel({
|
|
|
98
98
|
validation: {
|
|
99
99
|
rule: schema.string(),
|
|
100
100
|
},
|
|
101
|
-
|
|
101
|
+
// Stored and shown, never resolved: nothing redeems or joins on it yet,
|
|
102
|
+
// so what it holds is left to the feature that does. No factory, so a
|
|
103
|
+
// seed does not invent one (stacksjs/stacks#3002).
|
|
102
104
|
},
|
|
103
105
|
|
|
104
106
|
isActive: {
|
|
@@ -142,6 +142,7 @@ export default defineModel({
|
|
|
142
142
|
personal: true,
|
|
143
143
|
order: 11,
|
|
144
144
|
fillable: true,
|
|
145
|
+
type: 'text',
|
|
145
146
|
validation: {
|
|
146
147
|
rule: schema.string(),
|
|
147
148
|
},
|
|
@@ -199,7 +200,9 @@ export default defineModel({
|
|
|
199
200
|
validation: {
|
|
200
201
|
rule: schema.string(),
|
|
201
202
|
},
|
|
202
|
-
|
|
203
|
+
// Stored and shown, never resolved: nothing redeems or joins on it yet,
|
|
204
|
+
// so what it holds is left to the feature that does. No factory, so a
|
|
205
|
+
// seed does not invent one (stacksjs/stacks#3002).
|
|
203
206
|
},
|
|
204
207
|
},
|
|
205
208
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineModel } from '@stacksjs/orm'
|
|
2
|
+
import { slug } from '@stacksjs/strings'
|
|
2
3
|
import { schema } from '@stacksjs/validation/runtime'
|
|
3
4
|
|
|
4
5
|
export default defineModel({
|
|
@@ -56,9 +57,22 @@ export default defineModel({
|
|
|
56
57
|
factory: faker => faker.commerce.productName(),
|
|
57
58
|
},
|
|
58
59
|
|
|
60
|
+
// The storefront's address for a product: /products/{slug}, and what a
|
|
61
|
+
// cart line keeps in product_sku (stacksjs/stacks#3005).
|
|
62
|
+
slug: {
|
|
63
|
+
order: 1,
|
|
64
|
+
unique: true,
|
|
65
|
+
fillable: true,
|
|
66
|
+
validation: {
|
|
67
|
+
rule: schema.string().required().max(255),
|
|
68
|
+
},
|
|
69
|
+
factory: (_faker, attributes) => slug(String(attributes.name)),
|
|
70
|
+
},
|
|
71
|
+
|
|
59
72
|
description: {
|
|
60
73
|
order: 2,
|
|
61
74
|
fillable: true,
|
|
75
|
+
type: 'text',
|
|
62
76
|
validation: {
|
|
63
77
|
rule: schema.string(),
|
|
64
78
|
},
|
|
@@ -139,6 +153,7 @@ export default defineModel({
|
|
|
139
153
|
nutritionalInfo: {
|
|
140
154
|
order: 10,
|
|
141
155
|
fillable: true,
|
|
156
|
+
type: 'text',
|
|
142
157
|
validation: {
|
|
143
158
|
rule: schema.string(),
|
|
144
159
|
},
|
|
@@ -77,6 +77,7 @@ export default defineModel({
|
|
|
77
77
|
description: {
|
|
78
78
|
order: 5,
|
|
79
79
|
fillable: true,
|
|
80
|
+
type: 'text',
|
|
80
81
|
validation: {
|
|
81
82
|
rule: schema.string(),
|
|
82
83
|
},
|
|
@@ -86,6 +87,7 @@ export default defineModel({
|
|
|
86
87
|
options: {
|
|
87
88
|
order: 6,
|
|
88
89
|
fillable: true,
|
|
90
|
+
type: 'text',
|
|
89
91
|
validation: {
|
|
90
92
|
rule: schema.string(),
|
|
91
93
|
},
|
|
@@ -34,7 +34,9 @@ export default defineModel({
|
|
|
34
34
|
observe: true,
|
|
35
35
|
},
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
// The order a storefront review was left for: one review per product per
|
|
38
|
+
// order, and the proof the reviewer bought it (stacksjs/stacks#3017).
|
|
39
|
+
belongsTo: ['Product', 'Customer', 'Order'],
|
|
38
40
|
|
|
39
41
|
attributes: {
|
|
40
42
|
/**
|
|
@@ -72,7 +72,10 @@ export default defineModel({
|
|
|
72
72
|
order: 4,
|
|
73
73
|
fillable: true,
|
|
74
74
|
validation: {
|
|
75
|
-
|
|
75
|
+
// A Unix timestamp in milliseconds, so a bigint column: `number()`
|
|
76
|
+
// generated a 32-bit integer that Date.now() overflows on PostgreSQL
|
|
77
|
+
// and MySQL (stacksjs/stacks#2996).
|
|
78
|
+
rule: schema.unix(),
|
|
76
79
|
message: {
|
|
77
80
|
date: 'Time must be a valid timestamp',
|
|
78
81
|
},
|
package/dist/native.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import { MODEL_DEFINITION } from './define-model';
|
|
3
|
+
import type { StacksModelDefinition } from './define-model';
|
|
4
|
+
/**
|
|
5
|
+
* Own one SQLite database in a native backend process. Schema comes from the
|
|
6
|
+
* same migration planner as Buddy; additive upgrades and the snapshot commit
|
|
7
|
+
* atomically. Destructive upgrades require an explicit application migration.
|
|
8
|
+
*/
|
|
9
|
+
export declare function openNativeDatabase(options: { path: string, models: Record<string, NativeModel> }): Database;
|
|
10
|
+
/**
|
|
11
|
+
* Model-declared CRUD for an authenticated native transport. Authorization is
|
|
12
|
+
* mandatory and evaluated before queries; web middleware is never bypassed.
|
|
13
|
+
* Use only behind stx's authenticated native backend, or supply an equivalent
|
|
14
|
+
* per-request authorization implementation. Native models explicitly declare
|
|
15
|
+
* middleware: [] because their session is enforced by this transport.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createNativeModelApi(options: {
|
|
18
|
+
models: Record<string, NativeModel>
|
|
19
|
+
authorize: (request: Request, model: string, ability: string) => boolean | Promise<boolean>
|
|
20
|
+
}): (request: Request) => Promise<Response | null>;
|
|
21
|
+
/** Explicit model registry: the compiled app never discovers source files at runtime. */
|
|
22
|
+
export declare interface NativeModel {
|
|
23
|
+
[MODEL_DEFINITION]: StacksModelDefinition
|
|
24
|
+
find: (id: number) => Promise<unknown>
|
|
25
|
+
create: (data: Record<string, unknown>) => Promise<unknown>
|
|
26
|
+
update: (id: number, data: Record<string, unknown>) => Promise<unknown>
|
|
27
|
+
destroy: (id: number) => Promise<unknown>
|
|
28
|
+
limit: (count: number) => { offset: (offset: number) => { get: () => Promise<unknown> } }
|
|
29
|
+
}
|
package/dist/native.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Database}from"bun:sqlite";import{chmodSync,mkdirSync}from"node:fs";import{dirname,isAbsolute}from"node:path";import{buildMigrationPlan,configureOrm,generateDiffOperations}from"@stacksjs/query-builder";import{apiBasePath,filterFillable,getWritableFields,mapWriteError,resolveIndexPageArgs}from"./auto-crud";import{MODEL_DEFINITION,toAttrs}from"./define-model";export function openNativeDatabase(options){if(options.path!==":memory:"&&!isAbsolute(options.path))throw Error("A native database requires an absolute Application Support path");if(options.path!==":memory:")mkdirSync(dirname(options.path),{recursive:!0,mode:448});const db=new Database(options.path,{create:!0});try{if(options.path!==":memory:")chmodSync(options.path,384);db.exec("PRAGMA foreign_keys = ON; PRAGMA busy_timeout = 5000;");const models=Object.fromEntries(Object.entries(options.models).map(([name,model])=>[name,model[MODEL_DEFINITION]])),next=buildMigrationPlan(models,{dialect:"sqlite"});db.transaction(()=>{db.exec("CREATE TABLE IF NOT EXISTS _stacks_native_schema (id INTEGER PRIMARY KEY CHECK (id = 1), snapshot TEXT NOT NULL)");const saved=db.query("SELECT snapshot FROM _stacks_native_schema WHERE id = 1").get(),previous=saved?JSON.parse(saved.snapshot):void 0,diff=generateDiffOperations(previous,next);if(diff.operations.some((operation)=>operation.destructive))throw Error("Native model upgrade contains destructive changes; provide an explicit data migration");for(const statement of diff.statements)if(statement.replace(/--[^\n]*/g,"").trim())db.exec(statement);db.query("INSERT INTO _stacks_native_schema (id, snapshot) VALUES (1, ?) ON CONFLICT (id) DO UPDATE SET snapshot = excluded.snapshot").run(JSON.stringify(next))}).immediate();configureOrm({database:db});return db}catch(error){db.close();throw error}}export function createNativeModelApi(options){const models=Object.entries(options.models).flatMap(([name,model])=>{const definition=model[MODEL_DEFINITION],api=definition.traits?.useApi;if(!api||typeof api!=="object")return[];if(!Array.isArray(api.middleware)||api.middleware.length)throw Error(`${name}: native CRUD requires explicit middleware: [] and transport authorization`);if(!api.uri)throw Error(`${name}: native CRUD requires a useApi uri`);return[{name,model,definition,api,base:apiBasePath(api.uri,api.prefix)}]}),json=(data,status=200)=>Response.json(data,{status,headers:{"cache-control":"private, no-store"}});return async(request)=>{const url=new URL(request.url);for(const entry of models){const{name,model,definition,api,base}=entry,suffix=url.pathname.slice(base.length);if(!url.pathname.startsWith(base)||suffix&&!/^\/\d+$/.test(suffix))continue;const id=suffix?Number(suffix.slice(1)):void 0,ability=request.method==="GET"?id===void 0?"index":"show":request.method==="POST"&&id===void 0?"store":["PATCH","PUT"].includes(request.method)&&id!==void 0?"update":request.method==="DELETE"&&id!==void 0?"destroy":void 0;if(!ability||!api.routes?.includes(ability))return json({error:"Method not allowed"},405);if(!await options.authorize(request,name,ability))return json({error:"Forbidden"},403);try{if(ability==="index"){const{perPage,offset}=resolveIndexPageArgs(url.searchParams);return json({data:toAttrs(await model.limit(perPage).offset(offset).get())})}if(id!==void 0&&!await model.find(id))return json({error:"Not found"},404);if(ability==="show")return json({data:toAttrs(await model.find(id))});if(ability==="destroy"){await model.destroy(id);return new Response(null,{status:204})}let body;try{body=await request.json()}catch{return json({error:"Invalid JSON"},400)}if(!body||typeof body!=="object"||Array.isArray(body))return json({error:"Expected an object"},422);const fields=getWritableFields({attributes:definition.attributes,belongsTo:Object.values(definition.belongsTo??{})}),data=filterFillable(body,fields),row=ability==="store"?await model.create(data):await model.update(id,data);return json({data:toAttrs(row)},ability==="store"?201:200)}catch(error){const result=mapWriteError(error,name,ability==="store"?"create":"update"),body={...result.body};delete body.detail;return json(body,result.status)}}return null}}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/orm",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.321",
|
|
6
6
|
"description": "The Stacks ORM integration",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -63,31 +63,31 @@
|
|
|
63
63
|
"prepublishOnly": "bun run build"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@stacksjs/cache": "0.75.
|
|
67
|
-
"@stacksjs/cli": "0.75.
|
|
68
|
-
"@stacksjs/config": "0.75.
|
|
69
|
-
"@stacksjs/database": "0.75.
|
|
70
|
-
"@stacksjs/env": "0.75.
|
|
71
|
-
"@stacksjs/error-handling": "0.75.
|
|
72
|
-
"@stacksjs/events": "0.75.
|
|
73
|
-
"@stacksjs/logging": "0.75.
|
|
74
|
-
"@stacksjs/model-meta": "0.75.
|
|
75
|
-
"@stacksjs/pagination": "0.75.
|
|
76
|
-
"@stacksjs/path": "0.75.
|
|
77
|
-
"@stacksjs/query-builder": "0.75.
|
|
78
|
-
"@stacksjs/realtime": "0.75.
|
|
79
|
-
"@stacksjs/router": "0.75.
|
|
80
|
-
"@stacksjs/storage": "0.75.
|
|
81
|
-
"@stacksjs/strings": "0.75.
|
|
66
|
+
"@stacksjs/cache": "0.75.321",
|
|
67
|
+
"@stacksjs/cli": "0.75.321",
|
|
68
|
+
"@stacksjs/config": "0.75.321",
|
|
69
|
+
"@stacksjs/database": "0.75.321",
|
|
70
|
+
"@stacksjs/env": "0.75.321",
|
|
71
|
+
"@stacksjs/error-handling": "0.75.321",
|
|
72
|
+
"@stacksjs/events": "0.75.321",
|
|
73
|
+
"@stacksjs/logging": "0.75.321",
|
|
74
|
+
"@stacksjs/model-meta": "0.75.321",
|
|
75
|
+
"@stacksjs/pagination": "0.75.321",
|
|
76
|
+
"@stacksjs/path": "0.75.321",
|
|
77
|
+
"@stacksjs/query-builder": "0.75.321",
|
|
78
|
+
"@stacksjs/realtime": "0.75.321",
|
|
79
|
+
"@stacksjs/router": "0.75.321",
|
|
80
|
+
"@stacksjs/storage": "0.75.321",
|
|
81
|
+
"@stacksjs/strings": "0.75.321",
|
|
82
82
|
"@stacksjs/ts-validation": "^0.5.6",
|
|
83
|
-
"@stacksjs/validation": "0.75.
|
|
84
|
-
"bun-query-builder": "^0.3.
|
|
83
|
+
"@stacksjs/validation": "0.75.321",
|
|
84
|
+
"bun-query-builder": "^0.3.22"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
|
-
"@stacksjs/auth": "0.75.
|
|
88
|
-
"@stacksjs/payments": "0.75.
|
|
89
|
-
"@stacksjs/queue": "0.75.
|
|
90
|
-
"@stacksjs/search-engine": "0.75.
|
|
87
|
+
"@stacksjs/auth": "0.75.321",
|
|
88
|
+
"@stacksjs/payments": "0.75.321",
|
|
89
|
+
"@stacksjs/queue": "0.75.321",
|
|
90
|
+
"@stacksjs/search-engine": "0.75.321",
|
|
91
91
|
"stripe": "23.0.0"
|
|
92
92
|
},
|
|
93
93
|
"peerDependenciesMeta": {
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
}
|
|
109
109
|
},
|
|
110
110
|
"devDependencies": {
|
|
111
|
-
"@stacksjs/types": "0.75.
|
|
111
|
+
"@stacksjs/types": "0.75.321",
|
|
112
112
|
"better-dx": "^0.2.24",
|
|
113
113
|
"stripe": "23.0.0"
|
|
114
114
|
}
|