@stacksjs/orm 0.72.16 → 0.72.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.
Files changed (102) hide show
  1. package/dist/index.d.ts +97 -97
  2. package/dist/index.js +7 -7
  3. package/dist/models/Activity.ts +95 -0
  4. package/dist/models/AnalyticsEvent.ts +70 -0
  5. package/dist/models/Automation.ts +23 -0
  6. package/dist/models/AutomationRun.ts +26 -0
  7. package/dist/models/Board.ts +104 -0
  8. package/dist/models/BoardColumn.ts +88 -0
  9. package/dist/models/Campaign.ts +321 -0
  10. package/dist/models/CampaignSend.ts +191 -0
  11. package/dist/models/CampaignVariant.ts +25 -0
  12. package/dist/models/Card.ts +118 -0
  13. package/dist/models/CardComment.ts +68 -0
  14. package/dist/models/Comment.ts +109 -0
  15. package/dist/models/CommunicationSuppression.ts +22 -0
  16. package/dist/models/ConsentEvent.ts +30 -0
  17. package/dist/models/Content/Author.ts +109 -0
  18. package/dist/models/Content/Menu.ts +56 -0
  19. package/dist/models/Content/MenuItem.ts +91 -0
  20. package/dist/models/Content/Page.ts +205 -0
  21. package/dist/models/Content/PageRevision.ts +86 -0
  22. package/dist/models/Content/Post.ts +230 -0
  23. package/dist/models/Content/Redirect.ts +80 -0
  24. package/dist/models/Deployment.ts +117 -0
  25. package/dist/models/EmailIdempotency.ts +64 -0
  26. package/dist/models/EmailList.ts +134 -0
  27. package/dist/models/EmailListSubscriber.ts +91 -0
  28. package/dist/models/EmailSuppression.ts +52 -0
  29. package/dist/models/EmailWebhookEvent.ts +51 -0
  30. package/dist/models/Error.ts +77 -0
  31. package/dist/models/FailedJob.ts +84 -0
  32. package/dist/models/Forms/Form.ts +91 -0
  33. package/dist/models/Forms/FormField.ts +127 -0
  34. package/dist/models/Forms/FormSubmission.ts +114 -0
  35. package/dist/models/Job.ts +69 -0
  36. package/dist/models/Label.ts +67 -0
  37. package/dist/models/Log.ts +134 -0
  38. package/dist/models/MagicLinkToken.ts +97 -0
  39. package/dist/models/MailPreference.ts +213 -0
  40. package/dist/models/Notification.ts +68 -0
  41. package/dist/models/NotificationDelivery.ts +102 -0
  42. package/dist/models/PaymentMethod.ts +98 -0
  43. package/dist/models/PaymentProduct.ts +91 -0
  44. package/dist/models/PaymentTransaction.ts +78 -0
  45. package/dist/models/QueryLog.ts +182 -0
  46. package/dist/models/README.md +31 -0
  47. package/dist/models/Release.ts +90 -0
  48. package/dist/models/Request.ts +133 -0
  49. package/dist/models/SenderDomain.ts +22 -0
  50. package/dist/models/Site.ts +112 -0
  51. package/dist/models/SiteDomain.ts +74 -0
  52. package/dist/models/SmsOptOut.ts +65 -0
  53. package/dist/models/SocialAccount.ts +70 -0
  54. package/dist/models/SocialPost.ts +144 -0
  55. package/dist/models/Subscriber.ts +89 -0
  56. package/dist/models/SubscriberEmail.ts +55 -0
  57. package/dist/models/Subscription.ts +153 -0
  58. package/dist/models/Tag.ts +105 -0
  59. package/dist/models/Team.ts +75 -0
  60. package/dist/models/TeamInvitation.ts +159 -0
  61. package/dist/models/TeamMember.ts +88 -0
  62. package/dist/models/UsageEvent.ts +24 -0
  63. package/dist/models/User.ts +142 -0
  64. package/dist/models/commerce/Auction.ts +173 -0
  65. package/dist/models/commerce/AuctionItem.ts +204 -0
  66. package/dist/models/commerce/Bid.ts +129 -0
  67. package/dist/models/commerce/Cart.ts +140 -0
  68. package/dist/models/commerce/CartItem.ts +138 -0
  69. package/dist/models/commerce/Category.ts +125 -0
  70. package/dist/models/commerce/Coupon.ts +186 -0
  71. package/dist/models/commerce/Customer.ts +132 -0
  72. package/dist/models/commerce/DeliveryRoute.ts +127 -0
  73. package/dist/models/commerce/DeliveryStop.ts +166 -0
  74. package/dist/models/commerce/DigitalDelivery.ts +106 -0
  75. package/dist/models/commerce/Driver.ts +168 -0
  76. package/dist/models/commerce/DriverPing.ts +103 -0
  77. package/dist/models/commerce/GiftCard.ts +195 -0
  78. package/dist/models/commerce/LicenseKey.ts +89 -0
  79. package/dist/models/commerce/LoyaltyPoint.ts +108 -0
  80. package/dist/models/commerce/LoyaltyReward.ts +129 -0
  81. package/dist/models/commerce/Manufacturer.ts +90 -0
  82. package/dist/models/commerce/Order.ts +198 -0
  83. package/dist/models/commerce/OrderIdempotency.ts +34 -0
  84. package/dist/models/commerce/OrderItem.ts +51 -0
  85. package/dist/models/commerce/Payment.ts +182 -0
  86. package/dist/models/commerce/Pledge.ts +112 -0
  87. package/dist/models/commerce/PrintDevice.ts +120 -0
  88. package/dist/models/commerce/Product.ts +153 -0
  89. package/dist/models/commerce/ProductUnit.ts +113 -0
  90. package/dist/models/commerce/ProductVariant.ts +111 -0
  91. package/dist/models/commerce/Receipt.ts +144 -0
  92. package/dist/models/commerce/Review.ts +171 -0
  93. package/dist/models/commerce/ShippingMethod.ts +102 -0
  94. package/dist/models/commerce/ShippingRate.ts +79 -0
  95. package/dist/models/commerce/ShippingZone.ts +116 -0
  96. package/dist/models/commerce/TaxRate.ts +167 -0
  97. package/dist/models/commerce/Transaction.ts +127 -0
  98. package/dist/models/commerce/WaitlistProduct.ts +151 -0
  99. package/dist/models/commerce/WaitlistRestaurant.ts +189 -0
  100. package/dist/models/realtime/Websocket.ts +78 -0
  101. package/dist/password-policy.ts +46 -0
  102. package/package.json +4 -4
