alepha 0.19.2 → 0.19.4
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/assets/swagger-ui/swagger-ui-bundle.js +1 -1
- package/dist/api/audits/index.d.ts +8 -8
- package/dist/api/invitations/index.d.ts +790 -0
- package/dist/api/invitations/index.d.ts.map +1 -0
- package/dist/api/invitations/index.js +665 -0
- package/dist/api/invitations/index.js.map +1 -0
- package/dist/api/jobs/index.browser.js +8 -9
- package/dist/api/jobs/index.browser.js.map +1 -1
- package/dist/api/jobs/index.d.ts +90 -34
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +267 -44
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/notifications/index.browser.js +0 -1
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +3 -3
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +0 -1
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.browser.js +112 -1
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +90 -3
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +79 -12
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/{billing → api/payments}/index.d.ts +67 -49
- package/dist/api/payments/index.d.ts.map +1 -0
- package/dist/{billing → api/payments}/index.js +108 -74
- package/dist/api/payments/index.js.map +1 -0
- package/dist/api/subscriptions/index.d.ts +1692 -0
- package/dist/api/subscriptions/index.d.ts.map +1 -0
- package/dist/api/subscriptions/index.js +1870 -0
- package/dist/api/subscriptions/index.js.map +1 -0
- package/dist/api/users/index.d.ts +27 -21
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +167 -34
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/workflows/index.browser.js +246 -0
- package/dist/api/workflows/index.browser.js.map +1 -0
- package/dist/api/workflows/index.d.ts +1618 -0
- package/dist/api/workflows/index.d.ts.map +1 -0
- package/dist/api/workflows/index.js +1504 -0
- package/dist/api/workflows/index.js.map +1 -0
- package/dist/cli/config/index.d.ts +6 -28
- package/dist/cli/config/index.d.ts.map +1 -1
- package/dist/cli/config/index.js +5 -10
- package/dist/cli/config/index.js.map +1 -1
- package/dist/cli/core/index.d.ts +11669 -208
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +60 -69
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/devtools/index.d.ts +5 -0
- package/dist/cli/devtools/index.d.ts.map +1 -1
- package/dist/cli/devtools/index.js +4 -0
- package/dist/cli/devtools/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +69 -64
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +6 -2
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/vendor/index.d.ts +38 -10
- package/dist/cli/vendor/index.d.ts.map +1 -1
- package/dist/cli/vendor/index.js +85 -26
- package/dist/cli/vendor/index.js.map +1 -1
- package/dist/core/index.browser.js +21 -2
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +33 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +25 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +25 -2
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +25 -2
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/email/smtp/index.js +24 -8
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +1 -1
- package/dist/logger/index.js.map +1 -1
- package/dist/orm/core/index.browser.js +0 -18
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +25 -73
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +10 -32
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +25 -73
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.bun.js +3 -3
- package/dist/orm/postgres/index.bun.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +2 -1
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/orm/postgres/index.js +3 -3
- package/dist/orm/postgres/index.js.map +1 -1
- package/dist/react/router/index.browser.js +25 -3
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +16 -1
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +25 -3
- package/dist/react/router/index.js.map +1 -1
- package/dist/security/index.d.ts +28 -0
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +28 -0
- package/dist/security/index.js.map +1 -1
- package/package.json +37 -20
- package/src/api/invitations/__tests__/InvitationService.spec.ts +439 -0
- package/src/api/invitations/controllers/AdminInvitationController.ts +86 -0
- package/src/api/invitations/controllers/InvitationController.ts +84 -0
- package/src/api/invitations/entities/invitations.ts +33 -0
- package/src/api/invitations/index.ts +65 -0
- package/src/api/invitations/jobs/InvitationJobs.ts +37 -0
- package/src/api/invitations/providers/InvitationProvider.ts +45 -0
- package/src/api/invitations/schemas/createInvitationSchema.ts +12 -0
- package/src/api/invitations/schemas/invitationConfigAtom.ts +20 -0
- package/src/api/invitations/schemas/invitationQuerySchema.ts +15 -0
- package/src/api/invitations/schemas/invitationResourceSchema.ts +6 -0
- package/src/api/invitations/schemas/invitationWithResourceInfoSchema.ts +22 -0
- package/src/api/invitations/schemas/myInvitationsQuerySchema.ts +10 -0
- package/src/api/invitations/services/InvitationService.ts +556 -0
- package/src/api/jobs/__tests__/$job.spec.ts +876 -0
- package/src/api/jobs/controllers/AdminJobController.ts +44 -0
- package/src/api/jobs/entities/jobExecutionEntity.ts +0 -2
- package/src/api/jobs/index.ts +0 -3
- package/src/api/jobs/primitives/$job.ts +22 -11
- package/src/api/jobs/providers/JobProvider.ts +239 -25
- package/src/api/jobs/schemas/jobConfigAtom.ts +4 -0
- package/src/api/jobs/schemas/jobCronInfoSchema.ts +1 -0
- package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +0 -1
- package/src/api/jobs/schemas/jobQueueDepthSchema.ts +1 -0
- package/src/api/jobs/schemas/jobRegistrationSchema.ts +1 -6
- package/src/api/jobs/services/JobService.ts +51 -12
- package/src/api/notifications/schemas/notificationQuerySchema.ts +0 -1
- package/src/api/parameters/__tests__/$parameter.spec.ts +327 -0
- package/src/api/parameters/controllers/AdminParameterController.ts +29 -3
- package/src/api/parameters/index.browser.ts +12 -0
- package/src/api/parameters/primitives/$parameter.ts +20 -3
- package/src/api/parameters/services/ParameterProvider.ts +48 -7
- package/src/{billing → api/payments}/__tests__/PaymentMethodService.spec.ts +32 -6
- package/src/api/payments/__tests__/PaymentService.spec.ts +279 -0
- package/src/{billing/controllers/AdminBillingController.ts → api/payments/controllers/AdminPaymentController.ts} +26 -21
- package/src/{billing/controllers/BillingController.ts → api/payments/controllers/PaymentController.ts} +23 -11
- package/src/{billing → api/payments}/entities/paymentIntents.ts +1 -0
- package/src/{billing/errors/BillingError.ts → api/payments/errors/PaymentError.ts} +1 -1
- package/src/{billing → api/payments}/index.ts +31 -25
- package/src/{billing/providers/MemoryBillingProvider.ts → api/payments/providers/MemoryPaymentProvider.ts} +4 -4
- package/src/{billing/providers/BillingProvider.ts → api/payments/providers/PaymentProvider.ts} +9 -2
- package/src/{billing → api/payments}/services/PaymentMethodService.ts +5 -5
- package/src/{billing/services/BillingService.ts → api/payments/services/PaymentService.ts} +94 -18
- package/src/api/subscriptions/__tests__/BillingService.spec.ts +218 -0
- package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +278 -0
- package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +212 -0
- package/src/api/subscriptions/controllers/SubscriptionController.ts +189 -0
- package/src/api/subscriptions/entities/subscriptionEvents.ts +54 -0
- package/src/api/subscriptions/entities/subscriptions.ts +68 -0
- package/src/api/subscriptions/index.ts +144 -0
- package/src/api/subscriptions/jobs/SubscriptionJobs.ts +382 -0
- package/src/api/subscriptions/middleware/$requireLimit.ts +50 -0
- package/src/api/subscriptions/middleware/$requirePlan.ts +49 -0
- package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +110 -0
- package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +8 -0
- package/src/api/subscriptions/schemas/changePlanSchema.ts +9 -0
- package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +11 -0
- package/src/api/subscriptions/schemas/entitlementsSchema.ts +21 -0
- package/src/api/subscriptions/schemas/mrrSchema.ts +13 -0
- package/src/api/subscriptions/schemas/planDefinitionSchema.ts +71 -0
- package/src/api/subscriptions/schemas/planResourceSchema.ts +25 -0
- package/src/api/subscriptions/schemas/subscriptionEventResourceSchema.ts +8 -0
- package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +19 -0
- package/src/api/subscriptions/schemas/subscriptionResourceSchema.ts +6 -0
- package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +32 -0
- package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +23 -0
- package/src/api/subscriptions/services/BillingService.ts +437 -0
- package/src/api/subscriptions/services/SubscriptionConfig.ts +56 -0
- package/src/api/subscriptions/services/SubscriptionService.ts +867 -0
- package/src/api/subscriptions/services/UsageService.ts +118 -0
- package/src/api/users/__tests__/AdminUserController.spec.ts +80 -1
- package/src/api/users/__tests__/CredentialService.spec.ts +177 -0
- package/src/api/users/__tests__/EmailVerification.spec.ts +29 -18
- package/src/api/users/__tests__/PasswordReset.spec.ts +3 -0
- package/src/api/users/__tests__/RegistrationService.spec.ts +148 -1
- package/src/api/users/__tests__/SessionService.spec.ts +142 -1
- package/src/api/users/atoms/realmAuthSettingsAtom.ts +10 -1
- package/src/api/users/controllers/UserController.ts +3 -8
- package/src/api/users/notifications/UserNotifications.ts +23 -0
- package/src/api/users/schemas/loginSchema.ts +1 -1
- package/src/api/users/services/CredentialService.ts +51 -4
- package/src/api/users/services/RegistrationService.ts +38 -9
- package/src/api/users/services/SessionService.ts +62 -9
- package/src/api/users/services/UserService.ts +21 -12
- package/src/api/workflows/__tests__/$workflow.spec.ts +616 -0
- package/src/api/workflows/controllers/AdminWorkflowController.ts +191 -0
- package/src/api/workflows/entities/workflowExecutions.ts +74 -0
- package/src/api/workflows/entities/workflowStepExecutions.ts +74 -0
- package/src/api/workflows/entities/workflowStepLogs.ts +13 -0
- package/src/api/workflows/index.browser.ts +22 -0
- package/src/api/workflows/index.ts +124 -0
- package/src/api/workflows/jobs/WorkflowJobs.ts +77 -0
- package/src/api/workflows/primitives/$workflow.ts +202 -0
- package/src/api/workflows/providers/WorkflowProvider.ts +1284 -0
- package/src/api/workflows/schemas/workflowActivitySchema.ts +15 -0
- package/src/api/workflows/schemas/workflowConfigAtom.ts +51 -0
- package/src/api/workflows/schemas/workflowExecutionDetailSchema.ts +18 -0
- package/src/api/workflows/schemas/workflowExecutionQuerySchema.ts +26 -0
- package/src/api/workflows/schemas/workflowExecutionResourceSchema.ts +30 -0
- package/src/api/workflows/schemas/workflowRegistrationSchema.ts +26 -0
- package/src/api/workflows/schemas/workflowStatsSchema.ts +16 -0
- package/src/api/workflows/schemas/workflowStepExecutionResourceSchema.ts +15 -0
- package/src/api/workflows/services/WorkflowService.ts +382 -0
- package/src/cli/config/defineConfig.ts +17 -46
- package/src/cli/core/providers/ViteDevServerProvider.ts +45 -3
- package/src/cli/core/services/PackageManagerUtils.ts +3 -1
- package/src/cli/core/services/ProjectScaffolder.ts +5 -5
- package/src/cli/core/templates/agentMd.ts +14 -5
- package/src/cli/core/templates/webAppRouterTs.ts +5 -58
- package/src/cli/devtools/index.ts +21 -1
- package/src/cli/platform/index.ts +23 -2
- package/src/cli/vendor/__tests__/VendorService.spec.ts +283 -178
- package/src/cli/vendor/index.ts +20 -3
- package/src/cli/vendor/services/VendorService.ts +126 -27
- package/src/core/Alepha.ts +10 -0
- package/src/core/__tests__/TypeProvider.spec.ts +4 -2
- package/src/core/providers/SchemaValidator.ts +1 -1
- package/src/core/providers/TypeProvider.ts +46 -3
- package/src/logger/index.ts +6 -1
- package/src/orm/__tests__/enums.spec.ts +22 -29
- package/src/orm/__tests__/orm-showcase-tests.ts +430 -0
- package/src/orm/__tests__/orm-showcase.spec.ts +167 -0
- package/src/orm/core/providers/DatabaseTypeProvider.ts +0 -29
- package/src/orm/core/providers/DrizzleKitProvider.ts +56 -105
- package/src/orm/postgres/services/PostgresModelBuilder.ts +3 -6
- package/src/react/router/__tests__/$page.browser.spec.tsx +157 -0
- package/src/react/router/providers/ReactBrowserProvider.ts +39 -0
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +22 -0
- package/src/security/__tests__/$secure-combinations.spec.ts +945 -0
- package/src/security/primitives/$secure.ts +28 -0
- package/tsconfig.base.json +0 -1
- package/dist/billing/index.d.ts.map +0 -1
- package/dist/billing/index.js.map +0 -1
- package/src/billing/__tests__/BillingService.spec.ts +0 -136
- /package/src/{billing → api/payments}/entities/paymentMethods.ts +0 -0
- /package/src/{billing → api/payments}/entities/refunds.ts +0 -0
- /package/src/{billing → api/payments}/schemas/intentSchemas.ts +0 -0
- /package/src/{billing → api/payments}/schemas/paymentMethodSchemas.ts +0 -0
- /package/src/{billing → api/payments}/schemas/refundSchemas.ts +0 -0
|
@@ -50,6 +50,13 @@ export interface VendorDiffResult {
|
|
|
50
50
|
totalChanges: number;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Shape of the <root>/.alepha/vendor.json lock file.
|
|
55
|
+
*/
|
|
56
|
+
export interface VendorLock {
|
|
57
|
+
commit: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
53
60
|
/**
|
|
54
61
|
* Handles syncing and diffing vendored packages from a remote git repository.
|
|
55
62
|
*/
|
|
@@ -61,29 +68,44 @@ export class VendorService {
|
|
|
61
68
|
/**
|
|
62
69
|
* Sync vendored packages from a remote repository.
|
|
63
70
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
71
|
+
* Without `force`: checks for local modifications by comparing the local
|
|
72
|
+
* copy against the last-synced commit (stored in .alepha/vendor.json).
|
|
73
|
+
* If modifications are found, aborts without touching local files.
|
|
74
|
+
*
|
|
75
|
+
* With `force` (or first sync): replaces local copies unconditionally.
|
|
68
76
|
*/
|
|
69
77
|
async sync(options: VendorSyncOptions): Promise<VendorSyncResult> {
|
|
70
78
|
const synced: string[] = [];
|
|
71
79
|
const errors: string[] = [];
|
|
72
|
-
let tmpDir: string | undefined;
|
|
73
80
|
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
if (!options.force) {
|
|
82
|
+
const lock = await this.readLock(options.root);
|
|
83
|
+
|
|
84
|
+
if (lock) {
|
|
85
|
+
let baselineDir: string | undefined;
|
|
86
|
+
try {
|
|
87
|
+
baselineDir = await this.cloneAtCommit(options.remote, lock.commit);
|
|
88
|
+
const diffResult = await this.diffFromClone(
|
|
89
|
+
options.root,
|
|
90
|
+
baselineDir,
|
|
91
|
+
options.packages,
|
|
92
|
+
);
|
|
76
93
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return { synced: [], errors: [], aborted: diffResult };
|
|
94
|
+
if (diffResult.totalChanges > 0) {
|
|
95
|
+
return { synced: [], errors: [], aborted: diffResult };
|
|
96
|
+
}
|
|
97
|
+
} finally {
|
|
98
|
+
if (baselineDir) {
|
|
99
|
+
await this.fs.rm(baselineDir, { recursive: true, force: true });
|
|
100
|
+
}
|
|
85
101
|
}
|
|
86
102
|
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let tmpDir: string | undefined;
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
tmpDir = await this.cloneRemote(options.remote, options.branch);
|
|
87
109
|
|
|
88
110
|
for (const pkg of options.packages) {
|
|
89
111
|
const remotePkgDir = this.fs.join(tmpDir, "packages", pkg);
|
|
@@ -103,6 +125,9 @@ export class VendorService {
|
|
|
103
125
|
|
|
104
126
|
synced.push(pkg);
|
|
105
127
|
}
|
|
128
|
+
|
|
129
|
+
const commit = await this.getCommitHash(tmpDir);
|
|
130
|
+
await this.writeLock(options.root, { commit });
|
|
106
131
|
} finally {
|
|
107
132
|
if (tmpDir) {
|
|
108
133
|
await this.fs.rm(tmpDir, { recursive: true, force: true });
|
|
@@ -113,16 +138,21 @@ export class VendorService {
|
|
|
113
138
|
}
|
|
114
139
|
|
|
115
140
|
/**
|
|
116
|
-
* Diff vendored packages against
|
|
141
|
+
* Diff vendored packages against the last-synced commit.
|
|
117
142
|
*
|
|
118
|
-
*
|
|
119
|
-
* files to
|
|
143
|
+
* Reads the commit hash from .alepha/vendor.json, clones at that commit,
|
|
144
|
+
* and compares local files to detect modifications since last sync.
|
|
120
145
|
*/
|
|
121
146
|
async diff(options: VendorDiffOptions): Promise<VendorDiffResult> {
|
|
147
|
+
const lock = await this.readLock(options.root);
|
|
148
|
+
if (!lock) {
|
|
149
|
+
return { packages: [], totalChanges: 0 };
|
|
150
|
+
}
|
|
151
|
+
|
|
122
152
|
let tmpDir: string | undefined;
|
|
123
153
|
|
|
124
154
|
try {
|
|
125
|
-
tmpDir = await this.
|
|
155
|
+
tmpDir = await this.cloneAtCommit(options.remote, lock.commit);
|
|
126
156
|
return await this.diffFromClone(options.root, tmpDir, options.packages);
|
|
127
157
|
} finally {
|
|
128
158
|
if (tmpDir) {
|
|
@@ -155,24 +185,26 @@ export class VendorService {
|
|
|
155
185
|
}
|
|
156
186
|
|
|
157
187
|
if (!remoteExists) {
|
|
188
|
+
// No baseline = everything local was added by user
|
|
158
189
|
const localFiles = await this.fs.ls(localPkgDir, { recursive: true });
|
|
159
190
|
results.push({
|
|
160
191
|
name: pkg,
|
|
161
|
-
added:
|
|
192
|
+
added: localFiles,
|
|
162
193
|
modified: [],
|
|
163
|
-
removed:
|
|
194
|
+
removed: [],
|
|
164
195
|
});
|
|
165
196
|
totalChanges += localFiles.length;
|
|
166
197
|
continue;
|
|
167
198
|
}
|
|
168
199
|
|
|
169
200
|
if (!localExists) {
|
|
201
|
+
// Baseline exists but local doesn't = user deleted everything
|
|
170
202
|
const remoteFiles = await this.fs.ls(remotePkgDir, { recursive: true });
|
|
171
203
|
results.push({
|
|
172
204
|
name: pkg,
|
|
173
|
-
added:
|
|
205
|
+
added: [],
|
|
174
206
|
modified: [],
|
|
175
|
-
removed:
|
|
207
|
+
removed: remoteFiles,
|
|
176
208
|
});
|
|
177
209
|
totalChanges += remoteFiles.length;
|
|
178
210
|
continue;
|
|
@@ -205,7 +237,8 @@ export class VendorService {
|
|
|
205
237
|
if (
|
|
206
238
|
file.endsWith(".spec.ts") ||
|
|
207
239
|
file.endsWith(".spec.tsx") ||
|
|
208
|
-
file === "LICENSE"
|
|
240
|
+
file === "LICENSE" ||
|
|
241
|
+
file === "tsdown.config.ts"
|
|
209
242
|
) {
|
|
210
243
|
await this.fs.rm(this.fs.join(pkgDir, file), { force: true });
|
|
211
244
|
}
|
|
@@ -255,6 +288,69 @@ export class VendorService {
|
|
|
255
288
|
return tmpDir;
|
|
256
289
|
}
|
|
257
290
|
|
|
291
|
+
/**
|
|
292
|
+
* Clone a remote repository at a specific commit hash.
|
|
293
|
+
*/
|
|
294
|
+
protected async cloneAtCommit(
|
|
295
|
+
remote: string,
|
|
296
|
+
commit: string,
|
|
297
|
+
): Promise<string> {
|
|
298
|
+
const tmpDir = this.fs.join(
|
|
299
|
+
process.env.TMPDIR || "/tmp",
|
|
300
|
+
`.alepha-vendor-${Date.now()}`,
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
this.log.debug(`Cloning ${remote}@${commit} into ${tmpDir}`);
|
|
304
|
+
|
|
305
|
+
await this.shell.run(`git init ${tmpDir}`, { capture: true });
|
|
306
|
+
await this.shell.run(`git -C ${tmpDir} remote add origin ${remote}`, {
|
|
307
|
+
capture: true,
|
|
308
|
+
});
|
|
309
|
+
await this.shell.run(`git -C ${tmpDir} fetch --depth 1 origin ${commit}`, {
|
|
310
|
+
capture: true,
|
|
311
|
+
});
|
|
312
|
+
await this.shell.run(`git -C ${tmpDir} checkout FETCH_HEAD`, {
|
|
313
|
+
capture: true,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
return tmpDir;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Get the HEAD commit hash from a cloned repository.
|
|
321
|
+
*/
|
|
322
|
+
protected async getCommitHash(repoDir: string): Promise<string> {
|
|
323
|
+
const hash = await this.shell.run(`git -C ${repoDir} rev-parse HEAD`, {
|
|
324
|
+
capture: true,
|
|
325
|
+
});
|
|
326
|
+
return hash.trim();
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Read the vendor lock file.
|
|
331
|
+
*/
|
|
332
|
+
protected async readLock(root: string): Promise<VendorLock | undefined> {
|
|
333
|
+
const lockPath = this.fs.join(root, ".alepha", "vendor.json");
|
|
334
|
+
const exists = await this.fs.exists(lockPath);
|
|
335
|
+
if (!exists) {
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
338
|
+
const content = await this.fs.readFile(lockPath);
|
|
339
|
+
return JSON.parse(content.toString());
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Write the vendor lock file.
|
|
344
|
+
*/
|
|
345
|
+
protected async writeLock(root: string, lock: VendorLock): Promise<void> {
|
|
346
|
+
const dir = this.fs.join(root, ".alepha");
|
|
347
|
+
await this.fs.mkdir(dir, { recursive: true });
|
|
348
|
+
await this.fs.writeFile(
|
|
349
|
+
this.fs.join(dir, "vendor.json"),
|
|
350
|
+
JSON.stringify(lock, null, 2),
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
|
|
258
354
|
/**
|
|
259
355
|
* Directories to ignore during diff comparisons.
|
|
260
356
|
*/
|
|
@@ -272,7 +368,8 @@ export class VendorService {
|
|
|
272
368
|
if (
|
|
273
369
|
filePath.endsWith(".spec.ts") ||
|
|
274
370
|
filePath.endsWith(".spec.tsx") ||
|
|
275
|
-
filePath === "LICENSE"
|
|
371
|
+
filePath === "LICENSE" ||
|
|
372
|
+
filePath === "tsdown.config.ts"
|
|
276
373
|
) {
|
|
277
374
|
return true;
|
|
278
375
|
}
|
|
@@ -307,9 +404,10 @@ export class VendorService {
|
|
|
307
404
|
const localSet = new Set(filteredLocal);
|
|
308
405
|
const remoteSet = new Set(filteredRemote);
|
|
309
406
|
|
|
407
|
+
// Files in baseline but not local = user deleted them
|
|
310
408
|
for (const file of filteredRemote) {
|
|
311
409
|
if (!localSet.has(file)) {
|
|
312
|
-
|
|
410
|
+
removed.push(file);
|
|
313
411
|
continue;
|
|
314
412
|
}
|
|
315
413
|
|
|
@@ -327,9 +425,10 @@ export class VendorService {
|
|
|
327
425
|
}
|
|
328
426
|
}
|
|
329
427
|
|
|
428
|
+
// Files in local but not baseline = user added them
|
|
330
429
|
for (const file of filteredLocal) {
|
|
331
430
|
if (!remoteSet.has(file)) {
|
|
332
|
-
|
|
431
|
+
added.push(file);
|
|
333
432
|
}
|
|
334
433
|
}
|
|
335
434
|
|
package/src/core/Alepha.ts
CHANGED
|
@@ -167,6 +167,16 @@ export class Alepha {
|
|
|
167
167
|
};
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
// force production mode when building with vite
|
|
171
|
+
// vite's define replaces `process.env.NODE_ENV` with `"production"` at build time,
|
|
172
|
+
// but the spread above doesn't carry it (especially in workerd/cloudflare).
|
|
173
|
+
if (typeof process === "object" && process.env?.NODE_ENV === "production") {
|
|
174
|
+
state.env ??= {};
|
|
175
|
+
Object.assign(state.env, {
|
|
176
|
+
NODE_ENV: "production",
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
170
180
|
const alepha = new Alepha(state);
|
|
171
181
|
|
|
172
182
|
if (alepha.isTest()) {
|
|
@@ -850,12 +850,14 @@ describe("TypeProvider", () => {
|
|
|
850
850
|
).toEqual(["valid", "123", "also valid"]);
|
|
851
851
|
});
|
|
852
852
|
|
|
853
|
-
it("should
|
|
853
|
+
it("should auto-cast non-array values to single-element array", async () => {
|
|
854
854
|
const alepha = Alepha.create();
|
|
855
855
|
await alepha.start();
|
|
856
856
|
const schema = t.array(t.text());
|
|
857
857
|
|
|
858
|
-
expect(
|
|
858
|
+
expect(alepha.codec.validate(schema, "not an array")).toEqual([
|
|
859
|
+
"not an array",
|
|
860
|
+
]);
|
|
859
861
|
});
|
|
860
862
|
|
|
861
863
|
it("should support array of objects", async () => {
|
|
@@ -27,7 +27,7 @@ export class SchemaValidator {
|
|
|
27
27
|
try {
|
|
28
28
|
//
|
|
29
29
|
if (!this.useEval) {
|
|
30
|
-
return Value.Parse(schema, newValue)
|
|
30
|
+
return Value.Parse(schema, newValue) as Static<T>;
|
|
31
31
|
}
|
|
32
32
|
return this.getValidator(schema).Parse(newValue) as Static<T>;
|
|
33
33
|
} catch (error: any) {
|
|
@@ -458,18 +458,43 @@ export class TypeProvider {
|
|
|
458
458
|
|
|
459
459
|
/**
|
|
460
460
|
* Create a schema for a string enum.
|
|
461
|
+
*
|
|
462
|
+
* By default, this creates a real PostgreSQL ENUM type in the database.
|
|
463
|
+
* Use `{ mode: "text" }` to store as a TEXT column instead.
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* ```ts
|
|
467
|
+
* // PostgreSQL ENUM type (default)
|
|
468
|
+
* status: t.enum(["pending", "active", "archived"])
|
|
469
|
+
*
|
|
470
|
+
* // TEXT column
|
|
471
|
+
* status: t.enum(["pending", "active", "archived"], { mode: "text" })
|
|
472
|
+
*
|
|
473
|
+
* // Shared enum name across tables
|
|
474
|
+
* status: t.enum(["enabled", "disabled"], { name: "shared_status_enum" })
|
|
475
|
+
* ```
|
|
461
476
|
*/
|
|
462
477
|
public enum<T extends string[]>(
|
|
463
478
|
values: [...T],
|
|
464
|
-
options?:
|
|
479
|
+
options?: TEnumOptions,
|
|
465
480
|
): TUnsafe<T[number]> {
|
|
466
|
-
|
|
481
|
+
const { mode, name, ...textOptions } = options ?? {};
|
|
482
|
+
|
|
483
|
+
const schema = Type.Unsafe<T[number]>(
|
|
467
484
|
t.text({
|
|
468
485
|
enum: values,
|
|
469
486
|
pattern: values.map((v) => `^${v}$`).join("|"),
|
|
470
|
-
...
|
|
487
|
+
...textOptions,
|
|
471
488
|
}),
|
|
472
489
|
);
|
|
490
|
+
|
|
491
|
+
if (mode === "text") {
|
|
492
|
+
Object.assign(schema, { mode: "text" });
|
|
493
|
+
} else {
|
|
494
|
+
Object.assign(schema, { enumName: name });
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return schema;
|
|
473
498
|
}
|
|
474
499
|
|
|
475
500
|
// -------------------------------------------------------------------------------------------------------------------
|
|
@@ -666,6 +691,24 @@ export class TypeProvider {
|
|
|
666
691
|
|
|
667
692
|
export type TextLength = "short" | "regular" | "long" | "rich";
|
|
668
693
|
|
|
694
|
+
export interface TEnumOptions extends TTextOptions {
|
|
695
|
+
/**
|
|
696
|
+
* Storage mode for the enum.
|
|
697
|
+
*
|
|
698
|
+
* - `"text"` — stores as a TEXT column in the database.
|
|
699
|
+
* - When omitted, creates a real PostgreSQL ENUM type.
|
|
700
|
+
*/
|
|
701
|
+
mode?: "text";
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Custom name for the PostgreSQL ENUM type.
|
|
705
|
+
*
|
|
706
|
+
* Use this to share the same enum type across multiple tables.
|
|
707
|
+
* If not specified, the name is auto-generated from the table and column names.
|
|
708
|
+
*/
|
|
709
|
+
name?: string;
|
|
710
|
+
}
|
|
711
|
+
|
|
669
712
|
export interface TTextOptions extends TStringOptions {
|
|
670
713
|
/**
|
|
671
714
|
* Predefined size of the text.
|
package/src/logger/index.ts
CHANGED
|
@@ -139,7 +139,12 @@ export const AlephaLogger = $module({
|
|
|
139
139
|
|
|
140
140
|
alepha.store.set(
|
|
141
141
|
"alepha.logger.level",
|
|
142
|
-
logLevel ??
|
|
142
|
+
logLevel ??
|
|
143
|
+
(alepha.isTest()
|
|
144
|
+
? "trace"
|
|
145
|
+
: alepha.isProduction() && alepha.isBrowser()
|
|
146
|
+
? "warn"
|
|
147
|
+
: "info"),
|
|
143
148
|
);
|
|
144
149
|
},
|
|
145
150
|
});
|
|
@@ -3,33 +3,33 @@ import { describe, expect, it } from "vitest";
|
|
|
3
3
|
import { $entity, $repository, DrizzleKitProvider, db } from "../core/index.ts";
|
|
4
4
|
import { AlephaOrmPostgres } from "../postgres/index.ts";
|
|
5
5
|
|
|
6
|
-
// Test 1:
|
|
6
|
+
// Test 1: t.enum with mode: "text" (should map to TEXT column)
|
|
7
7
|
const textEnumEntity = $entity({
|
|
8
8
|
name: "text_enum_test",
|
|
9
9
|
schema: t.object({
|
|
10
10
|
id: db.primaryKey(),
|
|
11
|
-
status: t.enum(["pending", "active", "archived"]),
|
|
12
|
-
role: t.enum(["user", "admin", "moderator"]),
|
|
11
|
+
status: t.enum(["pending", "active", "archived"], { mode: "text" }),
|
|
12
|
+
role: t.enum(["user", "admin", "moderator"], { mode: "text" }),
|
|
13
13
|
}),
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
// Test 2:
|
|
16
|
+
// Test 2: t.enum without mode (should create real PG ENUM type)
|
|
17
17
|
const pgEnumEntity = $entity({
|
|
18
18
|
name: "pg_enum_test",
|
|
19
19
|
schema: t.object({
|
|
20
20
|
id: db.primaryKey(),
|
|
21
|
-
status:
|
|
22
|
-
priority:
|
|
21
|
+
status: t.enum(["draft", "published", "deleted"]),
|
|
22
|
+
priority: t.enum(["low", "medium", "high"]),
|
|
23
23
|
}),
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
// Test 3: Mixed
|
|
26
|
+
// Test 3: Mixed text and pg enum in the same table
|
|
27
27
|
const mixedEnumEntity = $entity({
|
|
28
28
|
name: "mixed_enum_test",
|
|
29
29
|
schema: t.object({
|
|
30
30
|
id: db.primaryKey(),
|
|
31
|
-
textStatus: t.enum(["open", "closed"]),
|
|
32
|
-
pgStatus:
|
|
31
|
+
textStatus: t.enum(["open", "closed"], { mode: "text" }),
|
|
32
|
+
pgStatus: t.enum(["new", "in_progress", "done"]),
|
|
33
33
|
}),
|
|
34
34
|
});
|
|
35
35
|
|
|
@@ -38,7 +38,7 @@ const sharedEnumEntity1 = $entity({
|
|
|
38
38
|
name: "shared_enum_test_1",
|
|
39
39
|
schema: t.object({
|
|
40
40
|
id: db.primaryKey(),
|
|
41
|
-
status:
|
|
41
|
+
status: t.enum(["enabled", "disabled"], { name: "shared_status_enum" }),
|
|
42
42
|
}),
|
|
43
43
|
});
|
|
44
44
|
|
|
@@ -46,7 +46,7 @@ const sharedEnumEntity2 = $entity({
|
|
|
46
46
|
name: "shared_enum_test_2",
|
|
47
47
|
schema: t.object({
|
|
48
48
|
id: db.primaryKey(),
|
|
49
|
-
status:
|
|
49
|
+
status: t.enum(["enabled", "disabled"], { name: "shared_status_enum" }),
|
|
50
50
|
}),
|
|
51
51
|
});
|
|
52
52
|
|
|
@@ -55,7 +55,7 @@ const conflictEnumEntity1 = $entity({
|
|
|
55
55
|
name: "conflict_enum_test_1",
|
|
56
56
|
schema: t.object({
|
|
57
57
|
id: db.primaryKey(),
|
|
58
|
-
status:
|
|
58
|
+
status: t.enum(["a", "b", "c"], { name: "conflict_status_enum" }),
|
|
59
59
|
}),
|
|
60
60
|
});
|
|
61
61
|
|
|
@@ -63,12 +63,12 @@ const conflictEnumEntity2 = $entity({
|
|
|
63
63
|
name: "conflict_enum_test_2",
|
|
64
64
|
schema: t.object({
|
|
65
65
|
id: db.primaryKey(),
|
|
66
|
-
status:
|
|
66
|
+
status: t.enum(["a", "b", "d"], { name: "conflict_status_enum" }), // Different value!
|
|
67
67
|
}),
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
describe("enums - t.enum (TEXT column)", () => {
|
|
71
|
-
it("should create TEXT columns for t.enum fields", async () => {
|
|
70
|
+
describe("enums - t.enum with mode: 'text' (TEXT column)", () => {
|
|
71
|
+
it("should create TEXT columns for t.enum fields with mode: 'text'", async () => {
|
|
72
72
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
73
73
|
|
|
74
74
|
class App {
|
|
@@ -87,12 +87,12 @@ describe("enums - t.enum (TEXT column)", () => {
|
|
|
87
87
|
|
|
88
88
|
expect(sql).toContainEqual(expect.stringContaining("CREATE TABLE"));
|
|
89
89
|
expect(sql).toContainEqual(expect.stringContaining("text_enum_test"));
|
|
90
|
-
//
|
|
90
|
+
// mode: "text" should map to TEXT, not a real ENUM type
|
|
91
91
|
expect(sql.some((s) => s.includes('"status" text'))).toBe(true);
|
|
92
92
|
expect(sql.some((s) => s.includes('"role" text'))).toBe(true);
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
it("should allow inserting and querying with
|
|
95
|
+
it("should allow inserting and querying with text enum values", async () => {
|
|
96
96
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
97
97
|
|
|
98
98
|
class App {
|
|
@@ -117,8 +117,8 @@ describe("enums - t.enum (TEXT column)", () => {
|
|
|
117
117
|
});
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
describe("enums -
|
|
121
|
-
it("should create real PostgreSQL ENUM types for
|
|
120
|
+
describe("enums - t.enum (real PG ENUM type)", () => {
|
|
121
|
+
it("should create real PostgreSQL ENUM types for t.enum fields", async () => {
|
|
122
122
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
123
123
|
|
|
124
124
|
class App {
|
|
@@ -137,13 +137,13 @@ describe("enums - db.enum (real PG ENUM type)", () => {
|
|
|
137
137
|
|
|
138
138
|
expect(sql).toContainEqual(expect.stringContaining("CREATE TABLE"));
|
|
139
139
|
expect(sql).toContainEqual(expect.stringContaining("pg_enum_test"));
|
|
140
|
-
//
|
|
140
|
+
// t.enum without mode should create real ENUM types
|
|
141
141
|
expect(
|
|
142
142
|
sql.some((s) => s.includes("CREATE TYPE") || s.includes("DO $$ BEGIN")),
|
|
143
143
|
).toBe(true);
|
|
144
144
|
});
|
|
145
145
|
|
|
146
|
-
it("should allow inserting and querying with
|
|
146
|
+
it("should allow inserting and querying with pg enum values", async () => {
|
|
147
147
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
148
148
|
|
|
149
149
|
class App {
|
|
@@ -168,7 +168,7 @@ describe("enums - db.enum (real PG ENUM type)", () => {
|
|
|
168
168
|
});
|
|
169
169
|
});
|
|
170
170
|
|
|
171
|
-
describe("enums - mixed
|
|
171
|
+
describe("enums - mixed text and pg enum in same table", () => {
|
|
172
172
|
it("should handle both TEXT and PG ENUM types in the same table", async () => {
|
|
173
173
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
174
174
|
|
|
@@ -299,13 +299,6 @@ describe("enums - conflict detection with different values", () => {
|
|
|
299
299
|
it("should throw error when same enum name has different values", async () => {
|
|
300
300
|
const alepha = Alepha.create().with(AlephaOrmPostgres);
|
|
301
301
|
|
|
302
|
-
const load = async () => {
|
|
303
|
-
return alepha.with(() => ({
|
|
304
|
-
r1: $repository(conflictEnumEntity1),
|
|
305
|
-
r2: $repository(conflictEnumEntity2),
|
|
306
|
-
}));
|
|
307
|
-
};
|
|
308
|
-
|
|
309
302
|
expect(() =>
|
|
310
303
|
alepha.with(() => ({
|
|
311
304
|
r1: $repository(conflictEnumEntity1),
|