@contractspec/example.saas-boilerplate 3.8.9 → 3.8.11

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 (156) hide show
  1. package/.turbo/turbo-build.log +155 -155
  2. package/CHANGELOG.md +34 -0
  3. package/dist/billing/billing.entity.js +1 -113
  4. package/dist/billing/billing.enum.js +1 -19
  5. package/dist/billing/billing.event.js +1 -90
  6. package/dist/billing/billing.handler.js +1 -148
  7. package/dist/billing/billing.operations.js +1 -278
  8. package/dist/billing/billing.presentation.js +1 -55
  9. package/dist/billing/billing.schema.js +1 -121
  10. package/dist/billing/index.js +1 -691
  11. package/dist/browser/billing/billing.entity.js +1 -113
  12. package/dist/browser/billing/billing.enum.js +1 -19
  13. package/dist/browser/billing/billing.event.js +1 -90
  14. package/dist/browser/billing/billing.handler.js +1 -148
  15. package/dist/browser/billing/billing.operations.js +1 -278
  16. package/dist/browser/billing/billing.presentation.js +1 -55
  17. package/dist/browser/billing/billing.schema.js +1 -121
  18. package/dist/browser/billing/index.js +1 -691
  19. package/dist/browser/dashboard/dashboard.presentation.js +1 -55
  20. package/dist/browser/dashboard/index.js +1 -55
  21. package/dist/browser/docs/index.js +5 -49
  22. package/dist/browser/docs/saas-boilerplate.docblock.js +5 -49
  23. package/dist/browser/example.js +1 -39
  24. package/dist/browser/handlers/index.js +2 -358
  25. package/dist/browser/handlers/saas.handlers.js +2 -134
  26. package/dist/browser/index.js +9 -3591
  27. package/dist/browser/presentations/index.js +1 -299
  28. package/dist/browser/project/index.js +1 -793
  29. package/dist/browser/project/project.entity.js +1 -77
  30. package/dist/browser/project/project.enum.js +1 -18
  31. package/dist/browser/project/project.event.js +1 -103
  32. package/dist/browser/project/project.handler.js +1 -178
  33. package/dist/browser/project/project.operations.js +1 -372
  34. package/dist/browser/project/project.presentation.js +1 -180
  35. package/dist/browser/project/project.schema.js +1 -134
  36. package/dist/browser/saas-boilerplate.feature.js +1 -304
  37. package/dist/browser/seeders/index.js +2 -20
  38. package/dist/browser/settings/index.js +1 -75
  39. package/dist/browser/settings/settings.entity.js +1 -74
  40. package/dist/browser/settings/settings.enum.js +1 -11
  41. package/dist/browser/shared/mock-data.js +1 -104
  42. package/dist/browser/tests/operations.test-spec.js +1 -112
  43. package/dist/browser/ui/SaasDashboard.js +1 -1239
  44. package/dist/browser/ui/SaasDashboard.visualizations.js +1 -249
  45. package/dist/browser/ui/SaasProjectList.js +1 -162
  46. package/dist/browser/ui/SaasSettingsPanel.js +1 -145
  47. package/dist/browser/ui/hooks/index.js +1 -159
  48. package/dist/browser/ui/hooks/useProjectList.js +1 -66
  49. package/dist/browser/ui/hooks/useProjectMutations.js +1 -91
  50. package/dist/browser/ui/index.js +5 -2077
  51. package/dist/browser/ui/modals/CreateProjectModal.js +1 -153
  52. package/dist/browser/ui/modals/ProjectActionsModal.js +1 -335
  53. package/dist/browser/ui/modals/index.js +1 -487
  54. package/dist/browser/ui/overlays/demo-overlays.js +1 -61
  55. package/dist/browser/ui/overlays/index.js +1 -61
  56. package/dist/browser/ui/renderers/index.js +5 -901
  57. package/dist/browser/ui/renderers/project-list.markdown.js +5 -725
  58. package/dist/browser/ui/renderers/project-list.renderer.js +1 -177
  59. package/dist/browser/visualizations/catalog.js +1 -155
  60. package/dist/browser/visualizations/index.js +1 -217
  61. package/dist/browser/visualizations/selectors.js +1 -210
  62. package/dist/dashboard/dashboard.presentation.js +1 -55
  63. package/dist/dashboard/index.js +1 -55
  64. package/dist/docs/index.js +5 -49
  65. package/dist/docs/saas-boilerplate.docblock.js +5 -49
  66. package/dist/example.js +1 -39
  67. package/dist/handlers/index.js +2 -358
  68. package/dist/handlers/saas.handlers.js +2 -134
  69. package/dist/index.js +9 -3591
  70. package/dist/node/billing/billing.entity.js +1 -113
  71. package/dist/node/billing/billing.enum.js +1 -19
  72. package/dist/node/billing/billing.event.js +1 -90
  73. package/dist/node/billing/billing.handler.js +1 -148
  74. package/dist/node/billing/billing.operations.js +1 -278
  75. package/dist/node/billing/billing.presentation.js +1 -55
  76. package/dist/node/billing/billing.schema.js +1 -121
  77. package/dist/node/billing/index.js +1 -691
  78. package/dist/node/dashboard/dashboard.presentation.js +1 -55
  79. package/dist/node/dashboard/index.js +1 -55
  80. package/dist/node/docs/index.js +5 -49
  81. package/dist/node/docs/saas-boilerplate.docblock.js +5 -49
  82. package/dist/node/example.js +1 -39
  83. package/dist/node/handlers/index.js +2 -358
  84. package/dist/node/handlers/saas.handlers.js +2 -134
  85. package/dist/node/index.js +9 -3591
  86. package/dist/node/presentations/index.js +1 -299
  87. package/dist/node/project/index.js +1 -793
  88. package/dist/node/project/project.entity.js +1 -77
  89. package/dist/node/project/project.enum.js +1 -18
  90. package/dist/node/project/project.event.js +1 -103
  91. package/dist/node/project/project.handler.js +1 -178
  92. package/dist/node/project/project.operations.js +1 -372
  93. package/dist/node/project/project.presentation.js +1 -180
  94. package/dist/node/project/project.schema.js +1 -134
  95. package/dist/node/saas-boilerplate.feature.js +1 -304
  96. package/dist/node/seeders/index.js +2 -20
  97. package/dist/node/settings/index.js +1 -75
  98. package/dist/node/settings/settings.entity.js +1 -74
  99. package/dist/node/settings/settings.enum.js +1 -11
  100. package/dist/node/shared/mock-data.js +1 -104
  101. package/dist/node/tests/operations.test-spec.js +1 -112
  102. package/dist/node/ui/SaasDashboard.js +1 -1239
  103. package/dist/node/ui/SaasDashboard.visualizations.js +1 -249
  104. package/dist/node/ui/SaasProjectList.js +1 -162
  105. package/dist/node/ui/SaasSettingsPanel.js +1 -145
  106. package/dist/node/ui/hooks/index.js +1 -159
  107. package/dist/node/ui/hooks/useProjectList.js +1 -66
  108. package/dist/node/ui/hooks/useProjectMutations.js +1 -91
  109. package/dist/node/ui/index.js +5 -2077
  110. package/dist/node/ui/modals/CreateProjectModal.js +1 -153
  111. package/dist/node/ui/modals/ProjectActionsModal.js +1 -335
  112. package/dist/node/ui/modals/index.js +1 -487
  113. package/dist/node/ui/overlays/demo-overlays.js +1 -61
  114. package/dist/node/ui/overlays/index.js +1 -61
  115. package/dist/node/ui/renderers/index.js +5 -901
  116. package/dist/node/ui/renderers/project-list.markdown.js +5 -725
  117. package/dist/node/ui/renderers/project-list.renderer.js +1 -177
  118. package/dist/node/visualizations/catalog.js +1 -155
  119. package/dist/node/visualizations/index.js +1 -217
  120. package/dist/node/visualizations/selectors.js +1 -210
  121. package/dist/presentations/index.js +1 -299
  122. package/dist/project/index.js +1 -793
  123. package/dist/project/project.entity.js +1 -77
  124. package/dist/project/project.enum.js +1 -18
  125. package/dist/project/project.event.js +1 -103
  126. package/dist/project/project.handler.js +1 -178
  127. package/dist/project/project.operations.js +1 -372
  128. package/dist/project/project.presentation.js +1 -180
  129. package/dist/project/project.schema.js +1 -134
  130. package/dist/saas-boilerplate.feature.js +1 -304
  131. package/dist/seeders/index.js +2 -20
  132. package/dist/settings/index.js +1 -75
  133. package/dist/settings/settings.entity.js +1 -74
  134. package/dist/settings/settings.enum.js +1 -11
  135. package/dist/shared/mock-data.js +1 -104
  136. package/dist/tests/operations.test-spec.js +1 -112
  137. package/dist/ui/SaasDashboard.js +1 -1239
  138. package/dist/ui/SaasDashboard.visualizations.js +1 -249
  139. package/dist/ui/SaasProjectList.js +1 -162
  140. package/dist/ui/SaasSettingsPanel.js +1 -145
  141. package/dist/ui/hooks/index.js +1 -159
  142. package/dist/ui/hooks/useProjectList.js +1 -66
  143. package/dist/ui/hooks/useProjectMutations.js +1 -91
  144. package/dist/ui/index.js +5 -2077
  145. package/dist/ui/modals/CreateProjectModal.js +1 -153
  146. package/dist/ui/modals/ProjectActionsModal.js +1 -335
  147. package/dist/ui/modals/index.js +1 -487
  148. package/dist/ui/overlays/demo-overlays.js +1 -61
  149. package/dist/ui/overlays/index.js +1 -61
  150. package/dist/ui/renderers/index.js +5 -901
  151. package/dist/ui/renderers/project-list.markdown.js +5 -725
  152. package/dist/ui/renderers/project-list.renderer.js +1 -177
  153. package/dist/visualizations/catalog.js +1 -155
  154. package/dist/visualizations/index.js +1 -217
  155. package/dist/visualizations/selectors.js +1 -210
  156. package/package.json +12 -12