@@ -0,0 +1,69 @@
1
+ import { defineModel } from '@stacksjs/orm'
2
+ import { schema } from '@stacksjs/validation'
3
+
4
+ export default defineModel({
5
+ name: 'Job',
6
+ table: 'jobs',
7
+ primaryKey: 'id',
8
+ autoIncrement: true,
9
+
10
+ traits: {
11
+ useTimestamps: true,
12
+ useSeeder: {
13
+ count: 15,
14
+ },
15
+ },
16
+
17
+ attributes: {
18
+ queue: {
19
+ fillable: true,
20
+ validation: {
21
+ rule: schema.string().required().max(255),
22
+ message: {
23
+ max: 'Queue must have a maximum of 255 characters',
24
+ },
25
+ },
26
+ factory: () => 'default',
27
+ },
28
+
29
+ payload: {
30
+ fillable: true,
31
+ validation: {
32
+ rule: schema.string().required(),
33
+ },
34
+ factory: () => JSON.stringify({
35
+ jobName: 'ExampleJob',
36
+ payload: {},
37
+ options: { tries: 3 },
38
+ envelopeVersion: 1,
39
+ dispatchedAt: new Date().toISOString(),
40
+ }),
41
+ },
42
+
43
+ attempts: {
44
+ fillable: true,
45
+ validation: {
46
+ rule: schema.number(),
47
+ message: {
48
+ number: 'attempts must be a number',
49
+ },
50
+ },
51
+ factory: () => 0,
52
+ },
53
+
54
+ available_at: {
55
+ fillable: true,
56
+ validation: {
57
+ rule: schema.number(),
58
+ },
59
+ factory: () => Math.floor(Date.now() / 1000),
60
+ },
61
+ reserved_at: {
62
+ fillable: true,
63
+ validation: {
64
+ rule: schema.number(),
65
+ },
66
+ factory: () => null,
67
+ },
68
+ },
69
+ } as const)
@@ -0,0 +1,67 @@
1
+ import { defineModel } from '@stacksjs/orm'
2
+ import { schema } from '@stacksjs/validation'
3
+
4
+ /**
5
+ * Card label / tag (stacksjs/stacks#1846).
6
+ *
7
+ * Labels are board-scoped: each board owns its own label palette
8
+ * (so "Bug" on board A is a different record from "Bug" on board B,
9
+ * with potentially different colours). Cards attach labels via the
10
+ * `card_labels` pivot — that wiring lands in Phase 3.
11
+ *
12
+ * Hidden from the sidebar as a standalone model row — labels are
13
+ * managed inside the board view, not as a top-level surface.
14
+ */
15
+ export default defineModel({
16
+ name: 'Label',
17
+ table: 'labels',
18
+ primaryKey: 'id',
19
+ autoIncrement: true,
20
+
21
+ traits: {
22
+ useUuid: true,
23
+ useTimestamps: true,
24
+ useSearch: {
25
+ displayable: ['id', 'name', 'color', 'boardId'],
26
+ searchable: ['name'],
27
+ sortable: ['name', 'createdAt'],
28
+ filterable: ['boardId'],
29
+ },
30
+
31
+ useSeeder: { count: 0 },
32
+
33
+ useApi: {
34
+ uri: 'labels',
35
+ routes: ['index', 'store', 'show', 'update', 'destroy'],
36
+ middleware: ['auth'],
37
+ },
38
+ },
39
+
40
+ belongsTo: ['Board'],
41
+
42
+ attributes: {
43
+ boardId: {
44
+ order: 1,
45
+ fillable: true,
46
+ validation: { rule: schema.number().required() },
47
+ factory: () => 1,
48
+ },
49
+
50
+ name: {
51
+ order: 2,
52
+ fillable: true,
53
+ validation: { rule: schema.string().required().min(1).max(60) },
54
+ factory: faker => faker.helpers.arrayElement(['Bug', 'Feature', 'Docs', 'Refactor', 'Urgent']),
55
+ },
56
+
57
+ color: {
58
+ order: 3,
59
+ fillable: true,
60
+ // Hue token resolved by the UI — same palette as Board.color.
61
+ validation: { rule: schema.string().max(40) },
62
+ factory: faker => faker.helpers.arrayElement(['red', 'amber', 'emerald', 'blue', 'violet', 'slate']),
63
+ },
64
+ },
65
+
66
+ dashboard: { enabled: false },
67
+ } as const)
@@ -0,0 +1,134 @@
1
+ import { defineModel } from '@stacksjs/orm'
2
+ import { schema } from '@stacksjs/validation'
3
+
4
+ export default defineModel({
5
+ name: 'Log',
6
+ table: 'logs',
7
+ primaryKey: 'id',
8
+ autoIncrement: true,
9
+
10
+ indexes: [
11
+ {
12
+ name: 'logs_timestamp_index',
13
+ columns: ['timestamp'],
14
+ },
15
+ {
16
+ name: 'logs_type_timestamp_index',
17
+ columns: ['type', 'timestamp'],
18
+ },
19
+ {
20
+ name: 'logs_source_timestamp_index',
21
+ columns: ['source', 'timestamp'],
22
+ },
23
+ {
24
+ name: 'logs_project_timestamp_index',
25
+ columns: ['project', 'timestamp'],
26
+ },
27
+ ],
28
+
29
+ traits: {
30
+ useTimestamps: true,
31
+ useApi: {
32
+ uri: 'logs',
33
+ routes: ['index', 'show'],
34
+ middleware: ['auth'],
35
+ },
36
+ useSeeder: {
37
+ count: 50,
38
+ },
39
+ useSearch: {
40
+ displayable: ['id', 'type', 'source', 'message', 'project', 'timestamp'],
41
+ searchable: ['message', 'project', 'file'],
42
+ sortable: ['timestamp', 'type', 'source'],
43
+ filterable: ['type', 'source', 'project'],
44
+ },
45
+ },
46
+
47
+ attributes: {
48
+ timestamp: {
49
+ order: 1,
50
+ fillable: true,
51
+ validation: {
52
+ rule: schema.number().required(),
53
+ message: {
54
+ date: 'Timestamp must be a valid date',
55
+ },
56
+ },
57
+ factory: faker => faker.date.recent().getTime(),
58
+ },
59
+
60
+ type: {
61
+ order: 2,
62
+ fillable: true,
63
+ validation: {
64
+ rule: schema.enum(['warning', 'error', 'info', 'success']).required(),
65
+ message: {
66
+ enum: 'Type must be one of: warning, error, info, success',
67
+ },
68
+ },
69
+ factory: faker => faker.helpers.arrayElement(['warning', 'error', 'info', 'success']),
70
+ },
71
+
72
+ source: {
73
+ order: 3,
74
+ fillable: true,
75
+ validation: {
76
+ rule: schema.enum(['file', 'cli', 'system']).required(),
77
+ message: {
78
+ enum: 'Source must be one of: file, cli, system',
79
+ },
80
+ },
81
+ factory: faker => faker.helpers.arrayElement(['file', 'cli', 'system']),
82
+ },
83
+
84
+ message: {
85
+ order: 4,
86
+ fillable: true,
87
+ validation: {
88
+ rule: schema.string().required().min(1).max(1000),
89
+ message: {
90
+ min: 'Message must not be empty',
91
+ max: 'Message must not exceed 1000 characters',
92
+ },
93
+ },
94
+ factory: faker => faker.lorem.sentence(),
95
+ },
96
+
97
+ project: {
98
+ order: 5,
99
+ fillable: true,
100
+ validation: {
101
+ rule: schema.string().min(1).required().max(255),
102
+ message: {
103
+ min: 'Project name must not be empty',
104
+ max: 'Project name must not exceed 255 characters',
105
+ },
106
+ },
107
+ factory: faker => faker.company.name(),
108
+ },
109
+
110
+ stacktrace: {
111
+ order: 6,
112
+ fillable: true,
113
+ validation: {
114
+ rule: schema.string().required().max(5000),
115
+ message: {
116
+ max: 'Stacktrace must not exceed 5000 characters',
117
+ },
118
+ },
119
+ factory: faker => faker.lorem.paragraphs(2),
120
+ },
121
+
122
+ file: {
123
+ order: 7,
124
+ fillable: true,
125
+ validation: {
126
+ rule: schema.string().required().max(255),
127
+ message: {
128
+ max: 'File path must not exceed 255 characters',
129
+ },
130
+ },
131
+ factory: faker => faker.system.filePath().substring(0, 255),
132
+ },
133
+ },
134
+ } as const)
@@ -0,0 +1,97 @@
1
+ import { defineModel } from '@stacksjs/orm'
2
+ import { schema } from '@stacksjs/validation'
3
+
4
+ /**
5
+ * A single-use passwordless sign-in token. `token` stores the SHA-256 of the
6
+ * raw value - deterministic, so consume is one indexed lookup, and with 256
7
+ * bits of entropy in the raw token an offline attack on a fast hash is
8
+ * irrelevant (deliberately NOT the bcrypt-and-scan of password resets).
9
+ *
10
+ * No `useApi`: these rows are written and consumed by the auth flow only.
11
+ */
12
+ export default defineModel({
13
+ name: 'MagicLinkToken',
14
+ table: 'magic_link_tokens',
15
+ primaryKey: 'id',
16
+ autoIncrement: true,
17
+
18
+ indexes: [
19
+ {
20
+ name: 'magic_link_tokens_token_unique',
21
+ columns: ['token'],
22
+ unique: true,
23
+ },
24
+ ],
25
+
26
+ traits: {
27
+ useTimestamps: true,
28
+ },
29
+
30
+ belongsTo: ['User'],
31
+
32
+ attributes: {
33
+ email: {
34
+ required: true,
35
+ order: 1,
36
+ fillable: true,
37
+ validation: {
38
+ rule: schema.string().email().max(255),
39
+ },
40
+ factory: faker => faker.internet.email(),
41
+ },
42
+
43
+ /** SHA-256 hex of the raw token. Never the raw value. */
44
+ token: {
45
+ required: true,
46
+ order: 2,
47
+ fillable: true,
48
+ unique: true,
49
+ validation: {
50
+ rule: schema.string().min(64).max(64),
51
+ },
52
+ factory: faker => faker.string.hexadecimal({ length: 64, prefix: '' }).toLowerCase(),
53
+ },
54
+
55
+ expiresAt: {
56
+ required: true,
57
+ order: 3,
58
+ fillable: true,
59
+ validation: {
60
+ rule: schema.timestamp(),
61
+ },
62
+ factory: () => new Date(Date.now() + 15 * 60_000).toISOString().slice(0, 19).replace('T', ' '),
63
+ },
64
+
65
+ consumedAt: {
66
+ required: false,
67
+ order: 4,
68
+ fillable: true,
69
+ validation: {
70
+ rule: schema.timestamp(),
71
+ },
72
+ factory: () => null,
73
+ },
74
+
75
+ /** Relative path the consumed link lands on. Validated relative-only. */
76
+ redirectTo: {
77
+ required: false,
78
+ order: 5,
79
+ fillable: true,
80
+ validation: {
81
+ rule: schema.string().max(2048),
82
+ },
83
+ factory: () => null,
84
+ },
85
+
86
+ /** The site whose primary host the link targets, on multi-site apps. */
87
+ siteId: {
88
+ required: false,
89
+ order: 6,
90
+ fillable: true,
91
+ validation: {
92
+ rule: schema.number().min(1),
93
+ },
94
+ factory: () => null,
95
+ },
96
+ },
97
+ } as const)
@@ -0,0 +1,213 @@
1
+ import { defineModel } from '@stacksjs/orm'
2
+ import { schema } from '@stacksjs/validation'
3
+
4
+ export default defineModel({
5
+ name: 'MailPreference',
6
+ table: 'mail_preferences',
7
+ primaryKey: 'id',
8
+ autoIncrement: true,
9
+
10
+ traits: {
11
+ useTimestamps: true,
12
+ useApi: {
13
+ uri: 'mail-preferences',
14
+ routes: ['index', 'store', 'show', 'update', 'destroy'],
15
+ middleware: ['auth'],
16
+ },
17
+ },
18
+
19
+ attributes: {
20
+ mailbox: {
21
+ fillable: true,
22
+ required: true,
23
+ unique: true,
24
+ validation: {
25
+ rule: schema.string().email().max(320).required(),
26
+ },
27
+ },
28
+
29
+ accountName: {
30
+ fillable: true,
31
+ required: true,
32
+ default: 'Stacks',
33
+ validation: {
34
+ rule: schema.string().max(255).required(),
35
+ },
36
+ },
37
+
38
+ signature: {
39
+ fillable: true,
40
+ required: false,
41
+ validation: {
42
+ rule: schema.string().max(20_000),
43
+ },
44
+ },
45
+
46
+ displayDensity: {
47
+ fillable: true,
48
+ required: true,
49
+ default: 'default',
50
+ validation: {
51
+ rule: schema.enum(['comfortable', 'default', 'compact']),
52
+ },
53
+ },
54
+
55
+ theme: {
56
+ fillable: true,
57
+ required: true,
58
+ default: 'system',
59
+ validation: {
60
+ rule: schema.enum(['light', 'dark', 'system']),
61
+ },
62
+ },
63
+
64
+ language: {
65
+ fillable: true,
66
+ required: true,
67
+ default: 'en',
68
+ validation: {
69
+ rule: schema.enum(['en', 'fr', 'de', 'es', 'ja']),
70
+ },
71
+ },
72
+
73
+ defaultReplyBehavior: {
74
+ fillable: true,
75
+ required: true,
76
+ default: 'replyAll',
77
+ validation: {
78
+ rule: schema.enum(['reply', 'replyAll']),
79
+ },
80
+ },
81
+
82
+ sendAndArchive: {
83
+ fillable: true,
84
+ required: true,
85
+ default: true,
86
+ validation: {
87
+ rule: schema.boolean(),
88
+ },
89
+ },
90
+
91
+ autoAdvance: {
92
+ fillable: true,
93
+ required: true,
94
+ default: 'newer',
95
+ validation: {
96
+ rule: schema.enum(['newer', 'older', 'back']),
97
+ },
98
+ },
99
+
100
+ desktopNotifications: {
101
+ fillable: true,
102
+ required: true,
103
+ default: true,
104
+ validation: {
105
+ rule: schema.boolean(),
106
+ },
107
+ },
108
+
109
+ notificationSound: {
110
+ fillable: true,
111
+ required: true,
112
+ default: 'default',
113
+ validation: {
114
+ rule: schema.enum(['default', 'subtle', 'none']),
115
+ },
116
+ },
117
+
118
+ notificationPreview: {
119
+ fillable: true,
120
+ required: true,
121
+ default: true,
122
+ validation: {
123
+ rule: schema.boolean(),
124
+ },
125
+ },
126
+
127
+ filters: {
128
+ fillable: true,
129
+ required: true,
130
+ default: '[]',
131
+ validation: {
132
+ rule: schema.string(),
133
+ },
134
+ },
135
+
136
+ blockedSenders: {
137
+ fillable: true,
138
+ required: true,
139
+ default: '[]',
140
+ validation: {
141
+ rule: schema.string(),
142
+ },
143
+ },
144
+
145
+ labels: {
146
+ fillable: true,
147
+ required: true,
148
+ default: '[]',
149
+ validation: {
150
+ rule: schema.string(),
151
+ },
152
+ },
153
+
154
+ loadRemoteImages: {
155
+ fillable: true,
156
+ required: true,
157
+ default: false,
158
+ validation: {
159
+ rule: schema.boolean(),
160
+ },
161
+ },
162
+
163
+ showExternalContent: {
164
+ fillable: true,
165
+ required: true,
166
+ default: false,
167
+ validation: {
168
+ rule: schema.boolean(),
169
+ },
170
+ },
171
+
172
+ vacationEnabled: {
173
+ fillable: true,
174
+ required: true,
175
+ default: false,
176
+ validation: {
177
+ rule: schema.boolean(),
178
+ },
179
+ },
180
+
181
+ vacationStartDate: {
182
+ fillable: true,
183
+ required: false,
184
+ validation: {
185
+ rule: schema.string(),
186
+ },
187
+ },
188
+
189
+ vacationEndDate: {
190
+ fillable: true,
191
+ required: false,
192
+ validation: {
193
+ rule: schema.string(),
194
+ },
195
+ },
196
+
197
+ vacationSubject: {
198
+ fillable: true,
199
+ required: false,
200
+ validation: {
201
+ rule: schema.string().max(255),
202
+ },
203
+ },
204
+
205
+ vacationMessage: {
206
+ fillable: true,
207
+ required: false,
208
+ validation: {
209
+ rule: schema.string().max(20_000),
210
+ },
211
+ },
212
+ },
213
+ } as const)
@@ -0,0 +1,68 @@
1
+ import { defineModel } from '@stacksjs/orm'
2
+ import { schema } from '@stacksjs/validation'
3
+
4
+ export default defineModel({
5
+ name: 'Notification',
6
+ table: 'notifications',
7
+ primaryKey: 'id',
8
+ autoIncrement: true,
9
+
10
+ traits: {
11
+ useUuid: true,
12
+ useTimestamps: true,
13
+ useSeeder: {
14
+ count: 30,
15
+ },
16
+ useApi: {
17
+ uri: 'notifications',
18
+ routes: ['index', 'store', 'show', 'update', 'destroy'],
19
+ middleware: ['auth'],
20
+ },
21
+ },
22
+
23
+ belongsTo: ['User'],
24
+
25
+ attributes: {
26
+ type: {
27
+ required: true,
28
+ fillable: true,
29
+ validation: {
30
+ rule: schema.string().max(255),
31
+ },
32
+ factory: faker => faker.helpers.arrayElement([
33
+ 'order.shipped',
34
+ 'payment.received',
35
+ 'security.alert',
36
+ 'subscription.renewed',
37
+ ]),
38
+ },
39
+
40
+ data: {
41
+ type: 'text',
42
+ required: true,
43
+ fillable: true,
44
+ validation: {
45
+ rule: schema.string(),
46
+ },
47
+ factory: faker => JSON.stringify({
48
+ body: faker.lorem.sentence(),
49
+ source: 'system',
50
+ }),
51
+ },
52
+
53
+ readAt: {
54
+ required: false,
55
+ fillable: true,
56
+ validation: {
57
+ rule: schema.timestamp(),
58
+ },
59
+ factory: (faker) => {
60
+ if (faker.datatype.boolean()) {
61
+ return faker.date.recent().toISOString().slice(0, 19).replace('T', ' ')
62
+ }
63
+ return null
64
+ },
65
+ },
66
+
67
+ },
68
+ } as const)