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
|
@@ -82,6 +82,12 @@ interface VendorDiffResult {
|
|
|
82
82
|
packages: VendorPackageDiff[];
|
|
83
83
|
totalChanges: number;
|
|
84
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Shape of the <root>/.alepha/vendor.json lock file.
|
|
87
|
+
*/
|
|
88
|
+
interface VendorLock {
|
|
89
|
+
commit: string;
|
|
90
|
+
}
|
|
85
91
|
/**
|
|
86
92
|
* Handles syncing and diffing vendored packages from a remote git repository.
|
|
87
93
|
*/
|
|
@@ -92,17 +98,18 @@ declare class VendorService {
|
|
|
92
98
|
/**
|
|
93
99
|
* Sync vendored packages from a remote repository.
|
|
94
100
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
101
|
+
* Without `force`: checks for local modifications by comparing the local
|
|
102
|
+
* copy against the last-synced commit (stored in .alepha/vendor.json).
|
|
103
|
+
* If modifications are found, aborts without touching local files.
|
|
104
|
+
*
|
|
105
|
+
* With `force` (or first sync): replaces local copies unconditionally.
|
|
99
106
|
*/
|
|
100
107
|
sync(options: VendorSyncOptions): Promise<VendorSyncResult>;
|
|
101
108
|
/**
|
|
102
|
-
* Diff vendored packages against
|
|
109
|
+
* Diff vendored packages against the last-synced commit.
|
|
103
110
|
*
|
|
104
|
-
*
|
|
105
|
-
* files to
|
|
111
|
+
* Reads the commit hash from .alepha/vendor.json, clones at that commit,
|
|
112
|
+
* and compares local files to detect modifications since last sync.
|
|
106
113
|
*/
|
|
107
114
|
diff(options: VendorDiffOptions): Promise<VendorDiffResult>;
|
|
108
115
|
/**
|
|
@@ -117,6 +124,22 @@ declare class VendorService {
|
|
|
117
124
|
* Clone a remote repository into a temporary directory.
|
|
118
125
|
*/
|
|
119
126
|
protected cloneRemote(remote: string, branch: string): Promise<string>;
|
|
127
|
+
/**
|
|
128
|
+
* Clone a remote repository at a specific commit hash.
|
|
129
|
+
*/
|
|
130
|
+
protected cloneAtCommit(remote: string, commit: string): Promise<string>;
|
|
131
|
+
/**
|
|
132
|
+
* Get the HEAD commit hash from a cloned repository.
|
|
133
|
+
*/
|
|
134
|
+
protected getCommitHash(repoDir: string): Promise<string>;
|
|
135
|
+
/**
|
|
136
|
+
* Read the vendor lock file.
|
|
137
|
+
*/
|
|
138
|
+
protected readLock(root: string): Promise<VendorLock | undefined>;
|
|
139
|
+
/**
|
|
140
|
+
* Write the vendor lock file.
|
|
141
|
+
*/
|
|
142
|
+
protected writeLock(root: string, lock: VendorLock): Promise<void>;
|
|
120
143
|
/**
|
|
121
144
|
* Directories to ignore during diff comparisons.
|
|
122
145
|
*/
|
|
@@ -165,6 +188,11 @@ declare class VendorCommand {
|
|
|
165
188
|
}
|
|
166
189
|
//#endregion
|
|
167
190
|
//#region ../../src/cli/vendor/index.d.ts
|
|
191
|
+
declare module "alepha/cli/config" {
|
|
192
|
+
interface AlephaCliConfig {
|
|
193
|
+
vendor?: VendorOptions;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
168
196
|
/**
|
|
169
197
|
* CLI plugin for vendoring Alepha packages into external projects.
|
|
170
198
|
*
|
|
@@ -179,10 +207,10 @@ declare class VendorCommand {
|
|
|
179
207
|
* Configuration in `alepha.config.ts`:
|
|
180
208
|
*
|
|
181
209
|
* ```typescript
|
|
182
|
-
* import {
|
|
210
|
+
* import { AlephaCliVendorPlugin } from "alepha/cli/vendor";
|
|
183
211
|
*
|
|
184
212
|
* export default defineConfig({
|
|
185
|
-
* services: [
|
|
213
|
+
* services: [AlephaCliVendorPlugin],
|
|
186
214
|
* vendor: {
|
|
187
215
|
* branch: "main",
|
|
188
216
|
* packages: ["alepha", "@alepha/bucket-s3"],
|
|
@@ -192,5 +220,5 @@ declare class VendorCommand {
|
|
|
192
220
|
*/
|
|
193
221
|
declare const AlephaCliVendorPlugin: _$alepha.Service<_$alepha.Module>;
|
|
194
222
|
//#endregion
|
|
195
|
-
export { AlephaCliVendorPlugin, VendorCommand, VendorDiffOptions, VendorDiffResult, VendorOptions, VendorPackageDiff, VendorService, VendorSyncOptions, VendorSyncResult, vendorOptions };
|
|
223
|
+
export { AlephaCliVendorPlugin, VendorCommand, VendorDiffOptions, VendorDiffResult, VendorLock, VendorOptions, VendorPackageDiff, VendorService, VendorSyncOptions, VendorSyncResult, vendorOptions };
|
|
196
224
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/cli/vendor/atoms/vendorOptions.ts","../../../src/cli/vendor/services/VendorService.ts","../../../src/cli/vendor/commands/VendorCommand.ts","../../../src/cli/vendor/index.ts"],"mappings":";;;;;;;;;;;;;;;cAQa,aAAA,EAAa,QAAA,CAAA,IAAA,CAAA,QAAA,CAAA,SAAA,UAAA,OAAA;;AAA1B;;;;6BA2BE,QAAA,CAAA,OAAA;;;;;;;EA3BwB;;;;;;;;;;KAgCd,aAAA,GAAgB,MAAA,QAAc,aAAA,CAAc,MAAA;;;;;;UCjCvC,iBAAA;EACf,IAAA;EACA,MAAA;EACA,MAAA;EACA,QAAA;EACA,KAAA;AAAA;;;;UAMe,gBAAA;EACf,MAAA;EACA,MAAA;EACA,OAAA,GAAU,gBAAA;AAAA;;;;UAMK,iBAAA;EACf,IAAA;EACA,MAAA;EACA,MAAA;EACA,QAAA;AAAA;;;;UAMe,iBAAA;EACf,IAAA;EACA,KAAA;EACA,QAAA;EACA,OAAA;AAAA;ADDF;;;AAAA,UCOiB,gBAAA;EACf,QAAA,EAAU,iBAAA;EACV,YAAA;AAAA;;;;cAMW,aAAA;EAAA,mBACQ,GAAA,EADK,gBAAA,CACF,MAAA;EAAA,mBACH,KAAA,EAAK,aAAA;EAAA,mBACL,EAAA,EAAE,kBAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/cli/vendor/atoms/vendorOptions.ts","../../../src/cli/vendor/services/VendorService.ts","../../../src/cli/vendor/commands/VendorCommand.ts","../../../src/cli/vendor/index.ts"],"mappings":"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"}
|
package/dist/cli/vendor/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { $atom, $inject, $module, $state, AlephaError, t } from "alepha";
|
|
2
|
+
import { cliConfigPlugins } from "alepha/cli/config";
|
|
2
3
|
import { PackageManagerUtils } from "alepha/cli";
|
|
3
4
|
import { $command } from "alepha/command";
|
|
4
5
|
import { $logger, ConsoleColorProvider } from "alepha/logger";
|
|
@@ -31,25 +32,38 @@ var VendorService = class {
|
|
|
31
32
|
/**
|
|
32
33
|
* Sync vendored packages from a remote repository.
|
|
33
34
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
35
|
+
* Without `force`: checks for local modifications by comparing the local
|
|
36
|
+
* copy against the last-synced commit (stored in .alepha/vendor.json).
|
|
37
|
+
* If modifications are found, aborts without touching local files.
|
|
38
|
+
*
|
|
39
|
+
* With `force` (or first sync): replaces local copies unconditionally.
|
|
38
40
|
*/
|
|
39
41
|
async sync(options) {
|
|
40
42
|
const synced = [];
|
|
41
43
|
const errors = [];
|
|
44
|
+
if (!options.force) {
|
|
45
|
+
const lock = await this.readLock(options.root);
|
|
46
|
+
if (lock) {
|
|
47
|
+
let baselineDir;
|
|
48
|
+
try {
|
|
49
|
+
baselineDir = await this.cloneAtCommit(options.remote, lock.commit);
|
|
50
|
+
const diffResult = await this.diffFromClone(options.root, baselineDir, options.packages);
|
|
51
|
+
if (diffResult.totalChanges > 0) return {
|
|
52
|
+
synced: [],
|
|
53
|
+
errors: [],
|
|
54
|
+
aborted: diffResult
|
|
55
|
+
};
|
|
56
|
+
} finally {
|
|
57
|
+
if (baselineDir) await this.fs.rm(baselineDir, {
|
|
58
|
+
recursive: true,
|
|
59
|
+
force: true
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
42
64
|
let tmpDir;
|
|
43
65
|
try {
|
|
44
66
|
tmpDir = await this.cloneRemote(options.remote, options.branch);
|
|
45
|
-
if (!options.force) {
|
|
46
|
-
const diffResult = await this.diffFromClone(options.root, tmpDir, options.packages);
|
|
47
|
-
if (diffResult.totalChanges > 0) return {
|
|
48
|
-
synced: [],
|
|
49
|
-
errors: [],
|
|
50
|
-
aborted: diffResult
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
67
|
for (const pkg of options.packages) {
|
|
54
68
|
const remotePkgDir = this.fs.join(tmpDir, "packages", pkg);
|
|
55
69
|
const localPkgDir = this.fs.join(options.root, "packages", pkg);
|
|
@@ -66,6 +80,8 @@ var VendorService = class {
|
|
|
66
80
|
await this.removeIgnoredFiles(localPkgDir);
|
|
67
81
|
synced.push(pkg);
|
|
68
82
|
}
|
|
83
|
+
const commit = await this.getCommitHash(tmpDir);
|
|
84
|
+
await this.writeLock(options.root, { commit });
|
|
69
85
|
} finally {
|
|
70
86
|
if (tmpDir) await this.fs.rm(tmpDir, {
|
|
71
87
|
recursive: true,
|
|
@@ -78,15 +94,20 @@ var VendorService = class {
|
|
|
78
94
|
};
|
|
79
95
|
}
|
|
80
96
|
/**
|
|
81
|
-
* Diff vendored packages against
|
|
97
|
+
* Diff vendored packages against the last-synced commit.
|
|
82
98
|
*
|
|
83
|
-
*
|
|
84
|
-
* files to
|
|
99
|
+
* Reads the commit hash from .alepha/vendor.json, clones at that commit,
|
|
100
|
+
* and compares local files to detect modifications since last sync.
|
|
85
101
|
*/
|
|
86
102
|
async diff(options) {
|
|
103
|
+
const lock = await this.readLock(options.root);
|
|
104
|
+
if (!lock) return {
|
|
105
|
+
packages: [],
|
|
106
|
+
totalChanges: 0
|
|
107
|
+
};
|
|
87
108
|
let tmpDir;
|
|
88
109
|
try {
|
|
89
|
-
tmpDir = await this.
|
|
110
|
+
tmpDir = await this.cloneAtCommit(options.remote, lock.commit);
|
|
90
111
|
return await this.diffFromClone(options.root, tmpDir, options.packages);
|
|
91
112
|
} finally {
|
|
92
113
|
if (tmpDir) await this.fs.rm(tmpDir, {
|
|
@@ -119,9 +140,9 @@ var VendorService = class {
|
|
|
119
140
|
const localFiles = await this.fs.ls(localPkgDir, { recursive: true });
|
|
120
141
|
results.push({
|
|
121
142
|
name: pkg,
|
|
122
|
-
added:
|
|
143
|
+
added: localFiles,
|
|
123
144
|
modified: [],
|
|
124
|
-
removed:
|
|
145
|
+
removed: []
|
|
125
146
|
});
|
|
126
147
|
totalChanges += localFiles.length;
|
|
127
148
|
continue;
|
|
@@ -130,9 +151,9 @@ var VendorService = class {
|
|
|
130
151
|
const remoteFiles = await this.fs.ls(remotePkgDir, { recursive: true });
|
|
131
152
|
results.push({
|
|
132
153
|
name: pkg,
|
|
133
|
-
added:
|
|
154
|
+
added: [],
|
|
134
155
|
modified: [],
|
|
135
|
-
removed:
|
|
156
|
+
removed: remoteFiles
|
|
136
157
|
});
|
|
137
158
|
totalChanges += remoteFiles.length;
|
|
138
159
|
continue;
|
|
@@ -157,7 +178,7 @@ var VendorService = class {
|
|
|
157
178
|
*/
|
|
158
179
|
async removeIgnoredFiles(pkgDir) {
|
|
159
180
|
const allFiles = await this.fs.ls(pkgDir, { recursive: true });
|
|
160
|
-
for (const file of allFiles) if (file.endsWith(".spec.ts") || file.endsWith(".spec.tsx") || file === "LICENSE") await this.fs.rm(this.fs.join(pkgDir, file), { force: true });
|
|
181
|
+
for (const file of allFiles) if (file.endsWith(".spec.ts") || file.endsWith(".spec.tsx") || file === "LICENSE" || file === "tsdown.config.ts") await this.fs.rm(this.fs.join(pkgDir, file), { force: true });
|
|
161
182
|
for (const file of allFiles) for (const ignored of this.ignoredPaths) if (file === ignored || file.startsWith(`${ignored}/`) || file.includes(`/${ignored}/`) || file.endsWith(`/${ignored}`)) {
|
|
162
183
|
const idx = file.indexOf(ignored);
|
|
163
184
|
const dirPath = this.fs.join(pkgDir, file.substring(0, idx + ignored.length));
|
|
@@ -178,6 +199,41 @@ var VendorService = class {
|
|
|
178
199
|
return tmpDir;
|
|
179
200
|
}
|
|
180
201
|
/**
|
|
202
|
+
* Clone a remote repository at a specific commit hash.
|
|
203
|
+
*/
|
|
204
|
+
async cloneAtCommit(remote, commit) {
|
|
205
|
+
const tmpDir = this.fs.join(process.env.TMPDIR || "/tmp", `.alepha-vendor-${Date.now()}`);
|
|
206
|
+
this.log.debug(`Cloning ${remote}@${commit} into ${tmpDir}`);
|
|
207
|
+
await this.shell.run(`git init ${tmpDir}`, { capture: true });
|
|
208
|
+
await this.shell.run(`git -C ${tmpDir} remote add origin ${remote}`, { capture: true });
|
|
209
|
+
await this.shell.run(`git -C ${tmpDir} fetch --depth 1 origin ${commit}`, { capture: true });
|
|
210
|
+
await this.shell.run(`git -C ${tmpDir} checkout FETCH_HEAD`, { capture: true });
|
|
211
|
+
return tmpDir;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Get the HEAD commit hash from a cloned repository.
|
|
215
|
+
*/
|
|
216
|
+
async getCommitHash(repoDir) {
|
|
217
|
+
return (await this.shell.run(`git -C ${repoDir} rev-parse HEAD`, { capture: true })).trim();
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Read the vendor lock file.
|
|
221
|
+
*/
|
|
222
|
+
async readLock(root) {
|
|
223
|
+
const lockPath = this.fs.join(root, ".alepha", "vendor.json");
|
|
224
|
+
if (!await this.fs.exists(lockPath)) return;
|
|
225
|
+
const content = await this.fs.readFile(lockPath);
|
|
226
|
+
return JSON.parse(content.toString());
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Write the vendor lock file.
|
|
230
|
+
*/
|
|
231
|
+
async writeLock(root, lock) {
|
|
232
|
+
const dir = this.fs.join(root, ".alepha");
|
|
233
|
+
await this.fs.mkdir(dir, { recursive: true });
|
|
234
|
+
await this.fs.writeFile(this.fs.join(dir, "vendor.json"), JSON.stringify(lock, null, 2));
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
181
237
|
* Directories to ignore during diff comparisons.
|
|
182
238
|
*/
|
|
183
239
|
ignoredPaths = [
|
|
@@ -190,7 +246,7 @@ var VendorService = class {
|
|
|
190
246
|
* Check if a file path should be ignored during diff.
|
|
191
247
|
*/
|
|
192
248
|
isIgnored(filePath) {
|
|
193
|
-
if (filePath.endsWith(".spec.ts") || filePath.endsWith(".spec.tsx") || filePath === "LICENSE") return true;
|
|
249
|
+
if (filePath.endsWith(".spec.ts") || filePath.endsWith(".spec.tsx") || filePath === "LICENSE" || filePath === "tsdown.config.ts") return true;
|
|
194
250
|
return this.ignoredPaths.some((p) => filePath === p || filePath.startsWith(`${p}/`) || filePath.includes(`/${p}/`) || filePath.endsWith(`/${p}`));
|
|
195
251
|
}
|
|
196
252
|
/**
|
|
@@ -207,7 +263,7 @@ var VendorService = class {
|
|
|
207
263
|
const remoteSet = new Set(filteredRemote);
|
|
208
264
|
for (const file of filteredRemote) {
|
|
209
265
|
if (!localSet.has(file)) {
|
|
210
|
-
|
|
266
|
+
removed.push(file);
|
|
211
267
|
continue;
|
|
212
268
|
}
|
|
213
269
|
try {
|
|
@@ -215,7 +271,7 @@ var VendorService = class {
|
|
|
215
271
|
if (!localContent.equals(remoteContent)) modified.push(file);
|
|
216
272
|
} catch {}
|
|
217
273
|
}
|
|
218
|
-
for (const file of filteredLocal) if (!remoteSet.has(file))
|
|
274
|
+
for (const file of filteredLocal) if (!remoteSet.has(file)) added.push(file);
|
|
219
275
|
return {
|
|
220
276
|
added,
|
|
221
277
|
modified,
|
|
@@ -362,10 +418,10 @@ var VendorCommand = class {
|
|
|
362
418
|
* Configuration in `alepha.config.ts`:
|
|
363
419
|
*
|
|
364
420
|
* ```typescript
|
|
365
|
-
* import {
|
|
421
|
+
* import { AlephaCliVendorPlugin } from "alepha/cli/vendor";
|
|
366
422
|
*
|
|
367
423
|
* export default defineConfig({
|
|
368
|
-
* services: [
|
|
424
|
+
* services: [AlephaCliVendorPlugin],
|
|
369
425
|
* vendor: {
|
|
370
426
|
* branch: "main",
|
|
371
427
|
* packages: ["alepha", "@alepha/bucket-s3"],
|
|
@@ -378,6 +434,9 @@ const AlephaCliVendorPlugin = $module({
|
|
|
378
434
|
atoms: [vendorOptions],
|
|
379
435
|
services: [VendorCommand, VendorService]
|
|
380
436
|
});
|
|
437
|
+
cliConfigPlugins.push((config, alepha) => {
|
|
438
|
+
if (config.vendor) alepha.set(vendorOptions, config.vendor);
|
|
439
|
+
});
|
|
381
440
|
//#endregion
|
|
382
441
|
export { AlephaCliVendorPlugin, VendorCommand, VendorService, vendorOptions };
|
|
383
442
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/cli/vendor/atoms/vendorOptions.ts","../../../src/cli/vendor/services/VendorService.ts","../../../src/cli/vendor/commands/VendorCommand.ts","../../../src/cli/vendor/index.ts"],"sourcesContent":["import { $atom, type Static, t } from \"alepha\";\n\n/**\n * Vendor configuration atom.\n *\n * Filled from the `vendor` section of `alepha.config.ts`.\n * Read by `VendorCommand` to resolve remote, branch, and packages.\n */\nexport const vendorOptions = $atom({\n name: \"alepha.cli.vendor.options\",\n description: \"Vendor synchronization configuration\",\n schema: t.optional(\n t.object({\n /**\n * Git remote URL.\n *\n * @default \"git@github.com:feunard/alepha.git\"\n */\n remote: t.optional(t.text()),\n\n /**\n * Branch to sync from.\n *\n * @default \"main\"\n */\n branch: t.optional(t.text()),\n\n /**\n * Package directory names under `packages/` to sync.\n *\n * @example [\"alepha\", \"@alepha/bucket-s3\"]\n */\n packages: t.array(t.text()),\n }),\n ),\n});\n\n/**\n * Type for vendor options.\n */\nexport type VendorOptions = Static<typeof vendorOptions.schema>;\n","import { $inject } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { FileSystemProvider, ShellProvider } from \"alepha/system\";\n\n/**\n * Options for syncing vendored packages from a remote repository.\n */\nexport interface VendorSyncOptions {\n root: string;\n remote: string;\n branch: string;\n packages: string[];\n force?: boolean;\n}\n\n/**\n * Result of a vendor sync operation.\n */\nexport interface VendorSyncResult {\n synced: string[];\n errors: string[];\n aborted?: VendorDiffResult;\n}\n\n/**\n * Options for diffing vendored packages against a remote repository.\n */\nexport interface VendorDiffOptions {\n root: string;\n remote: string;\n branch: string;\n packages: string[];\n}\n\n/**\n * Diff result for a single vendored package.\n */\nexport interface VendorPackageDiff {\n name: string;\n added: string[];\n modified: string[];\n removed: string[];\n}\n\n/**\n * Result of a vendor diff operation.\n */\nexport interface VendorDiffResult {\n packages: VendorPackageDiff[];\n totalChanges: number;\n}\n\n/**\n * Handles syncing and diffing vendored packages from a remote git repository.\n */\nexport class VendorService {\n protected readonly log = $logger();\n protected readonly shell = $inject(ShellProvider);\n protected readonly fs = $inject(FileSystemProvider);\n\n /**\n * Sync vendored packages from a remote repository.\n *\n * Shallow-clones the remote once, then:\n * - Without `force`: diffs first. If local modifications exist, aborts\n * and returns the diff result without touching local files.\n * - With `force` (or no changes): removes local copies and replaces them.\n */\n async sync(options: VendorSyncOptions): Promise<VendorSyncResult> {\n const synced: string[] = [];\n const errors: string[] = [];\n let tmpDir: string | undefined;\n\n try {\n tmpDir = await this.cloneRemote(options.remote, options.branch);\n\n if (!options.force) {\n const diffResult = await this.diffFromClone(\n options.root,\n tmpDir,\n options.packages,\n );\n if (diffResult.totalChanges > 0) {\n return { synced: [], errors: [], aborted: diffResult };\n }\n }\n\n for (const pkg of options.packages) {\n const remotePkgDir = this.fs.join(tmpDir, \"packages\", pkg);\n const localPkgDir = this.fs.join(options.root, \"packages\", pkg);\n\n const remoteExists = await this.fs.exists(remotePkgDir);\n if (!remoteExists) {\n errors.push(`Package \"${pkg}\" not found in remote`);\n continue;\n }\n\n this.log.debug(`Syncing package: ${pkg}`);\n\n await this.fs.rm(localPkgDir, { recursive: true, force: true });\n await this.fs.cp(remotePkgDir, localPkgDir, { recursive: true });\n await this.removeIgnoredFiles(localPkgDir);\n\n synced.push(pkg);\n }\n } finally {\n if (tmpDir) {\n await this.fs.rm(tmpDir, { recursive: true, force: true });\n }\n }\n\n return { synced, errors };\n }\n\n /**\n * Diff vendored packages against a remote repository.\n *\n * Shallow-clones the remote, then for each package: recursively compares\n * files to identify added, modified, and removed files.\n */\n async diff(options: VendorDiffOptions): Promise<VendorDiffResult> {\n let tmpDir: string | undefined;\n\n try {\n tmpDir = await this.cloneRemote(options.remote, options.branch);\n return await this.diffFromClone(options.root, tmpDir, options.packages);\n } finally {\n if (tmpDir) {\n await this.fs.rm(tmpDir, { recursive: true, force: true });\n }\n }\n }\n\n /**\n * Diff local packages against an already-cloned remote.\n */\n protected async diffFromClone(\n root: string,\n tmpDir: string,\n packages: string[],\n ): Promise<VendorDiffResult> {\n const results: VendorPackageDiff[] = [];\n let totalChanges = 0;\n\n for (const pkg of packages) {\n const remotePkgDir = this.fs.join(tmpDir, \"packages\", pkg);\n const localPkgDir = this.fs.join(root, \"packages\", pkg);\n\n const remoteExists = await this.fs.exists(remotePkgDir);\n const localExists = await this.fs.exists(localPkgDir);\n\n if (!remoteExists && !localExists) {\n results.push({ name: pkg, added: [], modified: [], removed: [] });\n continue;\n }\n\n if (!remoteExists) {\n const localFiles = await this.fs.ls(localPkgDir, { recursive: true });\n results.push({\n name: pkg,\n added: [],\n modified: [],\n removed: localFiles,\n });\n totalChanges += localFiles.length;\n continue;\n }\n\n if (!localExists) {\n const remoteFiles = await this.fs.ls(remotePkgDir, { recursive: true });\n results.push({\n name: pkg,\n added: remoteFiles,\n modified: [],\n removed: [],\n });\n totalChanges += remoteFiles.length;\n continue;\n }\n\n const result = await this.diffDirectories(localPkgDir, remotePkgDir);\n const pkgChanges =\n result.added.length + result.modified.length + result.removed.length;\n totalChanges += pkgChanges;\n\n results.push({\n name: pkg,\n added: result.added,\n modified: result.modified,\n removed: result.removed,\n });\n }\n\n return { packages: results, totalChanges };\n }\n\n /**\n * Remove test files and ignored directories from a synced package.\n */\n protected async removeIgnoredFiles(pkgDir: string): Promise<void> {\n const allFiles = await this.fs.ls(pkgDir, { recursive: true });\n\n // Remove ignored files\n for (const file of allFiles) {\n if (\n file.endsWith(\".spec.ts\") ||\n file.endsWith(\".spec.tsx\") ||\n file === \"LICENSE\"\n ) {\n await this.fs.rm(this.fs.join(pkgDir, file), { force: true });\n }\n }\n\n // Remove ignored directories (find all occurrences at any depth)\n for (const file of allFiles) {\n for (const ignored of this.ignoredPaths) {\n if (\n file === ignored ||\n file.startsWith(`${ignored}/`) ||\n file.includes(`/${ignored}/`) ||\n file.endsWith(`/${ignored}`)\n ) {\n // Extract the path to the ignored directory itself\n const idx = file.indexOf(ignored);\n const dirPath = this.fs.join(\n pkgDir,\n file.substring(0, idx + ignored.length),\n );\n await this.fs.rm(dirPath, { recursive: true, force: true });\n }\n }\n }\n }\n\n /**\n * Clone a remote repository into a temporary directory.\n */\n protected async cloneRemote(remote: string, branch: string): Promise<string> {\n const tmpDir = this.fs.join(\n process.env.TMPDIR || \"/tmp\",\n `.alepha-vendor-${Date.now()}`,\n );\n\n this.log.debug(`Cloning ${remote}#${branch} into ${tmpDir}`);\n\n const output = await this.shell.run(\n `git clone --depth 1 --branch ${branch} --filter=blob:none ${remote} ${tmpDir}`,\n { capture: true },\n );\n\n if (output) {\n this.log.debug(output);\n }\n\n return tmpDir;\n }\n\n /**\n * Directories to ignore during diff comparisons.\n */\n protected readonly ignoredPaths = [\n \"__tests__\",\n \"assets/swagger-ui\",\n \"node_modules\",\n \"dist\",\n ];\n\n /**\n * Check if a file path should be ignored during diff.\n */\n protected isIgnored(filePath: string): boolean {\n if (\n filePath.endsWith(\".spec.ts\") ||\n filePath.endsWith(\".spec.tsx\") ||\n filePath === \"LICENSE\"\n ) {\n return true;\n }\n return this.ignoredPaths.some(\n (p) =>\n filePath === p ||\n filePath.startsWith(`${p}/`) ||\n filePath.includes(`/${p}/`) ||\n filePath.endsWith(`/${p}`),\n );\n }\n\n /**\n * Recursively compare two directories and return the differences.\n */\n protected async diffDirectories(\n localDir: string,\n remoteDir: string,\n ): Promise<{ added: string[]; modified: string[]; removed: string[] }> {\n const added: string[] = [];\n const modified: string[] = [];\n const removed: string[] = [];\n\n const [localFiles, remoteFiles] = await Promise.all([\n this.fs.ls(localDir, { recursive: true }),\n this.fs.ls(remoteDir, { recursive: true }),\n ]);\n\n const filteredLocal = localFiles.filter((f) => !this.isIgnored(f));\n const filteredRemote = remoteFiles.filter((f) => !this.isIgnored(f));\n\n const localSet = new Set(filteredLocal);\n const remoteSet = new Set(filteredRemote);\n\n for (const file of filteredRemote) {\n if (!localSet.has(file)) {\n added.push(file);\n continue;\n }\n\n try {\n const [localContent, remoteContent] = await Promise.all([\n this.fs.readFile(this.fs.join(localDir, file)),\n this.fs.readFile(this.fs.join(remoteDir, file)),\n ]);\n\n if (!localContent.equals(remoteContent)) {\n modified.push(file);\n }\n } catch {\n // Skip directories and unreadable entries\n }\n }\n\n for (const file of filteredLocal) {\n if (!remoteSet.has(file)) {\n removed.push(file);\n }\n }\n\n return { added, modified, removed };\n }\n}\n","import { $inject, $state, AlephaError, t } from \"alepha\";\nimport { PackageManagerUtils } from \"alepha/cli\";\nimport { $command } from \"alepha/command\";\nimport { $logger, ConsoleColorProvider } from \"alepha/logger\";\nimport { vendorOptions } from \"../atoms/vendorOptions.ts\";\nimport type {\n VendorDiffResult,\n VendorSyncResult,\n} from \"../services/VendorService.ts\";\nimport { VendorService } from \"../services/VendorService.ts\";\n\n/**\n * Default remote when none is configured.\n */\nconst DEFAULT_REMOTE = \"git@github.com:feunard/alepha.git\";\n\nexport class VendorCommand {\n protected readonly log = $logger();\n protected readonly options = $state(vendorOptions);\n protected readonly vendorService = $inject(VendorService);\n protected readonly color = $inject(ConsoleColorProvider);\n protected readonly pm = $inject(PackageManagerUtils);\n\n /**\n * Ensure vendor config is present and return resolved options.\n */\n protected resolveOptions() {\n if (!this.options) {\n throw new AlephaError(\n 'Missing vendor configuration. Add a \"vendor\" section to alepha.config.ts.',\n );\n }\n return {\n remote: this.options.remote ?? DEFAULT_REMOTE,\n branch: this.options.branch ?? \"main\",\n packages: this.options.packages,\n };\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // alepha vendor sync\n // ─────────────────────────────────────────────────────────────────────────\n\n protected readonly syncFlags = t.object({\n force: t.optional(\n t.boolean({\n aliases: [\"f\"],\n description: \"Skip local modification check\",\n }),\n ),\n });\n\n protected readonly sync = $command({\n name: \"sync\",\n description: \"Replace local packages with remote source\",\n flags: this.syncFlags,\n handler: async ({ flags, root, run }) => {\n const opts = this.resolveOptions();\n const c = this.color;\n\n let result: VendorSyncResult = { synced: [], errors: [] };\n\n await run({\n name: `Syncing from ${opts.branch}`,\n handler: async () => {\n result = await this.vendorService.sync({\n root,\n remote: opts.remote,\n branch: opts.branch,\n packages: opts.packages,\n force: flags.force,\n });\n },\n });\n\n if (result.aborted) {\n run.end();\n\n process.stdout.write(\n `\\nLocal modifications detected. Use ${c.set(\"CYAN\", \"--force\")} to overwrite.\\n`,\n );\n\n for (const pkg of result.aborted.packages) {\n const count =\n pkg.added.length + pkg.modified.length + pkg.removed.length;\n if (count === 0) continue;\n\n process.stdout.write(\n `\\n${c.set(\"CYAN\", pkg.name)}: ${count} ${count === 1 ? \"file differs\" : \"files differ\"}\\n`,\n );\n for (const file of pkg.added) {\n process.stdout.write(` ${c.set(\"GREEN\", \"A\")} ${file}\\n`);\n }\n for (const file of pkg.modified) {\n process.stdout.write(` ${c.set(\"ORANGE\", \"M\")} ${file}\\n`);\n }\n for (const file of pkg.removed) {\n process.stdout.write(` ${c.set(\"RED\", \"D\")} ${file}\\n`);\n }\n }\n\n process.stdout.write(\"\\n\");\n return;\n }\n\n if (result.synced.length > 0) {\n const pmName = await this.pm.getPackageManager(root);\n await run(`${pmName} install`, { root });\n }\n\n run.end();\n\n if (result.errors.length > 0) {\n for (const error of result.errors) {\n process.stdout.write(`${c.set(\"RED\", \" error\")} ${error}\\n`);\n }\n }\n\n if (result.synced.length > 0) {\n process.stdout.write(\n `\\nSynced ${c.set(\"CYAN\", String(result.synced.length))} ${result.synced.length === 1 ? \"package\" : \"packages\"} from ${c.set(\"CYAN\", opts.branch)}\\n`,\n );\n for (const pkg of result.synced) {\n process.stdout.write(` ${c.set(\"GREEN\", \"\\u2713\")} ${pkg}\\n`);\n }\n }\n\n process.stdout.write(\"\\n\");\n },\n });\n\n // ─────────────────────────────────────────────────────────────────────────\n // alepha vendor diff\n // ─────────────────────────────────────────────────────────────────────────\n\n protected readonly diff = $command({\n name: \"diff\",\n description: \"Compare local packages against remote\",\n handler: async ({ root, run }) => {\n const opts = this.resolveOptions();\n\n let result: VendorDiffResult = { packages: [], totalChanges: 0 };\n\n await run({\n name: `Cloning ${opts.remote} at ${opts.branch}`,\n handler: async () => {\n result = await this.vendorService.diff({\n root,\n remote: opts.remote,\n branch: opts.branch,\n packages: opts.packages,\n });\n },\n });\n\n run.end();\n\n if (result.totalChanges === 0) {\n process.stdout.write(\"\\nNo changes\\n\\n\");\n return;\n }\n\n const c = this.color;\n\n for (const pkg of result.packages) {\n const count =\n pkg.added.length + pkg.modified.length + pkg.removed.length;\n if (count === 0) {\n process.stdout.write(`\\n${c.set(\"CYAN\", pkg.name)}: no changes\\n`);\n continue;\n }\n\n process.stdout.write(\n `\\n${c.set(\"CYAN\", pkg.name)}: ${count} ${count === 1 ? \"file differs\" : \"files differ\"}\\n`,\n );\n\n for (const file of pkg.added) {\n process.stdout.write(` ${c.set(\"GREEN\", \"A\")} ${file}\\n`);\n }\n for (const file of pkg.modified) {\n process.stdout.write(` ${c.set(\"ORANGE\", \"M\")} ${file}\\n`);\n }\n for (const file of pkg.removed) {\n process.stdout.write(` ${c.set(\"RED\", \"D\")} ${file}\\n`);\n }\n }\n\n process.stdout.write(\"\\n\");\n },\n });\n\n // ─────────────────────────────────────────────────────────────────────────\n // Parent command\n // ─────────────────────────────────────────────────────────────────────────\n\n public readonly vendor = $command({\n name: \"vendor\",\n description: \"Vendor Alepha packages into the project\",\n children: [this.sync, this.diff],\n handler: async ({ help }) => {\n help();\n },\n });\n}\n","import { $module } from \"alepha\";\nimport { vendorOptions } from \"./atoms/vendorOptions.ts\";\nimport { VendorCommand } from \"./commands/VendorCommand.ts\";\nimport { VendorService } from \"./services/VendorService.ts\";\n\n// ---------------------------------------------------------------------------\n\n/**\n * CLI plugin for vendoring Alepha packages into external projects.\n *\n * Copies package source code from a git remote into the current project's\n * `packages/` directory. Useful for corporate projects that need a local\n * copy of Alepha for AI tooling, audits, documentation, or quick fixes.\n *\n * Commands:\n * - `alepha vendor sync` — replace local packages with remote source\n * - `alepha vendor diff` — compare local packages against remote HEAD\n *\n * Configuration in `alepha.config.ts`:\n *\n * ```typescript\n * import { AlephaCliVendor } from \"alepha/cli/vendor\";\n *\n * export default defineConfig({\n * services: [AlephaCliVendor],\n * vendor: {\n * branch: \"main\",\n * packages: [\"alepha\", \"@alepha/bucket-s3\"],\n * },\n * });\n * ```\n */\nexport const AlephaCliVendorPlugin = $module({\n name: \"alepha.cli.plugins.vendor\",\n atoms: [vendorOptions],\n services: [VendorCommand, VendorService],\n});\n\n// ---------------------------------------------------------------------------\n\nexport * from \"./atoms/vendorOptions.ts\";\nexport * from \"./commands/VendorCommand.ts\";\nexport * from \"./services/VendorService.ts\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/cli/vendor/atoms/vendorOptions.ts","../../../src/cli/vendor/services/VendorService.ts","../../../src/cli/vendor/commands/VendorCommand.ts","../../../src/cli/vendor/index.ts"],"sourcesContent":["import { $atom, type Static, t } from \"alepha\";\n\n/**\n * Vendor configuration atom.\n *\n * Filled from the `vendor` section of `alepha.config.ts`.\n * Read by `VendorCommand` to resolve remote, branch, and packages.\n */\nexport const vendorOptions = $atom({\n name: \"alepha.cli.vendor.options\",\n description: \"Vendor synchronization configuration\",\n schema: t.optional(\n t.object({\n /**\n * Git remote URL.\n *\n * @default \"git@github.com:feunard/alepha.git\"\n */\n remote: t.optional(t.text()),\n\n /**\n * Branch to sync from.\n *\n * @default \"main\"\n */\n branch: t.optional(t.text()),\n\n /**\n * Package directory names under `packages/` to sync.\n *\n * @example [\"alepha\", \"@alepha/bucket-s3\"]\n */\n packages: t.array(t.text()),\n }),\n ),\n});\n\n/**\n * Type for vendor options.\n */\nexport type VendorOptions = Static<typeof vendorOptions.schema>;\n","import { $inject } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { FileSystemProvider, ShellProvider } from \"alepha/system\";\n\n/**\n * Options for syncing vendored packages from a remote repository.\n */\nexport interface VendorSyncOptions {\n root: string;\n remote: string;\n branch: string;\n packages: string[];\n force?: boolean;\n}\n\n/**\n * Result of a vendor sync operation.\n */\nexport interface VendorSyncResult {\n synced: string[];\n errors: string[];\n aborted?: VendorDiffResult;\n}\n\n/**\n * Options for diffing vendored packages against a remote repository.\n */\nexport interface VendorDiffOptions {\n root: string;\n remote: string;\n branch: string;\n packages: string[];\n}\n\n/**\n * Diff result for a single vendored package.\n */\nexport interface VendorPackageDiff {\n name: string;\n added: string[];\n modified: string[];\n removed: string[];\n}\n\n/**\n * Result of a vendor diff operation.\n */\nexport interface VendorDiffResult {\n packages: VendorPackageDiff[];\n totalChanges: number;\n}\n\n/**\n * Shape of the <root>/.alepha/vendor.json lock file.\n */\nexport interface VendorLock {\n commit: string;\n}\n\n/**\n * Handles syncing and diffing vendored packages from a remote git repository.\n */\nexport class VendorService {\n protected readonly log = $logger();\n protected readonly shell = $inject(ShellProvider);\n protected readonly fs = $inject(FileSystemProvider);\n\n /**\n * Sync vendored packages from a remote repository.\n *\n * Without `force`: checks for local modifications by comparing the local\n * copy against the last-synced commit (stored in .alepha/vendor.json).\n * If modifications are found, aborts without touching local files.\n *\n * With `force` (or first sync): replaces local copies unconditionally.\n */\n async sync(options: VendorSyncOptions): Promise<VendorSyncResult> {\n const synced: string[] = [];\n const errors: string[] = [];\n\n if (!options.force) {\n const lock = await this.readLock(options.root);\n\n if (lock) {\n let baselineDir: string | undefined;\n try {\n baselineDir = await this.cloneAtCommit(options.remote, lock.commit);\n const diffResult = await this.diffFromClone(\n options.root,\n baselineDir,\n options.packages,\n );\n\n if (diffResult.totalChanges > 0) {\n return { synced: [], errors: [], aborted: diffResult };\n }\n } finally {\n if (baselineDir) {\n await this.fs.rm(baselineDir, { recursive: true, force: true });\n }\n }\n }\n }\n\n let tmpDir: string | undefined;\n\n try {\n tmpDir = await this.cloneRemote(options.remote, options.branch);\n\n for (const pkg of options.packages) {\n const remotePkgDir = this.fs.join(tmpDir, \"packages\", pkg);\n const localPkgDir = this.fs.join(options.root, \"packages\", pkg);\n\n const remoteExists = await this.fs.exists(remotePkgDir);\n if (!remoteExists) {\n errors.push(`Package \"${pkg}\" not found in remote`);\n continue;\n }\n\n this.log.debug(`Syncing package: ${pkg}`);\n\n await this.fs.rm(localPkgDir, { recursive: true, force: true });\n await this.fs.cp(remotePkgDir, localPkgDir, { recursive: true });\n await this.removeIgnoredFiles(localPkgDir);\n\n synced.push(pkg);\n }\n\n const commit = await this.getCommitHash(tmpDir);\n await this.writeLock(options.root, { commit });\n } finally {\n if (tmpDir) {\n await this.fs.rm(tmpDir, { recursive: true, force: true });\n }\n }\n\n return { synced, errors };\n }\n\n /**\n * Diff vendored packages against the last-synced commit.\n *\n * Reads the commit hash from .alepha/vendor.json, clones at that commit,\n * and compares local files to detect modifications since last sync.\n */\n async diff(options: VendorDiffOptions): Promise<VendorDiffResult> {\n const lock = await this.readLock(options.root);\n if (!lock) {\n return { packages: [], totalChanges: 0 };\n }\n\n let tmpDir: string | undefined;\n\n try {\n tmpDir = await this.cloneAtCommit(options.remote, lock.commit);\n return await this.diffFromClone(options.root, tmpDir, options.packages);\n } finally {\n if (tmpDir) {\n await this.fs.rm(tmpDir, { recursive: true, force: true });\n }\n }\n }\n\n /**\n * Diff local packages against an already-cloned remote.\n */\n protected async diffFromClone(\n root: string,\n tmpDir: string,\n packages: string[],\n ): Promise<VendorDiffResult> {\n const results: VendorPackageDiff[] = [];\n let totalChanges = 0;\n\n for (const pkg of packages) {\n const remotePkgDir = this.fs.join(tmpDir, \"packages\", pkg);\n const localPkgDir = this.fs.join(root, \"packages\", pkg);\n\n const remoteExists = await this.fs.exists(remotePkgDir);\n const localExists = await this.fs.exists(localPkgDir);\n\n if (!remoteExists && !localExists) {\n results.push({ name: pkg, added: [], modified: [], removed: [] });\n continue;\n }\n\n if (!remoteExists) {\n // No baseline = everything local was added by user\n const localFiles = await this.fs.ls(localPkgDir, { recursive: true });\n results.push({\n name: pkg,\n added: localFiles,\n modified: [],\n removed: [],\n });\n totalChanges += localFiles.length;\n continue;\n }\n\n if (!localExists) {\n // Baseline exists but local doesn't = user deleted everything\n const remoteFiles = await this.fs.ls(remotePkgDir, { recursive: true });\n results.push({\n name: pkg,\n added: [],\n modified: [],\n removed: remoteFiles,\n });\n totalChanges += remoteFiles.length;\n continue;\n }\n\n const result = await this.diffDirectories(localPkgDir, remotePkgDir);\n const pkgChanges =\n result.added.length + result.modified.length + result.removed.length;\n totalChanges += pkgChanges;\n\n results.push({\n name: pkg,\n added: result.added,\n modified: result.modified,\n removed: result.removed,\n });\n }\n\n return { packages: results, totalChanges };\n }\n\n /**\n * Remove test files and ignored directories from a synced package.\n */\n protected async removeIgnoredFiles(pkgDir: string): Promise<void> {\n const allFiles = await this.fs.ls(pkgDir, { recursive: true });\n\n // Remove ignored files\n for (const file of allFiles) {\n if (\n file.endsWith(\".spec.ts\") ||\n file.endsWith(\".spec.tsx\") ||\n file === \"LICENSE\" ||\n file === \"tsdown.config.ts\"\n ) {\n await this.fs.rm(this.fs.join(pkgDir, file), { force: true });\n }\n }\n\n // Remove ignored directories (find all occurrences at any depth)\n for (const file of allFiles) {\n for (const ignored of this.ignoredPaths) {\n if (\n file === ignored ||\n file.startsWith(`${ignored}/`) ||\n file.includes(`/${ignored}/`) ||\n file.endsWith(`/${ignored}`)\n ) {\n // Extract the path to the ignored directory itself\n const idx = file.indexOf(ignored);\n const dirPath = this.fs.join(\n pkgDir,\n file.substring(0, idx + ignored.length),\n );\n await this.fs.rm(dirPath, { recursive: true, force: true });\n }\n }\n }\n }\n\n /**\n * Clone a remote repository into a temporary directory.\n */\n protected async cloneRemote(remote: string, branch: string): Promise<string> {\n const tmpDir = this.fs.join(\n process.env.TMPDIR || \"/tmp\",\n `.alepha-vendor-${Date.now()}`,\n );\n\n this.log.debug(`Cloning ${remote}#${branch} into ${tmpDir}`);\n\n const output = await this.shell.run(\n `git clone --depth 1 --branch ${branch} --filter=blob:none ${remote} ${tmpDir}`,\n { capture: true },\n );\n\n if (output) {\n this.log.debug(output);\n }\n\n return tmpDir;\n }\n\n /**\n * Clone a remote repository at a specific commit hash.\n */\n protected async cloneAtCommit(\n remote: string,\n commit: string,\n ): Promise<string> {\n const tmpDir = this.fs.join(\n process.env.TMPDIR || \"/tmp\",\n `.alepha-vendor-${Date.now()}`,\n );\n\n this.log.debug(`Cloning ${remote}@${commit} into ${tmpDir}`);\n\n await this.shell.run(`git init ${tmpDir}`, { capture: true });\n await this.shell.run(`git -C ${tmpDir} remote add origin ${remote}`, {\n capture: true,\n });\n await this.shell.run(`git -C ${tmpDir} fetch --depth 1 origin ${commit}`, {\n capture: true,\n });\n await this.shell.run(`git -C ${tmpDir} checkout FETCH_HEAD`, {\n capture: true,\n });\n\n return tmpDir;\n }\n\n /**\n * Get the HEAD commit hash from a cloned repository.\n */\n protected async getCommitHash(repoDir: string): Promise<string> {\n const hash = await this.shell.run(`git -C ${repoDir} rev-parse HEAD`, {\n capture: true,\n });\n return hash.trim();\n }\n\n /**\n * Read the vendor lock file.\n */\n protected async readLock(root: string): Promise<VendorLock | undefined> {\n const lockPath = this.fs.join(root, \".alepha\", \"vendor.json\");\n const exists = await this.fs.exists(lockPath);\n if (!exists) {\n return undefined;\n }\n const content = await this.fs.readFile(lockPath);\n return JSON.parse(content.toString());\n }\n\n /**\n * Write the vendor lock file.\n */\n protected async writeLock(root: string, lock: VendorLock): Promise<void> {\n const dir = this.fs.join(root, \".alepha\");\n await this.fs.mkdir(dir, { recursive: true });\n await this.fs.writeFile(\n this.fs.join(dir, \"vendor.json\"),\n JSON.stringify(lock, null, 2),\n );\n }\n\n /**\n * Directories to ignore during diff comparisons.\n */\n protected readonly ignoredPaths = [\n \"__tests__\",\n \"assets/swagger-ui\",\n \"node_modules\",\n \"dist\",\n ];\n\n /**\n * Check if a file path should be ignored during diff.\n */\n protected isIgnored(filePath: string): boolean {\n if (\n filePath.endsWith(\".spec.ts\") ||\n filePath.endsWith(\".spec.tsx\") ||\n filePath === \"LICENSE\" ||\n filePath === \"tsdown.config.ts\"\n ) {\n return true;\n }\n return this.ignoredPaths.some(\n (p) =>\n filePath === p ||\n filePath.startsWith(`${p}/`) ||\n filePath.includes(`/${p}/`) ||\n filePath.endsWith(`/${p}`),\n );\n }\n\n /**\n * Recursively compare two directories and return the differences.\n */\n protected async diffDirectories(\n localDir: string,\n remoteDir: string,\n ): Promise<{ added: string[]; modified: string[]; removed: string[] }> {\n const added: string[] = [];\n const modified: string[] = [];\n const removed: string[] = [];\n\n const [localFiles, remoteFiles] = await Promise.all([\n this.fs.ls(localDir, { recursive: true }),\n this.fs.ls(remoteDir, { recursive: true }),\n ]);\n\n const filteredLocal = localFiles.filter((f) => !this.isIgnored(f));\n const filteredRemote = remoteFiles.filter((f) => !this.isIgnored(f));\n\n const localSet = new Set(filteredLocal);\n const remoteSet = new Set(filteredRemote);\n\n // Files in baseline but not local = user deleted them\n for (const file of filteredRemote) {\n if (!localSet.has(file)) {\n removed.push(file);\n continue;\n }\n\n try {\n const [localContent, remoteContent] = await Promise.all([\n this.fs.readFile(this.fs.join(localDir, file)),\n this.fs.readFile(this.fs.join(remoteDir, file)),\n ]);\n\n if (!localContent.equals(remoteContent)) {\n modified.push(file);\n }\n } catch {\n // Skip directories and unreadable entries\n }\n }\n\n // Files in local but not baseline = user added them\n for (const file of filteredLocal) {\n if (!remoteSet.has(file)) {\n added.push(file);\n }\n }\n\n return { added, modified, removed };\n }\n}\n","import { $inject, $state, AlephaError, t } from \"alepha\";\nimport { PackageManagerUtils } from \"alepha/cli\";\nimport { $command } from \"alepha/command\";\nimport { $logger, ConsoleColorProvider } from \"alepha/logger\";\nimport { vendorOptions } from \"../atoms/vendorOptions.ts\";\nimport type {\n VendorDiffResult,\n VendorSyncResult,\n} from \"../services/VendorService.ts\";\nimport { VendorService } from \"../services/VendorService.ts\";\n\n/**\n * Default remote when none is configured.\n */\nconst DEFAULT_REMOTE = \"git@github.com:feunard/alepha.git\";\n\nexport class VendorCommand {\n protected readonly log = $logger();\n protected readonly options = $state(vendorOptions);\n protected readonly vendorService = $inject(VendorService);\n protected readonly color = $inject(ConsoleColorProvider);\n protected readonly pm = $inject(PackageManagerUtils);\n\n /**\n * Ensure vendor config is present and return resolved options.\n */\n protected resolveOptions() {\n if (!this.options) {\n throw new AlephaError(\n 'Missing vendor configuration. Add a \"vendor\" section to alepha.config.ts.',\n );\n }\n return {\n remote: this.options.remote ?? DEFAULT_REMOTE,\n branch: this.options.branch ?? \"main\",\n packages: this.options.packages,\n };\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // alepha vendor sync\n // ─────────────────────────────────────────────────────────────────────────\n\n protected readonly syncFlags = t.object({\n force: t.optional(\n t.boolean({\n aliases: [\"f\"],\n description: \"Skip local modification check\",\n }),\n ),\n });\n\n protected readonly sync = $command({\n name: \"sync\",\n description: \"Replace local packages with remote source\",\n flags: this.syncFlags,\n handler: async ({ flags, root, run }) => {\n const opts = this.resolveOptions();\n const c = this.color;\n\n let result: VendorSyncResult = { synced: [], errors: [] };\n\n await run({\n name: `Syncing from ${opts.branch}`,\n handler: async () => {\n result = await this.vendorService.sync({\n root,\n remote: opts.remote,\n branch: opts.branch,\n packages: opts.packages,\n force: flags.force,\n });\n },\n });\n\n if (result.aborted) {\n run.end();\n\n process.stdout.write(\n `\\nLocal modifications detected. Use ${c.set(\"CYAN\", \"--force\")} to overwrite.\\n`,\n );\n\n for (const pkg of result.aborted.packages) {\n const count =\n pkg.added.length + pkg.modified.length + pkg.removed.length;\n if (count === 0) continue;\n\n process.stdout.write(\n `\\n${c.set(\"CYAN\", pkg.name)}: ${count} ${count === 1 ? \"file differs\" : \"files differ\"}\\n`,\n );\n for (const file of pkg.added) {\n process.stdout.write(` ${c.set(\"GREEN\", \"A\")} ${file}\\n`);\n }\n for (const file of pkg.modified) {\n process.stdout.write(` ${c.set(\"ORANGE\", \"M\")} ${file}\\n`);\n }\n for (const file of pkg.removed) {\n process.stdout.write(` ${c.set(\"RED\", \"D\")} ${file}\\n`);\n }\n }\n\n process.stdout.write(\"\\n\");\n return;\n }\n\n if (result.synced.length > 0) {\n const pmName = await this.pm.getPackageManager(root);\n await run(`${pmName} install`, { root });\n }\n\n run.end();\n\n if (result.errors.length > 0) {\n for (const error of result.errors) {\n process.stdout.write(`${c.set(\"RED\", \" error\")} ${error}\\n`);\n }\n }\n\n if (result.synced.length > 0) {\n process.stdout.write(\n `\\nSynced ${c.set(\"CYAN\", String(result.synced.length))} ${result.synced.length === 1 ? \"package\" : \"packages\"} from ${c.set(\"CYAN\", opts.branch)}\\n`,\n );\n for (const pkg of result.synced) {\n process.stdout.write(` ${c.set(\"GREEN\", \"\\u2713\")} ${pkg}\\n`);\n }\n }\n\n process.stdout.write(\"\\n\");\n },\n });\n\n // ─────────────────────────────────────────────────────────────────────────\n // alepha vendor diff\n // ─────────────────────────────────────────────────────────────────────────\n\n protected readonly diff = $command({\n name: \"diff\",\n description: \"Compare local packages against remote\",\n handler: async ({ root, run }) => {\n const opts = this.resolveOptions();\n\n let result: VendorDiffResult = { packages: [], totalChanges: 0 };\n\n await run({\n name: `Cloning ${opts.remote} at ${opts.branch}`,\n handler: async () => {\n result = await this.vendorService.diff({\n root,\n remote: opts.remote,\n branch: opts.branch,\n packages: opts.packages,\n });\n },\n });\n\n run.end();\n\n if (result.totalChanges === 0) {\n process.stdout.write(\"\\nNo changes\\n\\n\");\n return;\n }\n\n const c = this.color;\n\n for (const pkg of result.packages) {\n const count =\n pkg.added.length + pkg.modified.length + pkg.removed.length;\n if (count === 0) {\n process.stdout.write(`\\n${c.set(\"CYAN\", pkg.name)}: no changes\\n`);\n continue;\n }\n\n process.stdout.write(\n `\\n${c.set(\"CYAN\", pkg.name)}: ${count} ${count === 1 ? \"file differs\" : \"files differ\"}\\n`,\n );\n\n for (const file of pkg.added) {\n process.stdout.write(` ${c.set(\"GREEN\", \"A\")} ${file}\\n`);\n }\n for (const file of pkg.modified) {\n process.stdout.write(` ${c.set(\"ORANGE\", \"M\")} ${file}\\n`);\n }\n for (const file of pkg.removed) {\n process.stdout.write(` ${c.set(\"RED\", \"D\")} ${file}\\n`);\n }\n }\n\n process.stdout.write(\"\\n\");\n },\n });\n\n // ─────────────────────────────────────────────────────────────────────────\n // Parent command\n // ─────────────────────────────────────────────────────────────────────────\n\n public readonly vendor = $command({\n name: \"vendor\",\n description: \"Vendor Alepha packages into the project\",\n children: [this.sync, this.diff],\n handler: async ({ help }) => {\n help();\n },\n });\n}\n","import { $module } from \"alepha\";\nimport { cliConfigPlugins } from \"alepha/cli/config\";\nimport { type VendorOptions, vendorOptions } from \"./atoms/vendorOptions.ts\";\nimport { VendorCommand } from \"./commands/VendorCommand.ts\";\nimport { VendorService } from \"./services/VendorService.ts\";\n\n// ---------------------------------------------------------------------------\n\ndeclare module \"alepha/cli/config\" {\n interface AlephaCliConfig {\n vendor?: VendorOptions;\n }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * CLI plugin for vendoring Alepha packages into external projects.\n *\n * Copies package source code from a git remote into the current project's\n * `packages/` directory. Useful for corporate projects that need a local\n * copy of Alepha for AI tooling, audits, documentation, or quick fixes.\n *\n * Commands:\n * - `alepha vendor sync` — replace local packages with remote source\n * - `alepha vendor diff` — compare local packages against remote HEAD\n *\n * Configuration in `alepha.config.ts`:\n *\n * ```typescript\n * import { AlephaCliVendorPlugin } from \"alepha/cli/vendor\";\n *\n * export default defineConfig({\n * services: [AlephaCliVendorPlugin],\n * vendor: {\n * branch: \"main\",\n * packages: [\"alepha\", \"@alepha/bucket-s3\"],\n * },\n * });\n * ```\n */\nexport const AlephaCliVendorPlugin = $module({\n name: \"alepha.cli.plugins.vendor\",\n atoms: [vendorOptions],\n services: [VendorCommand, VendorService],\n});\n\n// ---------------------------------------------------------------------------\n\ncliConfigPlugins.push((config, alepha) => {\n if (config.vendor) {\n alepha.set(vendorOptions, config.vendor);\n }\n});\n\n// ---------------------------------------------------------------------------\n\nexport * from \"./atoms/vendorOptions.ts\";\nexport * from \"./commands/VendorCommand.ts\";\nexport * from \"./services/VendorService.ts\";\n"],"mappings":";;;;;;;;;;;;;AAQA,MAAa,gBAAgB,MAAM;CACjC,MAAM;CACN,aAAa;CACb,QAAQ,EAAE,SACR,EAAE,OAAO;EAMP,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC;EAO5B,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC;EAO5B,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC;EAC5B,CAAC,CACH;CACF,CAAC;;;;;;AC2BF,IAAa,gBAAb,MAA2B;CACzB,MAAyB,SAAS;CAClC,QAA2B,QAAQ,cAAc;CACjD,KAAwB,QAAQ,mBAAmB;;;;;;;;;;CAWnD,MAAM,KAAK,SAAuD;EAChE,MAAM,SAAmB,EAAE;EAC3B,MAAM,SAAmB,EAAE;AAE3B,MAAI,CAAC,QAAQ,OAAO;GAClB,MAAM,OAAO,MAAM,KAAK,SAAS,QAAQ,KAAK;AAE9C,OAAI,MAAM;IACR,IAAI;AACJ,QAAI;AACF,mBAAc,MAAM,KAAK,cAAc,QAAQ,QAAQ,KAAK,OAAO;KACnE,MAAM,aAAa,MAAM,KAAK,cAC5B,QAAQ,MACR,aACA,QAAQ,SACT;AAED,SAAI,WAAW,eAAe,EAC5B,QAAO;MAAE,QAAQ,EAAE;MAAE,QAAQ,EAAE;MAAE,SAAS;MAAY;cAEhD;AACR,SAAI,YACF,OAAM,KAAK,GAAG,GAAG,aAAa;MAAE,WAAW;MAAM,OAAO;MAAM,CAAC;;;;EAMvE,IAAI;AAEJ,MAAI;AACF,YAAS,MAAM,KAAK,YAAY,QAAQ,QAAQ,QAAQ,OAAO;AAE/D,QAAK,MAAM,OAAO,QAAQ,UAAU;IAClC,MAAM,eAAe,KAAK,GAAG,KAAK,QAAQ,YAAY,IAAI;IAC1D,MAAM,cAAc,KAAK,GAAG,KAAK,QAAQ,MAAM,YAAY,IAAI;AAG/D,QAAI,CADiB,MAAM,KAAK,GAAG,OAAO,aAAa,EACpC;AACjB,YAAO,KAAK,YAAY,IAAI,uBAAuB;AACnD;;AAGF,SAAK,IAAI,MAAM,oBAAoB,MAAM;AAEzC,UAAM,KAAK,GAAG,GAAG,aAAa;KAAE,WAAW;KAAM,OAAO;KAAM,CAAC;AAC/D,UAAM,KAAK,GAAG,GAAG,cAAc,aAAa,EAAE,WAAW,MAAM,CAAC;AAChE,UAAM,KAAK,mBAAmB,YAAY;AAE1C,WAAO,KAAK,IAAI;;GAGlB,MAAM,SAAS,MAAM,KAAK,cAAc,OAAO;AAC/C,SAAM,KAAK,UAAU,QAAQ,MAAM,EAAE,QAAQ,CAAC;YACtC;AACR,OAAI,OACF,OAAM,KAAK,GAAG,GAAG,QAAQ;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;;AAI9D,SAAO;GAAE;GAAQ;GAAQ;;;;;;;;CAS3B,MAAM,KAAK,SAAuD;EAChE,MAAM,OAAO,MAAM,KAAK,SAAS,QAAQ,KAAK;AAC9C,MAAI,CAAC,KACH,QAAO;GAAE,UAAU,EAAE;GAAE,cAAc;GAAG;EAG1C,IAAI;AAEJ,MAAI;AACF,YAAS,MAAM,KAAK,cAAc,QAAQ,QAAQ,KAAK,OAAO;AAC9D,UAAO,MAAM,KAAK,cAAc,QAAQ,MAAM,QAAQ,QAAQ,SAAS;YAC/D;AACR,OAAI,OACF,OAAM,KAAK,GAAG,GAAG,QAAQ;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;;;;;;CAQhE,MAAgB,cACd,MACA,QACA,UAC2B;EAC3B,MAAM,UAA+B,EAAE;EACvC,IAAI,eAAe;AAEnB,OAAK,MAAM,OAAO,UAAU;GAC1B,MAAM,eAAe,KAAK,GAAG,KAAK,QAAQ,YAAY,IAAI;GAC1D,MAAM,cAAc,KAAK,GAAG,KAAK,MAAM,YAAY,IAAI;GAEvD,MAAM,eAAe,MAAM,KAAK,GAAG,OAAO,aAAa;GACvD,MAAM,cAAc,MAAM,KAAK,GAAG,OAAO,YAAY;AAErD,OAAI,CAAC,gBAAgB,CAAC,aAAa;AACjC,YAAQ,KAAK;KAAE,MAAM;KAAK,OAAO,EAAE;KAAE,UAAU,EAAE;KAAE,SAAS,EAAE;KAAE,CAAC;AACjE;;AAGF,OAAI,CAAC,cAAc;IAEjB,MAAM,aAAa,MAAM,KAAK,GAAG,GAAG,aAAa,EAAE,WAAW,MAAM,CAAC;AACrE,YAAQ,KAAK;KACX,MAAM;KACN,OAAO;KACP,UAAU,EAAE;KACZ,SAAS,EAAE;KACZ,CAAC;AACF,oBAAgB,WAAW;AAC3B;;AAGF,OAAI,CAAC,aAAa;IAEhB,MAAM,cAAc,MAAM,KAAK,GAAG,GAAG,cAAc,EAAE,WAAW,MAAM,CAAC;AACvE,YAAQ,KAAK;KACX,MAAM;KACN,OAAO,EAAE;KACT,UAAU,EAAE;KACZ,SAAS;KACV,CAAC;AACF,oBAAgB,YAAY;AAC5B;;GAGF,MAAM,SAAS,MAAM,KAAK,gBAAgB,aAAa,aAAa;GACpE,MAAM,aACJ,OAAO,MAAM,SAAS,OAAO,SAAS,SAAS,OAAO,QAAQ;AAChE,mBAAgB;AAEhB,WAAQ,KAAK;IACX,MAAM;IACN,OAAO,OAAO;IACd,UAAU,OAAO;IACjB,SAAS,OAAO;IACjB,CAAC;;AAGJ,SAAO;GAAE,UAAU;GAAS;GAAc;;;;;CAM5C,MAAgB,mBAAmB,QAA+B;EAChE,MAAM,WAAW,MAAM,KAAK,GAAG,GAAG,QAAQ,EAAE,WAAW,MAAM,CAAC;AAG9D,OAAK,MAAM,QAAQ,SACjB,KACE,KAAK,SAAS,WAAW,IACzB,KAAK,SAAS,YAAY,IAC1B,SAAS,aACT,SAAS,mBAET,OAAM,KAAK,GAAG,GAAG,KAAK,GAAG,KAAK,QAAQ,KAAK,EAAE,EAAE,OAAO,MAAM,CAAC;AAKjE,OAAK,MAAM,QAAQ,SACjB,MAAK,MAAM,WAAW,KAAK,aACzB,KACE,SAAS,WACT,KAAK,WAAW,GAAG,QAAQ,GAAG,IAC9B,KAAK,SAAS,IAAI,QAAQ,GAAG,IAC7B,KAAK,SAAS,IAAI,UAAU,EAC5B;GAEA,MAAM,MAAM,KAAK,QAAQ,QAAQ;GACjC,MAAM,UAAU,KAAK,GAAG,KACtB,QACA,KAAK,UAAU,GAAG,MAAM,QAAQ,OAAO,CACxC;AACD,SAAM,KAAK,GAAG,GAAG,SAAS;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;;;;;;CASnE,MAAgB,YAAY,QAAgB,QAAiC;EAC3E,MAAM,SAAS,KAAK,GAAG,KACrB,QAAQ,IAAI,UAAU,QACtB,kBAAkB,KAAK,KAAK,GAC7B;AAED,OAAK,IAAI,MAAM,WAAW,OAAO,GAAG,OAAO,QAAQ,SAAS;EAE5D,MAAM,SAAS,MAAM,KAAK,MAAM,IAC9B,gCAAgC,OAAO,sBAAsB,OAAO,GAAG,UACvE,EAAE,SAAS,MAAM,CAClB;AAED,MAAI,OACF,MAAK,IAAI,MAAM,OAAO;AAGxB,SAAO;;;;;CAMT,MAAgB,cACd,QACA,QACiB;EACjB,MAAM,SAAS,KAAK,GAAG,KACrB,QAAQ,IAAI,UAAU,QACtB,kBAAkB,KAAK,KAAK,GAC7B;AAED,OAAK,IAAI,MAAM,WAAW,OAAO,GAAG,OAAO,QAAQ,SAAS;AAE5D,QAAM,KAAK,MAAM,IAAI,YAAY,UAAU,EAAE,SAAS,MAAM,CAAC;AAC7D,QAAM,KAAK,MAAM,IAAI,UAAU,OAAO,qBAAqB,UAAU,EACnE,SAAS,MACV,CAAC;AACF,QAAM,KAAK,MAAM,IAAI,UAAU,OAAO,0BAA0B,UAAU,EACxE,SAAS,MACV,CAAC;AACF,QAAM,KAAK,MAAM,IAAI,UAAU,OAAO,uBAAuB,EAC3D,SAAS,MACV,CAAC;AAEF,SAAO;;;;;CAMT,MAAgB,cAAc,SAAkC;AAI9D,UAHa,MAAM,KAAK,MAAM,IAAI,UAAU,QAAQ,kBAAkB,EACpE,SAAS,MACV,CAAC,EACU,MAAM;;;;;CAMpB,MAAgB,SAAS,MAA+C;EACtE,MAAM,WAAW,KAAK,GAAG,KAAK,MAAM,WAAW,cAAc;AAE7D,MAAI,CADW,MAAM,KAAK,GAAG,OAAO,SAAS,CAE3C;EAEF,MAAM,UAAU,MAAM,KAAK,GAAG,SAAS,SAAS;AAChD,SAAO,KAAK,MAAM,QAAQ,UAAU,CAAC;;;;;CAMvC,MAAgB,UAAU,MAAc,MAAiC;EACvE,MAAM,MAAM,KAAK,GAAG,KAAK,MAAM,UAAU;AACzC,QAAM,KAAK,GAAG,MAAM,KAAK,EAAE,WAAW,MAAM,CAAC;AAC7C,QAAM,KAAK,GAAG,UACZ,KAAK,GAAG,KAAK,KAAK,cAAc,EAChC,KAAK,UAAU,MAAM,MAAM,EAAE,CAC9B;;;;;CAMH,eAAkC;EAChC;EACA;EACA;EACA;EACD;;;;CAKD,UAAoB,UAA2B;AAC7C,MACE,SAAS,SAAS,WAAW,IAC7B,SAAS,SAAS,YAAY,IAC9B,aAAa,aACb,aAAa,mBAEb,QAAO;AAET,SAAO,KAAK,aAAa,MACtB,MACC,aAAa,KACb,SAAS,WAAW,GAAG,EAAE,GAAG,IAC5B,SAAS,SAAS,IAAI,EAAE,GAAG,IAC3B,SAAS,SAAS,IAAI,IAAI,CAC7B;;;;;CAMH,MAAgB,gBACd,UACA,WACqE;EACrE,MAAM,QAAkB,EAAE;EAC1B,MAAM,WAAqB,EAAE;EAC7B,MAAM,UAAoB,EAAE;EAE5B,MAAM,CAAC,YAAY,eAAe,MAAM,QAAQ,IAAI,CAClD,KAAK,GAAG,GAAG,UAAU,EAAE,WAAW,MAAM,CAAC,EACzC,KAAK,GAAG,GAAG,WAAW,EAAE,WAAW,MAAM,CAAC,CAC3C,CAAC;EAEF,MAAM,gBAAgB,WAAW,QAAQ,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC;EAClE,MAAM,iBAAiB,YAAY,QAAQ,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC;EAEpE,MAAM,WAAW,IAAI,IAAI,cAAc;EACvC,MAAM,YAAY,IAAI,IAAI,eAAe;AAGzC,OAAK,MAAM,QAAQ,gBAAgB;AACjC,OAAI,CAAC,SAAS,IAAI,KAAK,EAAE;AACvB,YAAQ,KAAK,KAAK;AAClB;;AAGF,OAAI;IACF,MAAM,CAAC,cAAc,iBAAiB,MAAM,QAAQ,IAAI,CACtD,KAAK,GAAG,SAAS,KAAK,GAAG,KAAK,UAAU,KAAK,CAAC,EAC9C,KAAK,GAAG,SAAS,KAAK,GAAG,KAAK,WAAW,KAAK,CAAC,CAChD,CAAC;AAEF,QAAI,CAAC,aAAa,OAAO,cAAc,CACrC,UAAS,KAAK,KAAK;WAEf;;AAMV,OAAK,MAAM,QAAQ,cACjB,KAAI,CAAC,UAAU,IAAI,KAAK,CACtB,OAAM,KAAK,KAAK;AAIpB,SAAO;GAAE;GAAO;GAAU;GAAS;;;;;;;;ACpavC,MAAM,iBAAiB;AAEvB,IAAa,gBAAb,MAA2B;CACzB,MAAyB,SAAS;CAClC,UAA6B,OAAO,cAAc;CAClD,gBAAmC,QAAQ,cAAc;CACzD,QAA2B,QAAQ,qBAAqB;CACxD,KAAwB,QAAQ,oBAAoB;;;;CAKpD,iBAA2B;AACzB,MAAI,CAAC,KAAK,QACR,OAAM,IAAI,YACR,8EACD;AAEH,SAAO;GACL,QAAQ,KAAK,QAAQ,UAAU;GAC/B,QAAQ,KAAK,QAAQ,UAAU;GAC/B,UAAU,KAAK,QAAQ;GACxB;;CAOH,YAA+B,EAAE,OAAO,EACtC,OAAO,EAAE,SACP,EAAE,QAAQ;EACR,SAAS,CAAC,IAAI;EACd,aAAa;EACd,CAAC,CACH,EACF,CAAC;CAEF,OAA0B,SAAS;EACjC,MAAM;EACN,aAAa;EACb,OAAO,KAAK;EACZ,SAAS,OAAO,EAAE,OAAO,MAAM,UAAU;GACvC,MAAM,OAAO,KAAK,gBAAgB;GAClC,MAAM,IAAI,KAAK;GAEf,IAAI,SAA2B;IAAE,QAAQ,EAAE;IAAE,QAAQ,EAAE;IAAE;AAEzD,SAAM,IAAI;IACR,MAAM,gBAAgB,KAAK;IAC3B,SAAS,YAAY;AACnB,cAAS,MAAM,KAAK,cAAc,KAAK;MACrC;MACA,QAAQ,KAAK;MACb,QAAQ,KAAK;MACb,UAAU,KAAK;MACf,OAAO,MAAM;MACd,CAAC;;IAEL,CAAC;AAEF,OAAI,OAAO,SAAS;AAClB,QAAI,KAAK;AAET,YAAQ,OAAO,MACb,uCAAuC,EAAE,IAAI,QAAQ,UAAU,CAAC,kBACjE;AAED,SAAK,MAAM,OAAO,OAAO,QAAQ,UAAU;KACzC,MAAM,QACJ,IAAI,MAAM,SAAS,IAAI,SAAS,SAAS,IAAI,QAAQ;AACvD,SAAI,UAAU,EAAG;AAEjB,aAAQ,OAAO,MACb,KAAK,EAAE,IAAI,QAAQ,IAAI,KAAK,CAAC,IAAI,MAAM,GAAG,UAAU,IAAI,iBAAiB,eAAe,IACzF;AACD,UAAK,MAAM,QAAQ,IAAI,MACrB,SAAQ,OAAO,MAAM,KAAK,EAAE,IAAI,SAAS,IAAI,CAAC,GAAG,KAAK,IAAI;AAE5D,UAAK,MAAM,QAAQ,IAAI,SACrB,SAAQ,OAAO,MAAM,KAAK,EAAE,IAAI,UAAU,IAAI,CAAC,GAAG,KAAK,IAAI;AAE7D,UAAK,MAAM,QAAQ,IAAI,QACrB,SAAQ,OAAO,MAAM,KAAK,EAAE,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,IAAI;;AAI5D,YAAQ,OAAO,MAAM,KAAK;AAC1B;;AAGF,OAAI,OAAO,OAAO,SAAS,EAEzB,OAAM,IAAI,GADK,MAAM,KAAK,GAAG,kBAAkB,KAAK,CAChC,WAAW,EAAE,MAAM,CAAC;AAG1C,OAAI,KAAK;AAET,OAAI,OAAO,OAAO,SAAS,EACzB,MAAK,MAAM,SAAS,OAAO,OACzB,SAAQ,OAAO,MAAM,GAAG,EAAE,IAAI,OAAO,UAAU,CAAC,GAAG,MAAM,IAAI;AAIjE,OAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,YAAQ,OAAO,MACb,YAAY,EAAE,IAAI,QAAQ,OAAO,OAAO,OAAO,OAAO,CAAC,CAAC,GAAG,OAAO,OAAO,WAAW,IAAI,YAAY,WAAW,QAAQ,EAAE,IAAI,QAAQ,KAAK,OAAO,CAAC,IACnJ;AACD,SAAK,MAAM,OAAO,OAAO,OACvB,SAAQ,OAAO,MAAM,KAAK,EAAE,IAAI,SAAS,IAAS,CAAC,GAAG,IAAI,IAAI;;AAIlE,WAAQ,OAAO,MAAM,KAAK;;EAE7B,CAAC;CAMF,OAA0B,SAAS;EACjC,MAAM;EACN,aAAa;EACb,SAAS,OAAO,EAAE,MAAM,UAAU;GAChC,MAAM,OAAO,KAAK,gBAAgB;GAElC,IAAI,SAA2B;IAAE,UAAU,EAAE;IAAE,cAAc;IAAG;AAEhE,SAAM,IAAI;IACR,MAAM,WAAW,KAAK,OAAO,MAAM,KAAK;IACxC,SAAS,YAAY;AACnB,cAAS,MAAM,KAAK,cAAc,KAAK;MACrC;MACA,QAAQ,KAAK;MACb,QAAQ,KAAK;MACb,UAAU,KAAK;MAChB,CAAC;;IAEL,CAAC;AAEF,OAAI,KAAK;AAET,OAAI,OAAO,iBAAiB,GAAG;AAC7B,YAAQ,OAAO,MAAM,mBAAmB;AACxC;;GAGF,MAAM,IAAI,KAAK;AAEf,QAAK,MAAM,OAAO,OAAO,UAAU;IACjC,MAAM,QACJ,IAAI,MAAM,SAAS,IAAI,SAAS,SAAS,IAAI,QAAQ;AACvD,QAAI,UAAU,GAAG;AACf,aAAQ,OAAO,MAAM,KAAK,EAAE,IAAI,QAAQ,IAAI,KAAK,CAAC,gBAAgB;AAClE;;AAGF,YAAQ,OAAO,MACb,KAAK,EAAE,IAAI,QAAQ,IAAI,KAAK,CAAC,IAAI,MAAM,GAAG,UAAU,IAAI,iBAAiB,eAAe,IACzF;AAED,SAAK,MAAM,QAAQ,IAAI,MACrB,SAAQ,OAAO,MAAM,KAAK,EAAE,IAAI,SAAS,IAAI,CAAC,GAAG,KAAK,IAAI;AAE5D,SAAK,MAAM,QAAQ,IAAI,SACrB,SAAQ,OAAO,MAAM,KAAK,EAAE,IAAI,UAAU,IAAI,CAAC,GAAG,KAAK,IAAI;AAE7D,SAAK,MAAM,QAAQ,IAAI,QACrB,SAAQ,OAAO,MAAM,KAAK,EAAE,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,IAAI;;AAI5D,WAAQ,OAAO,MAAM,KAAK;;EAE7B,CAAC;CAMF,SAAyB,SAAS;EAChC,MAAM;EACN,aAAa;EACb,UAAU,CAAC,KAAK,MAAM,KAAK,KAAK;EAChC,SAAS,OAAO,EAAE,WAAW;AAC3B,SAAM;;EAET,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjKJ,MAAa,wBAAwB,QAAQ;CAC3C,MAAM;CACN,OAAO,CAAC,cAAc;CACtB,UAAU,CAAC,eAAe,cAAc;CACzC,CAAC;AAIF,iBAAiB,MAAM,QAAQ,WAAW;AACxC,KAAI,OAAO,OACT,QAAO,IAAI,eAAe,OAAO,OAAO;EAE1C"}
|
|
@@ -742,13 +742,32 @@ var TypeProvider = class TypeProvider {
|
|
|
742
742
|
nullify = (schema, options) => Type.Mapped(Type.Identifier("K"), Type.KeyOf(schema), Type.Ref("K"), Type.Union([Type.Index(schema, Type.Ref("K")), Type.Null()]), options);
|
|
743
743
|
/**
|
|
744
744
|
* Create a schema for a string enum.
|
|
745
|
+
*
|
|
746
|
+
* By default, this creates a real PostgreSQL ENUM type in the database.
|
|
747
|
+
* Use `{ mode: "text" }` to store as a TEXT column instead.
|
|
748
|
+
*
|
|
749
|
+
* @example
|
|
750
|
+
* ```ts
|
|
751
|
+
* // PostgreSQL ENUM type (default)
|
|
752
|
+
* status: t.enum(["pending", "active", "archived"])
|
|
753
|
+
*
|
|
754
|
+
* // TEXT column
|
|
755
|
+
* status: t.enum(["pending", "active", "archived"], { mode: "text" })
|
|
756
|
+
*
|
|
757
|
+
* // Shared enum name across tables
|
|
758
|
+
* status: t.enum(["enabled", "disabled"], { name: "shared_status_enum" })
|
|
759
|
+
* ```
|
|
745
760
|
*/
|
|
746
761
|
enum(values, options) {
|
|
747
|
-
|
|
762
|
+
const { mode, name, ...textOptions } = options ?? {};
|
|
763
|
+
const schema = Type.Unsafe(t.text({
|
|
748
764
|
enum: values,
|
|
749
765
|
pattern: values.map((v) => `^${v}$`).join("|"),
|
|
750
|
-
...
|
|
766
|
+
...textOptions
|
|
751
767
|
}));
|
|
768
|
+
if (mode === "text") Object.assign(schema, { mode: "text" });
|
|
769
|
+
else Object.assign(schema, { enumName: name });
|
|
770
|
+
return schema;
|
|
752
771
|
}
|
|
753
772
|
/**
|
|
754
773
|
* Create a schema for a bigint represented as a string.
|