@@ -1,692 +1,2 @@
1
1
  // @bun
2
- // src/billing/billing.entity.ts
3
- import {
4
- defineEntity,
5
- defineEntityEnum,
6
- field,
7
- index
8
- } from "@contractspec/lib.schema";
9
- var SubscriptionStatusEnum = defineEntityEnum({
10
- name: "SubscriptionStatus",
11
- values: ["TRIALING", "ACTIVE", "PAST_DUE", "CANCELED", "PAUSED"],
12
- schema: "saas_app",
13
- description: "Status of a subscription."
14
- });
15
- var SubscriptionEntity = defineEntity({
16
- name: "Subscription",
17
- description: "Organization subscription/plan information.",
18
- schema: "saas_app",
19
- map: "subscription",
20
- fields: {
21
- id: field.id(),
22
- organizationId: field.foreignKey({ isUnique: true }),
23
- planId: field.string({ description: "Plan identifier" }),
24
- planName: field.string({ description: "Plan display name" }),
25
- status: field.enum("SubscriptionStatus"),
26
- currentPeriodStart: field.dateTime(),
27
- currentPeriodEnd: field.dateTime(),
28
- trialEndsAt: field.dateTime({ isOptional: true }),
29
- cancelAtPeriodEnd: field.boolean({ default: false }),
30
- canceledAt: field.dateTime({ isOptional: true }),
31
- stripeSubscriptionId: field.string({ isOptional: true }),
32
- stripeCustomerId: field.string({ isOptional: true }),
33
- metadata: field.json({ isOptional: true }),
34
- createdAt: field.createdAt(),
35
- updatedAt: field.updatedAt()
36
- },
37
- enums: [SubscriptionStatusEnum]
38
- });
39
- var BillingUsageEntity = defineEntity({
40
- name: "BillingUsage",
41
- description: "Track usage of metered features.",
42
- schema: "saas_app",
43
- map: "billing_usage",
44
- fields: {
45
- id: field.id(),
46
- organizationId: field.foreignKey(),
47
- feature: field.string({
48
- description: 'Feature being tracked (e.g., "api_calls", "storage_gb")'
49
- }),
50
- quantity: field.int({ description: "Usage quantity" }),
51
- unit: field.string({
52
- isOptional: true,
53
- description: "Unit of measurement"
54
- }),
55
- billingPeriod: field.string({
56
- description: 'Billing period (e.g., "2024-01")'
57
- }),
58
- recordedAt: field.dateTime({ description: "When usage was recorded" }),
59
- sourceId: field.string({
60
- isOptional: true,
61
- description: "Source of usage (e.g., request ID)"
62
- }),
63
- sourceType: field.string({ isOptional: true }),
64
- metadata: field.json({ isOptional: true })
65
- },
66
- indexes: [
67
- index.on(["organizationId", "feature", "billingPeriod"]),
68
- index.on(["organizationId", "recordedAt"])
69
- ]
70
- });
71
- var UsageLimitEntity = defineEntity({
72
- name: "UsageLimit",
73
- description: "Usage limits per plan/organization.",
74
- schema: "saas_app",
75
- map: "usage_limit",
76
- fields: {
77
- id: field.id(),
78
- planId: field.string({
79
- isOptional: true,
80
- description: "Plan this limit applies to"
81
- }),
82
- organizationId: field.string({
83
- isOptional: true,
84
- description: "Org-specific override"
85
- }),
86
- feature: field.string({ description: "Feature being limited" }),
87
- limit: field.int({ description: "Maximum allowed usage" }),
88
- resetPeriod: field.string({
89
- default: '"monthly"',
90
- description: "When limit resets"
91
- }),
92
- isSoftLimit: field.boolean({
93
- default: false,
94
- description: "Whether to warn vs block"
95
- }),
96
- overage: field.boolean({
97
- default: false,
98
- description: "Whether overage is allowed"
99
- }),
100
- overageRate: field.float({
101
- isOptional: true,
102
- description: "Cost per unit over limit"
103
- }),
104
- createdAt: field.createdAt(),
105
- updatedAt: field.updatedAt()
106
- },
107
- indexes: [index.unique(["planId", "feature"])]
108
- });
109
-
110
- // src/billing/billing.enum.ts
111
- import { defineEnum } from "@contractspec/lib.schema";
112
- var SubscriptionStatusSchemaEnum = defineEnum("SubscriptionStatus", [
113
- "TRIALING",
114
- "ACTIVE",
115
- "PAST_DUE",
116
- "CANCELED",
117
- "PAUSED"
118
- ]);
119
- var FeatureAccessReasonEnum = defineEnum("FeatureAccessReason", [
120
- "included",
121
- "limit_available",
122
- "limit_reached",
123
- "not_in_plan"
124
- ]);
125
-
126
- // src/billing/billing.event.ts
127
- import { defineEvent } from "@contractspec/lib.contracts-spec";
128
- import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
129
- var UsageRecordedPayload = defineSchemaModel({
130
- name: "UsageRecordedPayload",
131
- description: "Payload when feature usage is recorded",
132
- fields: {
133
- organizationId: {
134
- type: ScalarTypeEnum.String_unsecure(),
135
- isOptional: false
136
- },
137
- feature: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
138
- quantity: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
139
- billingPeriod: {
140
- type: ScalarTypeEnum.String_unsecure(),
141
- isOptional: false
142
- },
143
- recordedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
144
- }
145
- });
146
- var UsageLimitReachedPayload = defineSchemaModel({
147
- name: "UsageLimitReachedPayload",
148
- description: "Payload when usage limit is reached",
149
- fields: {
150
- organizationId: {
151
- type: ScalarTypeEnum.String_unsecure(),
152
- isOptional: false
153
- },
154
- feature: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
155
- limit: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
156
- currentUsage: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
157
- reachedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
158
- }
159
- });
160
- var SubscriptionChangedPayload = defineSchemaModel({
161
- name: "SubscriptionChangedPayload",
162
- description: "Payload when subscription status changes",
163
- fields: {
164
- organizationId: {
165
- type: ScalarTypeEnum.String_unsecure(),
166
- isOptional: false
167
- },
168
- previousPlan: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
169
- newPlan: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
170
- previousStatus: {
171
- type: ScalarTypeEnum.String_unsecure(),
172
- isOptional: true
173
- },
174
- newStatus: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
175
- changedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
176
- }
177
- });
178
- var UsageRecordedEvent = defineEvent({
179
- meta: {
180
- key: "billing.usage.recorded",
181
- version: "1.0.0",
182
- description: "Feature usage has been recorded.",
183
- stability: "stable",
184
- owners: ["@saas-team"],
185
- tags: ["billing", "usage", "recorded"]
186
- },
187
- payload: UsageRecordedPayload
188
- });
189
- var UsageLimitReachedEvent = defineEvent({
190
- meta: {
191
- key: "billing.limit.reached",
192
- version: "1.0.0",
193
- description: "Usage limit has been reached for a feature.",
194
- stability: "stable",
195
- owners: ["@saas-team"],
196
- tags: ["billing", "limit", "reached"]
197
- },
198
- payload: UsageLimitReachedPayload
199
- });
200
- var SubscriptionChangedEvent = defineEvent({
201
- meta: {
202
- key: "billing.subscription.changed",
203
- version: "1.0.0",
204
- description: "Subscription status has changed.",
205
- stability: "stable",
206
- owners: ["@saas-team"],
207
- tags: ["billing", "subscription", "changed"]
208
- },
209
- payload: SubscriptionChangedPayload
210
- });
211
-
212
- // src/shared/mock-data.ts
213
- var MOCK_PROJECTS = [
214
- {
215
- id: "proj-1",
216
- name: "Marketing Website",
217
- description: "Main company website redesign project",
218
- slug: "marketing-website",
219
- organizationId: "demo-org",
220
- createdBy: "user-1",
221
- status: "ACTIVE",
222
- isPublic: false,
223
- tags: ["marketing", "website", "redesign"],
224
- createdAt: new Date("2024-01-15T10:00:00Z"),
225
- updatedAt: new Date("2024-03-20T14:30:00Z")
226
- },
227
- {
228
- id: "proj-2",
229
- name: "Mobile App v2",
230
- description: "Next generation mobile application",
231
- slug: "mobile-app-v2",
232
- organizationId: "demo-org",
233
- createdBy: "user-2",
234
- status: "ACTIVE",
235
- isPublic: false,
236
- tags: ["mobile", "app", "v2"],
237
- createdAt: new Date("2024-02-01T09:00:00Z"),
238
- updatedAt: new Date("2024-04-05T11:15:00Z")
239
- },
240
- {
241
- id: "proj-3",
242
- name: "API Integration",
243
- description: "Third-party API integration project",
244
- slug: "api-integration",
245
- organizationId: "demo-org",
246
- createdBy: "user-1",
247
- status: "DRAFT",
248
- isPublic: false,
249
- tags: ["api", "integration"],
250
- createdAt: new Date("2024-03-10T08:00:00Z"),
251
- updatedAt: new Date("2024-03-10T08:00:00Z")
252
- },
253
- {
254
- id: "proj-4",
255
- name: "Analytics Dashboard",
256
- description: "Internal analytics and reporting dashboard",
257
- slug: "analytics-dashboard",
258
- organizationId: "demo-org",
259
- createdBy: "user-3",
260
- status: "ARCHIVED",
261
- isPublic: true,
262
- tags: ["analytics", "dashboard", "reporting"],
263
- createdAt: new Date("2023-10-01T12:00:00Z"),
264
- updatedAt: new Date("2024-02-28T16:45:00Z")
265
- }
266
- ];
267
- var MOCK_SUBSCRIPTION = {
268
- id: "sub-1",
269
- organizationId: "demo-org",
270
- planId: "pro",
271
- planName: "Professional",
272
- status: "ACTIVE",
273
- currentPeriodStart: new Date("2024-04-01T00:00:00Z"),
274
- currentPeriodEnd: new Date("2024-05-01T00:00:00Z"),
275
- limits: {
276
- projects: 25,
277
- users: 10,
278
- storage: 50,
279
- apiCalls: 1e5
280
- },
281
- usage: {
282
- projects: 4,
283
- users: 5,
284
- storage: 12.5,
285
- apiCalls: 45230
286
- }
287
- };
288
- var MOCK_USAGE_SUMMARY = {
289
- organizationId: "demo-org",
290
- period: "current_month",
291
- apiCalls: {
292
- total: 45230,
293
- limit: 1e5,
294
- percentUsed: 45.23
295
- },
296
- storage: {
297
- totalGb: 12.5,
298
- limitGb: 50,
299
- percentUsed: 25
300
- },
301
- activeProjects: 4,
302
- activeUsers: 5,
303
- breakdown: [
304
- { date: "2024-04-01", apiCalls: 3200, storageGb: 12.1 },
305
- { date: "2024-04-02", apiCalls: 2800, storageGb: 12.2 },
306
- { date: "2024-04-03", apiCalls: 4100, storageGb: 12.3 },
307
- { date: "2024-04-04", apiCalls: 3600, storageGb: 12.4 },
308
- { date: "2024-04-05", apiCalls: 3800, storageGb: 12.5 }
309
- ]
310
- };
311
-
312
- // src/billing/billing.handler.ts
313
- async function mockGetSubscriptionHandler() {
314
- return MOCK_SUBSCRIPTION;
315
- }
316
- async function mockGetUsageSummaryHandler(input) {
317
- return {
318
- ...MOCK_USAGE_SUMMARY,
319
- period: input.period ?? "current_month"
320
- };
321
- }
322
- async function mockRecordUsageHandler(input) {
323
- const currentUsage = MOCK_USAGE_SUMMARY.apiCalls.total;
324
- const newTotal = currentUsage + input.quantity;
325
- return {
326
- recorded: true,
327
- newTotal
328
- };
329
- }
330
- async function mockCheckFeatureAccessHandler(input) {
331
- const { feature } = input;
332
- const featureMap = {
333
- custom_domains: {
334
- allowed: true
335
- },
336
- api_access: {
337
- allowed: true,
338
- currentUsage: MOCK_USAGE_SUMMARY.apiCalls.total,
339
- limit: MOCK_USAGE_SUMMARY.apiCalls.limit
340
- },
341
- advanced_analytics: {
342
- allowed: false,
343
- reason: "FEATURE_NOT_INCLUDED"
344
- },
345
- unlimited_projects: {
346
- allowed: false,
347
- reason: "PLAN_LIMIT",
348
- currentUsage: MOCK_SUBSCRIPTION.usage.projects,
349
- limit: MOCK_SUBSCRIPTION.limits.projects
350
- }
351
- };
352
- return featureMap[feature] ?? { allowed: true };
353
- }
354
-
355
- // src/billing/billing.schema.ts
356
- import { defineSchemaModel as defineSchemaModel2, ScalarTypeEnum as ScalarTypeEnum2 } from "@contractspec/lib.schema";
357
- var SubscriptionModel = defineSchemaModel2({
358
- name: "Subscription",
359
- description: "Organization subscription details",
360
- fields: {
361
- id: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
362
- organizationId: {
363
- type: ScalarTypeEnum2.String_unsecure(),
364
- isOptional: false
365
- },
366
- planId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
367
- planName: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
368
- status: { type: SubscriptionStatusSchemaEnum, isOptional: false },
369
- currentPeriodStart: { type: ScalarTypeEnum2.DateTime(), isOptional: false },
370
- currentPeriodEnd: { type: ScalarTypeEnum2.DateTime(), isOptional: false },
371
- trialEndsAt: { type: ScalarTypeEnum2.DateTime(), isOptional: true },
372
- cancelAtPeriodEnd: { type: ScalarTypeEnum2.Boolean(), isOptional: false }
373
- }
374
- });
375
- var UsageSummaryModel = defineSchemaModel2({
376
- name: "UsageSummary",
377
- description: "Usage summary for a feature",
378
- fields: {
379
- feature: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
380
- used: { type: ScalarTypeEnum2.Int_unsecure(), isOptional: false },
381
- limit: { type: ScalarTypeEnum2.Int_unsecure(), isOptional: true },
382
- unit: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
383
- percentage: { type: ScalarTypeEnum2.Float_unsecure(), isOptional: true }
384
- }
385
- });
386
- var RecordUsageInputModel = defineSchemaModel2({
387
- name: "RecordUsageInput",
388
- description: "Input for recording feature usage",
389
- fields: {
390
- feature: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
391
- quantity: { type: ScalarTypeEnum2.Int_unsecure(), isOptional: false },
392
- sourceId: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
393
- sourceType: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true },
394
- metadata: { type: ScalarTypeEnum2.JSONObject(), isOptional: true }
395
- }
396
- });
397
- var RecordUsageOutputModel = defineSchemaModel2({
398
- name: "RecordUsageOutput",
399
- description: "Output for recording feature usage",
400
- fields: {
401
- recorded: { type: ScalarTypeEnum2.Boolean(), isOptional: false },
402
- currentUsage: { type: ScalarTypeEnum2.Int_unsecure(), isOptional: false },
403
- limit: { type: ScalarTypeEnum2.Int_unsecure(), isOptional: true },
404
- limitReached: { type: ScalarTypeEnum2.Boolean(), isOptional: false }
405
- }
406
- });
407
- var UsageRecordedPayloadModel = defineSchemaModel2({
408
- name: "UsageRecordedPayload",
409
- description: "Payload for usage.recorded event",
410
- fields: {
411
- feature: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false },
412
- quantity: { type: ScalarTypeEnum2.Int_unsecure(), isOptional: false }
413
- }
414
- });
415
- var GetUsageSummaryInputModel = defineSchemaModel2({
416
- name: "GetUsageSummaryInput",
417
- description: "Input for getting usage summary",
418
- fields: {
419
- billingPeriod: { type: ScalarTypeEnum2.String_unsecure(), isOptional: true }
420
- }
421
- });
422
- var GetUsageSummaryOutputModel = defineSchemaModel2({
423
- name: "GetUsageSummaryOutput",
424
- description: "Output for usage summary",
425
- fields: {
426
- billingPeriod: {
427
- type: ScalarTypeEnum2.String_unsecure(),
428
- isOptional: false
429
- },
430
- usage: { type: UsageSummaryModel, isArray: true, isOptional: false }
431
- }
432
- });
433
- var CheckFeatureAccessInputModel = defineSchemaModel2({
434
- name: "CheckFeatureAccessInput",
435
- description: "Input for checking feature access",
436
- fields: {
437
- feature: { type: ScalarTypeEnum2.String_unsecure(), isOptional: false }
438
- }
439
- });
440
- var CheckFeatureAccessOutputModel = defineSchemaModel2({
441
- name: "CheckFeatureAccessOutput",
442
- description: "Output for feature access check",
443
- fields: {
444
- hasAccess: { type: ScalarTypeEnum2.Boolean(), isOptional: false },
445
- reason: { type: FeatureAccessReasonEnum, isOptional: true },
446
- upgradeUrl: { type: ScalarTypeEnum2.URL(), isOptional: true }
447
- }
448
- });
449
-
450
- // src/billing/billing.operations.ts
451
- import { defineCommand, defineQuery } from "@contractspec/lib.contracts-spec";
452
- var OWNERS = ["@example.saas-boilerplate"];
453
- var GetSubscriptionContract = defineQuery({
454
- meta: {
455
- key: "saas.billing.subscription.get",
456
- version: "1.0.0",
457
- stability: "stable",
458
- owners: [...OWNERS],
459
- tags: ["saas", "billing", "subscription"],
460
- description: "Get organization subscription status.",
461
- goal: "Show current plan and billing status.",
462
- context: "Billing page, plan upgrade prompts."
463
- },
464
- io: {
465
- input: null,
466
- output: SubscriptionModel
467
- },
468
- policy: {
469
- auth: "user"
470
- },
471
- acceptance: {
472
- scenarios: [
473
- {
474
- key: "get-subscription-happy-path",
475
- given: ["Organization has active subscription"],
476
- when: ["User requests subscription status"],
477
- then: ["Subscription details are returned"]
478
- }
479
- ],
480
- examples: [
481
- {
482
- key: "get-basic",
483
- input: null,
484
- output: {
485
- plan: "pro",
486
- status: "active",
487
- currentPeriodEnd: "2025-02-01T00:00:00Z"
488
- }
489
- }
490
- ]
491
- }
492
- });
493
- var RecordUsageContract = defineCommand({
494
- meta: {
495
- key: "saas.billing.usage.record",
496
- version: "1.0.0",
497
- stability: "stable",
498
- owners: [...OWNERS],
499
- tags: ["saas", "billing", "usage"],
500
- description: "Record usage of a metered feature.",
501
- goal: "Track feature usage for billing.",
502
- context: "Called by services when metered features are used."
503
- },
504
- io: {
505
- input: RecordUsageInputModel,
506
- output: RecordUsageOutputModel
507
- },
508
- policy: {
509
- auth: "user"
510
- },
511
- sideEffects: {
512
- emits: [
513
- {
514
- key: "billing.usage.recorded",
515
- version: "1.0.0",
516
- when: "Usage is recorded",
517
- payload: UsageRecordedPayloadModel
518
- }
519
- ]
520
- },
521
- acceptance: {
522
- scenarios: [
523
- {
524
- key: "record-usage-happy-path",
525
- given: ["Organization exists"],
526
- when: ["System records feature usage"],
527
- then: ["Usage is recorded"]
528
- }
529
- ],
530
- examples: [
531
- {
532
- key: "record-api-call",
533
- input: { feature: "api_calls", quantity: 1, idempotencyKey: "abc-123" },
534
- output: { recorded: true, currentUsage: 100 }
535
- }
536
- ]
537
- }
538
- });
539
- var GetUsageSummaryContract = defineQuery({
540
- meta: {
541
- key: "saas.billing.usage.summary",
542
- version: "1.0.0",
543
- stability: "stable",
544
- owners: [...OWNERS],
545
- tags: ["saas", "billing", "usage"],
546
- description: "Get usage summary for the current billing period.",
547
- goal: "Show usage vs limits.",
548
- context: "Billing page, usage dashboards."
549
- },
550
- io: {
551
- input: GetUsageSummaryInputModel,
552
- output: GetUsageSummaryOutputModel
553
- },
554
- policy: {
555
- auth: "user"
556
- },
557
- acceptance: {
558
- scenarios: [
559
- {
560
- key: "get-usage-happy-path",
561
- given: ["Organization has usage history"],
562
- when: ["User requests usage summary"],
563
- then: ["Usage metrics are returned"]
564
- }
565
- ],
566
- examples: [
567
- {
568
- key: "get-current-usage",
569
- input: { period: "current" },
570
- output: { features: [{ name: "api_calls", used: 100, limit: 1000 }] }
571
- }
572
- ]
573
- }
574
- });
575
- var CheckFeatureAccessContract = defineQuery({
576
- meta: {
577
- key: "saas.billing.feature.check",
578
- version: "1.0.0",
579
- stability: "stable",
580
- owners: [...OWNERS],
581
- tags: ["saas", "billing", "feature"],
582
- description: "Check if organization has access to a feature.",
583
- goal: "Gate features based on plan/usage.",
584
- context: "Feature access checks, upgrade prompts."
585
- },
586
- io: {
587
- input: CheckFeatureAccessInputModel,
588
- output: CheckFeatureAccessOutputModel
589
- },
590
- policy: {
591
- auth: "user"
592
- },
593
- acceptance: {
594
- scenarios: [
595
- {
596
- key: "check-access-granted",
597
- given: ["Organization is on Pro plan"],
598
- when: ["User checks access to Pro feature"],
599
- then: ["Access is granted"]
600
- }
601
- ],
602
- examples: [
603
- {
604
- key: "check-advanced-reports",
605
- input: { feature: "advanced_reports" },
606
- output: { hasAccess: true, reason: "Included in Pro plan" }
607
- }
608
- ]
609
- }
610
- });
611
-
612
- // src/billing/billing.presentation.ts
613
- import {
614
- definePresentation,
615
- StabilityEnum
616
- } from "@contractspec/lib.contracts-spec";
617
- var SubscriptionPresentation = definePresentation({
618
- meta: {
619
- key: "saas.billing.subscription",
620
- version: "1.0.0",
621
- title: "Subscription Status",
622
- description: "Subscription status with plan info, limits, and current usage",
623
- domain: "saas-boilerplate",
624
- owners: ["@saas-team"],
625
- tags: ["billing", "subscription"],
626
- stability: StabilityEnum.Beta,
627
- goal: "View subscription plan and status",
628
- context: "Billing section"
629
- },
630
- source: {
631
- type: "component",
632
- framework: "react",
633
- componentKey: "SubscriptionView"
634
- },
635
- targets: ["react", "markdown"],
636
- policy: {
637
- flags: ["saas.billing.enabled"]
638
- }
639
- });
640
- var UsageDashboardPresentation = definePresentation({
641
- meta: {
642
- key: "saas.billing.usage",
643
- version: "1.0.0",
644
- title: "Usage Dashboard",
645
- description: "Usage metrics and breakdown by resource type",
646
- domain: "saas-boilerplate",
647
- owners: ["@saas-team"],
648
- tags: ["billing", "usage", "metrics"],
649
- stability: StabilityEnum.Beta,
650
- goal: "Monitor feature usage and limits",
651
- context: "Billing section"
652
- },
653
- source: {
654
- type: "component",
655
- framework: "react",
656
- componentKey: "UsageDashboardView"
657
- },
658
- targets: ["react", "markdown"],
659
- policy: {
660
- flags: ["saas.billing.enabled"]
661
- }
662
- });
663
- export {
664
- mockRecordUsageHandler,
665
- mockGetUsageSummaryHandler,
666
- mockGetSubscriptionHandler,
667
- mockCheckFeatureAccessHandler,
668
- UsageSummaryModel,
669
- UsageRecordedPayloadModel,
670
- UsageRecordedEvent,
671
- UsageLimitReachedEvent,
672
- UsageLimitEntity,
673
- UsageDashboardPresentation,
674
- SubscriptionStatusSchemaEnum,
675
- SubscriptionStatusEnum,
676
- SubscriptionPresentation,
677
- SubscriptionModel,
678
- SubscriptionEntity,
679
- SubscriptionChangedEvent,
680
- RecordUsageOutputModel,
681
- RecordUsageInputModel,
682
- RecordUsageContract,
683
- GetUsageSummaryOutputModel,
684
- GetUsageSummaryInputModel,
685
- GetUsageSummaryContract,
686
- GetSubscriptionContract,
687
- FeatureAccessReasonEnum,
688
- CheckFeatureAccessOutputModel,
689
- CheckFeatureAccessInputModel,
690
- CheckFeatureAccessContract,
691
- BillingUsageEntity
692
- };
2
+ import{defineEntity as z,defineEntityEnum as K,field as g,index as w}from"@contractspec/lib.schema";var U=K({name:"SubscriptionStatus",values:["TRIALING","ACTIVE","PAST_DUE","CANCELED","PAUSED"],schema:"saas_app",description:"Status of a subscription."}),N=z({name:"Subscription",description:"Organization subscription/plan information.",schema:"saas_app",map:"subscription",fields:{id:g.id(),organizationId:g.foreignKey({isUnique:!0}),planId:g.string({description:"Plan identifier"}),planName:g.string({description:"Plan display name"}),status:g.enum("SubscriptionStatus"),currentPeriodStart:g.dateTime(),currentPeriodEnd:g.dateTime(),trialEndsAt:g.dateTime({isOptional:!0}),cancelAtPeriodEnd:g.boolean({default:!1}),canceledAt:g.dateTime({isOptional:!0}),stripeSubscriptionId:g.string({isOptional:!0}),stripeCustomerId:g.string({isOptional:!0}),metadata:g.json({isOptional:!0}),createdAt:g.createdAt(),updatedAt:g.updatedAt()},enums:[U]}),t=z({name:"BillingUsage",description:"Track usage of metered features.",schema:"saas_app",map:"billing_usage",fields:{id:g.id(),organizationId:g.foreignKey(),feature:g.string({description:'Feature being tracked (e.g., "api_calls", "storage_gb")'}),quantity:g.int({description:"Usage quantity"}),unit:g.string({isOptional:!0,description:"Unit of measurement"}),billingPeriod:g.string({description:'Billing period (e.g., "2024-01")'}),recordedAt:g.dateTime({description:"When usage was recorded"}),sourceId:g.string({isOptional:!0,description:"Source of usage (e.g., request ID)"}),sourceType:g.string({isOptional:!0}),metadata:g.json({isOptional:!0})},indexes:[w.on(["organizationId","feature","billingPeriod"]),w.on(["organizationId","recordedAt"])]}),R=z({name:"UsageLimit",description:"Usage limits per plan/organization.",schema:"saas_app",map:"usage_limit",fields:{id:g.id(),planId:g.string({isOptional:!0,description:"Plan this limit applies to"}),organizationId:g.string({isOptional:!0,description:"Org-specific override"}),feature:g.string({description:"Feature being limited"}),limit:g.int({description:"Maximum allowed usage"}),resetPeriod:g.string({default:'"monthly"',description:"When limit resets"}),isSoftLimit:g.boolean({default:!1,description:"Whether to warn vs block"}),overage:g.boolean({default:!1,description:"Whether overage is allowed"}),overageRate:g.float({isOptional:!0,description:"Cost per unit over limit"}),createdAt:g.createdAt(),updatedAt:g.updatedAt()},indexes:[w.unique(["planId","feature"])]});import{defineEnum as W}from"@contractspec/lib.schema";var D=W("SubscriptionStatus",["TRIALING","ACTIVE","PAST_DUE","CANCELED","PAUSED"]),G=W("FeatureAccessReason",["included","limit_available","limit_reached","not_in_plan"]);import{defineEvent as J}from"@contractspec/lib.contracts-spec";import{defineSchemaModel as V,ScalarTypeEnum as x}from"@contractspec/lib.schema";var _=V({name:"UsageRecordedPayload",description:"Payload when feature usage is recorded",fields:{organizationId:{type:x.String_unsecure(),isOptional:!1},feature:{type:x.String_unsecure(),isOptional:!1},quantity:{type:x.Int_unsecure(),isOptional:!1},billingPeriod:{type:x.String_unsecure(),isOptional:!1},recordedAt:{type:x.DateTime(),isOptional:!1}}}),O=V({name:"UsageLimitReachedPayload",description:"Payload when usage limit is reached",fields:{organizationId:{type:x.String_unsecure(),isOptional:!1},feature:{type:x.String_unsecure(),isOptional:!1},limit:{type:x.Int_unsecure(),isOptional:!1},currentUsage:{type:x.Int_unsecure(),isOptional:!1},reachedAt:{type:x.DateTime(),isOptional:!1}}}),h=V({name:"SubscriptionChangedPayload",description:"Payload when subscription status changes",fields:{organizationId:{type:x.String_unsecure(),isOptional:!1},previousPlan:{type:x.String_unsecure(),isOptional:!0},newPlan:{type:x.String_unsecure(),isOptional:!1},previousStatus:{type:x.String_unsecure(),isOptional:!0},newStatus:{type:x.String_unsecure(),isOptional:!1},changedAt:{type:x.DateTime(),isOptional:!1}}}),M=J({meta:{key:"billing.usage.recorded",version:"1.0.0",description:"Feature usage has been recorded.",stability:"stable",owners:["@saas-team"],tags:["billing","usage","recorded"]},payload:_}),r=J({meta:{key:"billing.limit.reached",version:"1.0.0",description:"Usage limit has been reached for a feature.",stability:"stable",owners:["@saas-team"],tags:["billing","limit","reached"]},payload:O}),p=J({meta:{key:"billing.subscription.changed",version:"1.0.0",description:"Subscription status has changed.",stability:"stable",owners:["@saas-team"],tags:["billing","subscription","changed"]},payload:h});var Fg=[{id:"proj-1",name:"Marketing Website",description:"Main company website redesign project",slug:"marketing-website",organizationId:"demo-org",createdBy:"user-1",status:"ACTIVE",isPublic:!1,tags:["marketing","website","redesign"],createdAt:new Date("2024-01-15T10:00:00Z"),updatedAt:new Date("2024-03-20T14:30:00Z")},{id:"proj-2",name:"Mobile App v2",description:"Next generation mobile application",slug:"mobile-app-v2",organizationId:"demo-org",createdBy:"user-2",status:"ACTIVE",isPublic:!1,tags:["mobile","app","v2"],createdAt:new Date("2024-02-01T09:00:00Z"),updatedAt:new Date("2024-04-05T11:15:00Z")},{id:"proj-3",name:"API Integration",description:"Third-party API integration project",slug:"api-integration",organizationId:"demo-org",createdBy:"user-1",status:"DRAFT",isPublic:!1,tags:["api","integration"],createdAt:new Date("2024-03-10T08:00:00Z"),updatedAt:new Date("2024-03-10T08:00:00Z")},{id:"proj-4",name:"Analytics Dashboard",description:"Internal analytics and reporting dashboard",slug:"analytics-dashboard",organizationId:"demo-org",createdBy:"user-3",status:"ARCHIVED",isPublic:!0,tags:["analytics","dashboard","reporting"],createdAt:new Date("2023-10-01T12:00:00Z"),updatedAt:new Date("2024-02-28T16:45:00Z")}],j={id:"sub-1",organizationId:"demo-org",planId:"pro",planName:"Professional",status:"ACTIVE",currentPeriodStart:new Date("2024-04-01T00:00:00Z"),currentPeriodEnd:new Date("2024-05-01T00:00:00Z"),limits:{projects:25,users:10,storage:50,apiCalls:1e5},usage:{projects:4,users:5,storage:12.5,apiCalls:45230}},F={organizationId:"demo-org",period:"current_month",apiCalls:{total:45230,limit:1e5,percentUsed:45.23},storage:{totalGb:12.5,limitGb:50,percentUsed:25},activeProjects:4,activeUsers:5,breakdown:[{date:"2024-04-01",apiCalls:3200,storageGb:12.1},{date:"2024-04-02",apiCalls:2800,storageGb:12.2},{date:"2024-04-03",apiCalls:4100,storageGb:12.3},{date:"2024-04-04",apiCalls:3600,storageGb:12.4},{date:"2024-04-05",apiCalls:3800,storageGb:12.5}]};async function y(){return j}async function T(q){return{...F,period:q.period??"current_month"}}async function u(q){return{recorded:!0,newTotal:F.apiCalls.total+q.quantity}}async function E(q){let{feature:I}=q;return{custom_domains:{allowed:!0},api_access:{allowed:!0,currentUsage:F.apiCalls.total,limit:F.apiCalls.limit},advanced_analytics:{allowed:!1,reason:"FEATURE_NOT_INCLUDED"},unlimited_projects:{allowed:!1,reason:"PLAN_LIMIT",currentUsage:j.usage.projects,limit:j.limits.projects}}[I]??{allowed:!0}}import{defineSchemaModel as H,ScalarTypeEnum as k}from"@contractspec/lib.schema";var X=H({name:"Subscription",description:"Organization subscription details",fields:{id:{type:k.String_unsecure(),isOptional:!1},organizationId:{type:k.String_unsecure(),isOptional:!1},planId:{type:k.String_unsecure(),isOptional:!1},planName:{type:k.String_unsecure(),isOptional:!1},status:{type:D,isOptional:!1},currentPeriodStart:{type:k.DateTime(),isOptional:!1},currentPeriodEnd:{type:k.DateTime(),isOptional:!1},trialEndsAt:{type:k.DateTime(),isOptional:!0},cancelAtPeriodEnd:{type:k.Boolean(),isOptional:!1}}}),Y=H({name:"UsageSummary",description:"Usage summary for a feature",fields:{feature:{type:k.String_unsecure(),isOptional:!1},used:{type:k.Int_unsecure(),isOptional:!1},limit:{type:k.Int_unsecure(),isOptional:!0},unit:{type:k.String_unsecure(),isOptional:!0},percentage:{type:k.Float_unsecure(),isOptional:!0}}}),Z=H({name:"RecordUsageInput",description:"Input for recording feature usage",fields:{feature:{type:k.String_unsecure(),isOptional:!1},quantity:{type:k.Int_unsecure(),isOptional:!1},sourceId:{type:k.String_unsecure(),isOptional:!0},sourceType:{type:k.String_unsecure(),isOptional:!0},metadata:{type:k.JSONObject(),isOptional:!0}}}),$=H({name:"RecordUsageOutput",description:"Output for recording feature usage",fields:{recorded:{type:k.Boolean(),isOptional:!1},currentUsage:{type:k.Int_unsecure(),isOptional:!1},limit:{type:k.Int_unsecure(),isOptional:!0},limitReached:{type:k.Boolean(),isOptional:!1}}}),B=H({name:"UsageRecordedPayload",description:"Payload for usage.recorded event",fields:{feature:{type:k.String_unsecure(),isOptional:!1},quantity:{type:k.Int_unsecure(),isOptional:!1}}}),L=H({name:"GetUsageSummaryInput",description:"Input for getting usage summary",fields:{billingPeriod:{type:k.String_unsecure(),isOptional:!0}}}),o=H({name:"GetUsageSummaryOutput",description:"Output for usage summary",fields:{billingPeriod:{type:k.String_unsecure(),isOptional:!1},usage:{type:Y,isArray:!0,isOptional:!1}}}),s=H({name:"CheckFeatureAccessInput",description:"Input for checking feature access",fields:{feature:{type:k.String_unsecure(),isOptional:!1}}}),Q=H({name:"CheckFeatureAccessOutput",description:"Output for feature access check",fields:{hasAccess:{type:k.Boolean(),isOptional:!1},reason:{type:G,isOptional:!0},upgradeUrl:{type:k.URL(),isOptional:!0}}});import{defineCommand as f,defineQuery as b}from"@contractspec/lib.contracts-spec";var v=["@example.saas-boilerplate"],m=b({meta:{key:"saas.billing.subscription.get",version:"1.0.0",stability:"stable",owners:[...v],tags:["saas","billing","subscription"],description:"Get organization subscription status.",goal:"Show current plan and billing status.",context:"Billing page, plan upgrade prompts."},io:{input:null,output:X},policy:{auth:"user"},acceptance:{scenarios:[{key:"get-subscription-happy-path",given:["Organization has active subscription"],when:["User requests subscription status"],then:["Subscription details are returned"]}],examples:[{key:"get-basic",input:null,output:{plan:"pro",status:"active",currentPeriodEnd:"2025-02-01T00:00:00Z"}}]}}),S=f({meta:{key:"saas.billing.usage.record",version:"1.0.0",stability:"stable",owners:[...v],tags:["saas","billing","usage"],description:"Record usage of a metered feature.",goal:"Track feature usage for billing.",context:"Called by services when metered features are used."},io:{input:Z,output:$},policy:{auth:"user"},sideEffects:{emits:[{key:"billing.usage.recorded",version:"1.0.0",when:"Usage is recorded",payload:B}]},acceptance:{scenarios:[{key:"record-usage-happy-path",given:["Organization exists"],when:["System records feature usage"],then:["Usage is recorded"]}],examples:[{key:"record-api-call",input:{feature:"api_calls",quantity:1,idempotencyKey:"abc-123"},output:{recorded:!0,currentUsage:100}}]}}),c=b({meta:{key:"saas.billing.usage.summary",version:"1.0.0",stability:"stable",owners:[...v],tags:["saas","billing","usage"],description:"Get usage summary for the current billing period.",goal:"Show usage vs limits.",context:"Billing page, usage dashboards."},io:{input:L,output:o},policy:{auth:"user"},acceptance:{scenarios:[{key:"get-usage-happy-path",given:["Organization has usage history"],when:["User requests usage summary"],then:["Usage metrics are returned"]}],examples:[{key:"get-current-usage",input:{period:"current"},output:{features:[{name:"api_calls",used:100,limit:1000}]}}]}}),d=b({meta:{key:"saas.billing.feature.check",version:"1.0.0",stability:"stable",owners:[...v],tags:["saas","billing","feature"],description:"Check if organization has access to a feature.",goal:"Gate features based on plan/usage.",context:"Feature access checks, upgrade prompts."},io:{input:s,output:Q},policy:{auth:"user"},acceptance:{scenarios:[{key:"check-access-granted",given:["Organization is on Pro plan"],when:["User checks access to Pro feature"],then:["Access is granted"]}],examples:[{key:"check-advanced-reports",input:{feature:"advanced_reports"},output:{hasAccess:!0,reason:"Included in Pro plan"}}]}});import{definePresentation as A,StabilityEnum as C}from"@contractspec/lib.contracts-spec";var i=A({meta:{key:"saas.billing.subscription",version:"1.0.0",title:"Subscription Status",description:"Subscription status with plan info, limits, and current usage",domain:"saas-boilerplate",owners:["@saas-team"],tags:["billing","subscription"],stability:C.Beta,goal:"View subscription plan and status",context:"Billing section"},source:{type:"component",framework:"react",componentKey:"SubscriptionView"},targets:["react","markdown"],policy:{flags:["saas.billing.enabled"]}}),n=A({meta:{key:"saas.billing.usage",version:"1.0.0",title:"Usage Dashboard",description:"Usage metrics and breakdown by resource type",domain:"saas-boilerplate",owners:["@saas-team"],tags:["billing","usage","metrics"],stability:C.Beta,goal:"Monitor feature usage and limits",context:"Billing section"},source:{type:"component",framework:"react",componentKey:"UsageDashboardView"},targets:["react","markdown"],policy:{flags:["saas.billing.enabled"]}});export{u as mockRecordUsageHandler,T as mockGetUsageSummaryHandler,y as mockGetSubscriptionHandler,E as mockCheckFeatureAccessHandler,Y as UsageSummaryModel,B as UsageRecordedPayloadModel,M as UsageRecordedEvent,r as UsageLimitReachedEvent,R as UsageLimitEntity,n as UsageDashboardPresentation,D as SubscriptionStatusSchemaEnum,U as SubscriptionStatusEnum,i as SubscriptionPresentation,X as SubscriptionModel,N as SubscriptionEntity,p as SubscriptionChangedEvent,$ as RecordUsageOutputModel,Z as RecordUsageInputModel,S as RecordUsageContract,o as GetUsageSummaryOutputModel,L as GetUsageSummaryInputModel,c as GetUsageSummaryContract,m as GetSubscriptionContract,G as FeatureAccessReasonEnum,Q as CheckFeatureAccessOutputModel,s as CheckFeatureAccessInputModel,d as CheckFeatureAccessContract,t as BillingUsageEntity};