@akanjs/cli 0.0.55 → 0.0.57
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/index.js
CHANGED
|
@@ -326,21 +326,6 @@ var import_dayjs3 = __toESM(require("dayjs"));
|
|
|
326
326
|
var import_customParseFormat = __toESM(require("dayjs/plugin/customParseFormat"));
|
|
327
327
|
import_dayjs3.default.extend(import_customParseFormat.default);
|
|
328
328
|
|
|
329
|
-
// pkgs/@akanjs/common/randomPicks.ts
|
|
330
|
-
var randomPicks = (arr, count = 1, allowDuplicate = false) => {
|
|
331
|
-
if (!allowDuplicate && arr.length <= count)
|
|
332
|
-
return arr;
|
|
333
|
-
const idxs = [];
|
|
334
|
-
let pickIdx;
|
|
335
|
-
for (let i = 0; i < count; i++) {
|
|
336
|
-
do {
|
|
337
|
-
pickIdx = Math.floor(Math.random() * arr.length);
|
|
338
|
-
} while (!allowDuplicate && idxs.includes(pickIdx));
|
|
339
|
-
idxs.push(pickIdx);
|
|
340
|
-
}
|
|
341
|
-
return idxs.map((idx) => arr[idx]);
|
|
342
|
-
};
|
|
343
|
-
|
|
344
329
|
// pkgs/@akanjs/common/pluralize.ts
|
|
345
330
|
var import_pluralize = __toESM(require("pluralize"));
|
|
346
331
|
|
|
@@ -2490,540 +2475,6 @@ dictionaryStart
|
|
|
2490
2475
|
|
|
2491
2476
|
dictionaryEnd
|
|
2492
2477
|
|
|
2493
|
-
`;
|
|
2494
|
-
var frameworkAbstract = `
|
|
2495
|
-
Intro
|
|
2496
|
-
- Build an all-stack application at once.
|
|
2497
|
-
- Write one line, deploy on web, app, server, database, and infra.
|
|
2498
|
-
- Akan is a framework with least code, highest performance for typescript-written applications.
|
|
2499
|
-
|
|
2500
|
-
Key features
|
|
2501
|
-
- Integral interface: Akan serves an interface for building from schema, to service logic, api endpoint, state management, and component design.
|
|
2502
|
-
- Stable, Scalable, Safe built-in architecture: Fully type-safe, i18n, security, file management, text-search, automatic documentation, admin page, etc are all served with modular development.
|
|
2503
|
-
- application as a service: Akan deploys server, database, web, app at once through Akan cloud. Commit once, deploy and manage all.
|
|
2504
|
-
|
|
2505
|
-
Procedure
|
|
2506
|
-
- add field on database and api at once, with fully typed
|
|
2507
|
-
- add backend api endpoint and frontend fetch function at once, with fully typed
|
|
2508
|
-
- write query interface and use everywhere!
|
|
2509
|
-
- No spaghetti state management anymore, build your global store with domain-driven state&actions.
|
|
2510
|
-
- No Spaghetti Components anymore, build your page with domain-driven components
|
|
2511
|
-
- write one page, use SSR on Next.js and build Android&iOS CSR app with beautiful page transitions!
|
|
2512
|
-
- built-in ai code generation, tell about business, the logic is generated.
|
|
2513
|
-
`;
|
|
2514
|
-
var scalarConstantDescription = `
|
|
2515
|
-
Purpose and Structure
|
|
2516
|
-
|
|
2517
|
-
Scalar constant files define reusable data structures that can be embedded within other models. They represent complex field types
|
|
2518
|
-
that are not entities themselves but are used as components within larger data models. These are located in the __scalar directory
|
|
2519
|
-
within application or library modules.
|
|
2520
|
-
|
|
2521
|
-
Key Characteristics
|
|
2522
|
-
|
|
2523
|
-
- Defined with @Model.Scalar decorator (not @Model.Input, @Model.Object, etc.)
|
|
2524
|
-
- Do not have their own database collection
|
|
2525
|
-
- Cannot be queried independently
|
|
2526
|
-
- Used as embedded objects within other models
|
|
2527
|
-
- Often represent complex value objects or domain concepts
|
|
2528
|
-
|
|
2529
|
-
Creating Scalar Constant Files
|
|
2530
|
-
|
|
2531
|
-
File Organization
|
|
2532
|
-
|
|
2533
|
-
1. Place scalar constants in the lib/__scalar/{scalarName}/ directory
|
|
2534
|
-
2. Name the file {scalarName}.constant.ts
|
|
2535
|
-
3. Register scalars in the _server.ts file in the __scalar directory
|
|
2536
|
-
|
|
2537
|
-
Basic Structure
|
|
2538
|
-
|
|
2539
|
-
import { Field, Model } from "@akanjs/constant";
|
|
2540
|
-
import { enumOf, Int, Dayjs } from "@akanjs/base"; // Import needed types
|
|
2541
|
-
|
|
2542
|
-
// Optional: Define enums used by this scalar
|
|
2543
|
-
export const ScalarEnum = enumOf(["value1", "value2", "value3"] as const);
|
|
2544
|
-
export type ScalarEnum = enumOf<typeof ScalarEnum>;
|
|
2545
|
-
|
|
2546
|
-
@Model.Scalar("ScalarName") // Use the @Model.Scalar decorator
|
|
2547
|
-
export class ScalarName {
|
|
2548
|
-
// Define properties with @Field.Prop decorator
|
|
2549
|
-
@Field.Prop(() => String)
|
|
2550
|
-
stringProperty: string;
|
|
2551
|
-
|
|
2552
|
-
@Field.Prop(() => Int, { min: 0 })
|
|
2553
|
-
numericProperty: number;
|
|
2554
|
-
|
|
2555
|
-
@Field.Prop(() => Boolean, { default: false })
|
|
2556
|
-
booleanProperty: boolean;
|
|
2557
|
-
|
|
2558
|
-
@Field.Prop(() => Date)
|
|
2559
|
-
dateProperty: Dayjs;
|
|
2560
|
-
|
|
2561
|
-
@Field.Prop(() => String, { enum: ScalarEnum })
|
|
2562
|
-
enumProperty: ScalarEnum;
|
|
2563
|
-
|
|
2564
|
-
@Field.Prop(() => String, { nullable: true })
|
|
2565
|
-
optionalProperty: string | null;
|
|
2566
|
-
}
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
Common Types of Scalar Objects
|
|
2570
|
-
|
|
2571
|
-
Based on the analyzed codebase, here are common patterns for scalar objects:
|
|
2572
|
-
|
|
2573
|
-
1. Value Objects
|
|
2574
|
-
|
|
2575
|
-
Simple structures that group related properties:
|
|
2576
|
-
|
|
2577
|
-
@Model.Scalar("Address")
|
|
2578
|
-
export class Address {
|
|
2579
|
-
@Field.Prop(() => String)
|
|
2580
|
-
street: string;
|
|
2581
|
-
|
|
2582
|
-
@Field.Prop(() => String)
|
|
2583
|
-
city: string;
|
|
2584
|
-
|
|
2585
|
-
@Field.Prop(() => String)
|
|
2586
|
-
zipCode: string;
|
|
2587
|
-
|
|
2588
|
-
@Field.Prop(() => String)
|
|
2589
|
-
country: string;
|
|
2590
|
-
}
|
|
2591
|
-
|
|
2592
|
-
2. Configuration Objects
|
|
2593
|
-
|
|
2594
|
-
Objects holding configuration or settings:
|
|
2595
|
-
|
|
2596
|
-
@Model.Scalar("NotificationSettings")
|
|
2597
|
-
export class NotificationSettings {
|
|
2598
|
-
@Field.Prop(() => Boolean, { default: true })
|
|
2599
|
-
emailEnabled: boolean;
|
|
2600
|
-
|
|
2601
|
-
@Field.Prop(() => Boolean, { default: true })
|
|
2602
|
-
pushEnabled: boolean;
|
|
2603
|
-
|
|
2604
|
-
@Field.Prop(() => Boolean, { default: false })
|
|
2605
|
-
smsEnabled: boolean;
|
|
2606
|
-
}
|
|
2607
|
-
|
|
2608
|
-
3. Metadata Objects
|
|
2609
|
-
|
|
2610
|
-
Objects providing metadata about other entities:
|
|
2611
|
-
|
|
2612
|
-
@Model.Scalar("FileMeta")
|
|
2613
|
-
export class FileMeta {
|
|
2614
|
-
@Field.Prop(() => Date)
|
|
2615
|
-
lastModifiedAt: Dayjs;
|
|
2616
|
-
|
|
2617
|
-
@Field.Prop(() => Int)
|
|
2618
|
-
size: number;
|
|
2619
|
-
|
|
2620
|
-
@Field.Prop(() => String, { nullable: true })
|
|
2621
|
-
mimeType: string | null;
|
|
2622
|
-
}
|
|
2623
|
-
|
|
2624
|
-
4. Complex Value Type Objects
|
|
2625
|
-
|
|
2626
|
-
Objects representing domain-specific complex values:
|
|
2627
|
-
|
|
2628
|
-
@Model.Scalar("GeoLocation")
|
|
2629
|
-
export class GeoLocation {
|
|
2630
|
-
@Field.Prop(() => Float)
|
|
2631
|
-
latitude: number;
|
|
2632
|
-
|
|
2633
|
-
@Field.Prop(() => Float)
|
|
2634
|
-
longitude: number;
|
|
2635
|
-
|
|
2636
|
-
@Field.Prop(() => Float, { nullable: true })
|
|
2637
|
-
altitude: number | null;
|
|
2638
|
-
}
|
|
2639
|
-
|
|
2640
|
-
Best Practices
|
|
2641
|
-
|
|
2642
|
-
1. Keep it Simple: Scalar objects should be focused on a single concept
|
|
2643
|
-
2. No External References: Avoid referencing entities directly from scalar objects
|
|
2644
|
-
3. Validation Rules: Include validation rules in field definitions
|
|
2645
|
-
4. Default Values: Provide sensible defaults where appropriate
|
|
2646
|
-
5. Documentation: Document the purpose and usage of each scalar type
|
|
2647
|
-
6. Reusability: Design scalar objects to be reusable across different models
|
|
2648
|
-
7. Immutability: Treat scalar objects as immutable value objects
|
|
2649
|
-
8. Naming Convention: Use descriptive names that reflect the domain concept
|
|
2650
|
-
|
|
2651
|
-
Using Scalar Types in Models
|
|
2652
|
-
|
|
2653
|
-
After defining scalar objects, you can use them in your entity models:
|
|
2654
|
-
|
|
2655
|
-
import { Field, Model } from "@akanjs/constant";
|
|
2656
|
-
import { FileMeta } from "../__scalar/fileMeta/fileMeta.constant";
|
|
2657
|
-
import { ExternalLink } from "../__scalar/externalLink/externalLink.constant";
|
|
2658
|
-
|
|
2659
|
-
@Model.Input("ProfileInput")
|
|
2660
|
-
export class ProfileInput {
|
|
2661
|
-
@Field.Prop(() => String)
|
|
2662
|
-
name: string;
|
|
2663
|
-
|
|
2664
|
-
@Field.Prop(() => FileMeta, { nullable: true })
|
|
2665
|
-
avatar: FileMeta | null;
|
|
2666
|
-
|
|
2667
|
-
@Field.Prop(() => [ExternalLink])
|
|
2668
|
-
socialLinks: ExternalLink[];
|
|
2669
|
-
}
|
|
2670
|
-
|
|
2671
|
-
Key Differences from Regular Models
|
|
2672
|
-
|
|
2673
|
-
This structured approach to scalar objects helps maintain clean, modular, and reusable code across your application, while keeping
|
|
2674
|
-
the domain concepts well-organized and type-safe.
|
|
2675
|
-
`;
|
|
2676
|
-
var howToSetFieldInModelConstant = `
|
|
2677
|
-
Comprehensive Guide to @Field Decorators in constant.ts Files
|
|
2678
|
-
|
|
2679
|
-
The @Field decorator is a crucial component for defining schema fields in your constant.ts files. This guide provides detailed
|
|
2680
|
-
information about using @Field.Prop and @Field.Secret decorators with various types and option configurations.
|
|
2681
|
-
|
|
2682
|
-
Basic Structure
|
|
2683
|
-
|
|
2684
|
-
@Field.Prop(() => TypeFunction, optionsObject)
|
|
2685
|
-
fieldName: FieldType;
|
|
2686
|
-
|
|
2687
|
-
Field Decorator Types
|
|
2688
|
-
|
|
2689
|
-
1. @Field.Prop
|
|
2690
|
-
|
|
2691
|
-
The standard field decorator used for most properties in your models.
|
|
2692
|
-
|
|
2693
|
-
@Field.Prop(() => String)
|
|
2694
|
-
name: string;
|
|
2695
|
-
|
|
2696
|
-
2. @Field.Secret
|
|
2697
|
-
|
|
2698
|
-
Used for sensitive data that should be handled with extra security measures. These fields are typically excluded from normal queries
|
|
2699
|
-
and responses by default.
|
|
2700
|
-
|
|
2701
|
-
@Field.Secret(() => String)
|
|
2702
|
-
password: string;
|
|
2703
|
-
|
|
2704
|
-
Data Type Functions
|
|
2705
|
-
|
|
2706
|
-
The first argument to a field decorator is a type function that defines the data type:
|
|
2707
|
-
|
|
2708
|
-
Basic Types
|
|
2709
|
-
|
|
2710
|
-
@Field.Prop(() => String)
|
|
2711
|
-
name: string;
|
|
2712
|
-
|
|
2713
|
-
@Field.Prop(() => Int)
|
|
2714
|
-
age: number;
|
|
2715
|
-
|
|
2716
|
-
@Field.Prop(() => Float)
|
|
2717
|
-
weight: number;
|
|
2718
|
-
|
|
2719
|
-
@Field.Prop(() => Boolean)
|
|
2720
|
-
isActive: boolean;
|
|
2721
|
-
|
|
2722
|
-
@Field.Prop(() => Date)
|
|
2723
|
-
createdAt: Dayjs;
|
|
2724
|
-
|
|
2725
|
-
@Field.Prop(() => ID)
|
|
2726
|
-
userId: string;
|
|
2727
|
-
|
|
2728
|
-
@Field.Prop(() => JSON)
|
|
2729
|
-
metadata: any;
|
|
2730
|
-
|
|
2731
|
-
Array Types
|
|
2732
|
-
|
|
2733
|
-
@Field.Prop(() => [String])
|
|
2734
|
-
tags: string[];
|
|
2735
|
-
|
|
2736
|
-
@Field.Prop(() => [Int])
|
|
2737
|
-
scores: number[];
|
|
2738
|
-
|
|
2739
|
-
@Field.Prop(() => [UserModel])
|
|
2740
|
-
friends: UserModel[];
|
|
2741
|
-
|
|
2742
|
-
Reference Types
|
|
2743
|
-
|
|
2744
|
-
// Reference to scalar types
|
|
2745
|
-
@Field.Prop(() => FileMeta)
|
|
2746
|
-
fileMeta: FileMeta;
|
|
2747
|
-
|
|
2748
|
-
// Reference to entity models
|
|
2749
|
-
@Field.Prop(() => LightUser)
|
|
2750
|
-
user: LightUser;
|
|
2751
|
-
|
|
2752
|
-
Enum Types
|
|
2753
|
-
|
|
2754
|
-
@Field.Prop(() => String, { enum: UserStatus })
|
|
2755
|
-
status: UserStatus;
|
|
2756
|
-
|
|
2757
|
-
@Field.Prop(() => [String], { enum: UserRole })
|
|
2758
|
-
roles: UserRole[];
|
|
2759
|
-
|
|
2760
|
-
Field Options
|
|
2761
|
-
|
|
2762
|
-
The second argument to field decorators is an options object that can include many configuration settings:
|
|
2763
|
-
|
|
2764
|
-
Nullability
|
|
2765
|
-
|
|
2766
|
-
// Non-nullable field (default)
|
|
2767
|
-
@Field.Prop(() => String)
|
|
2768
|
-
requiredField: string;
|
|
2769
|
-
|
|
2770
|
-
// Nullable field
|
|
2771
|
-
@Field.Prop(() => String, { nullable: true })
|
|
2772
|
-
optionalField: string | null;
|
|
2773
|
-
|
|
2774
|
-
Default Values
|
|
2775
|
-
|
|
2776
|
-
// Static default value
|
|
2777
|
-
@Field.Prop(() => String, { default: "Untitled" })
|
|
2778
|
-
title: string;
|
|
2779
|
-
|
|
2780
|
-
// Dynamic default value (function)
|
|
2781
|
-
@Field.Prop(() => Date, { default: () => dayjs() })
|
|
2782
|
-
createdAt: Dayjs;
|
|
2783
|
-
|
|
2784
|
-
// Default for arrays
|
|
2785
|
-
@Field.Prop(() => [Int], { default: [0, 0] })
|
|
2786
|
-
coordinates: number[];
|
|
2787
|
-
|
|
2788
|
-
// Default for objects
|
|
2789
|
-
@Field.Prop(() => JSON, { default: {} })
|
|
2790
|
-
settings: Record<string, any>;
|
|
2791
|
-
|
|
2792
|
-
Validation Constraints
|
|
2793
|
-
|
|
2794
|
-
// String length
|
|
2795
|
-
@Field.Prop(() => String, { min: 3, max: 100 })
|
|
2796
|
-
name: string;
|
|
2797
|
-
|
|
2798
|
-
// Numeric range
|
|
2799
|
-
@Field.Prop(() => Int, { min: 0, max: 100 })
|
|
2800
|
-
score: number;
|
|
2801
|
-
|
|
2802
|
-
// Custom type validation
|
|
2803
|
-
@Field.Prop(() => String, { type: "email" })
|
|
2804
|
-
email: string;
|
|
2805
|
-
|
|
2806
|
-
@Field.Prop(() => String, { type: "url" })
|
|
2807
|
-
website: string;
|
|
2808
|
-
|
|
2809
|
-
@Field.Prop(() => String, { type: "phone" })
|
|
2810
|
-
phone: string;
|
|
2811
|
-
|
|
2812
|
-
// Multiple constraints
|
|
2813
|
-
@Field.Prop(() => String, {
|
|
2814
|
-
min: 8,
|
|
2815
|
-
max: 50,
|
|
2816
|
-
regex: /^[a-zA-Z0-9!@#$%^&*()]+$/
|
|
2817
|
-
})
|
|
2818
|
-
password: string;
|
|
2819
|
-
|
|
2820
|
-
Enumerations
|
|
2821
|
-
|
|
2822
|
-
// Single enum value
|
|
2823
|
-
@Field.Prop(() => String, { enum: UserRole, default: "user" })
|
|
2824
|
-
role: UserRole;
|
|
2825
|
-
|
|
2826
|
-
// Array of enum values
|
|
2827
|
-
@Field.Prop(() => [String], { enum: Permissions, default: ["read"] })
|
|
2828
|
-
permissions: Permissions[];
|
|
2829
|
-
|
|
2830
|
-
// Multiple enum constraints
|
|
2831
|
-
@Field.Prop(() => [String], [{ enum: Verify }])
|
|
2832
|
-
verifies: Verify[];
|
|
2833
|
-
|
|
2834
|
-
Database-Specific Options
|
|
2835
|
-
|
|
2836
|
-
// Unique constraint
|
|
2837
|
-
@Field.Prop(() => String, { unique: true })
|
|
2838
|
-
username: string;
|
|
2839
|
-
|
|
2840
|
-
// Index field
|
|
2841
|
-
@Field.Prop(() => String, { index: true })
|
|
2842
|
-
category: string;
|
|
2843
|
-
|
|
2844
|
-
// Case-insensitive index
|
|
2845
|
-
@Field.Prop(() => String, { index: { collation: { locale: "en", strength: 2 } } })
|
|
2846
|
-
searchTerm: string;
|
|
2847
|
-
|
|
2848
|
-
Accumulation for Insights
|
|
2849
|
-
|
|
2850
|
-
Used specifically in Insight models to define how to aggregate data:
|
|
2851
|
-
|
|
2852
|
-
@Field.Prop(() => Int, { default: 0, accumulate: { $sum: 1 } })
|
|
2853
|
-
count: number;
|
|
2854
|
-
|
|
2855
|
-
@Field.Prop(() => Int, { default: 0, accumulate: { $sum: "$amount" } })
|
|
2856
|
-
totalAmount: number;
|
|
2857
|
-
|
|
2858
|
-
@Field.Prop(() => Int, { accumulate: { $avg: "$score" } })
|
|
2859
|
-
averageScore: number;
|
|
2860
|
-
|
|
2861
|
-
@Field.Prop(() => Int, { accumulate: { $max: "$value" } })
|
|
2862
|
-
highestValue: number;
|
|
2863
|
-
|
|
2864
|
-
Query Options for Summary Models
|
|
2865
|
-
|
|
2866
|
-
Used specifically in Summary models to define query criteria for aggregate calculations:
|
|
2867
|
-
|
|
2868
|
-
// Basic query - count all records
|
|
2869
|
-
@Field.Prop(() => Int, { min: 0, default: 0, query: {} })
|
|
2870
|
-
totalRecords: number;
|
|
2871
|
-
|
|
2872
|
-
// Filtered query - count records with specific status
|
|
2873
|
-
@Field.Prop(() => Int, { min: 0, default: 0, query: { status: "active" } })
|
|
2874
|
-
activeRecords: number;
|
|
2875
|
-
|
|
2876
|
-
// Complex query - count records matching multiple criteria
|
|
2877
|
-
@Field.Prop(() => Int, { query: { status: "active", type: "premium" } })
|
|
2878
|
-
activePremiumUsers: number;
|
|
2879
|
-
|
|
2880
|
-
// Dynamic query using a function
|
|
2881
|
-
@Field.Prop(() => Int, {
|
|
2882
|
-
query: () => ({ lastLoginAt: { $gte: dayjs().subtract(1, "day").toDate() } })
|
|
2883
|
-
})
|
|
2884
|
-
dailyActiveUsers: number;
|
|
2885
|
-
|
|
2886
|
-
// Combined constraints
|
|
2887
|
-
@Field.Prop(() => Int, {
|
|
2888
|
-
min: 0,
|
|
2889
|
-
default: 0,
|
|
2890
|
-
query: { status: { $ne: "deleted" } }
|
|
2891
|
-
})
|
|
2892
|
-
nonDeletedRecords: number;
|
|
2893
|
-
|
|
2894
|
-
Reference Options
|
|
2895
|
-
|
|
2896
|
-
// Basic reference
|
|
2897
|
-
@Field.Prop(() => OtherModel)
|
|
2898
|
-
relatedItem: OtherModel;
|
|
2899
|
-
|
|
2900
|
-
// Reference with rendering option for UI
|
|
2901
|
-
@Filter.Arg("userId", () => ID, {
|
|
2902
|
-
ref: "user",
|
|
2903
|
-
renderOption: (user: LightUser) => user.nickname
|
|
2904
|
-
})
|
|
2905
|
-
userId: string;
|
|
2906
|
-
|
|
2907
|
-
Combined Examples
|
|
2908
|
-
|
|
2909
|
-
Complex Object Reference with Nullable
|
|
2910
|
-
|
|
2911
|
-
@Field.Prop(() => UserProfile, { nullable: true })
|
|
2912
|
-
profile: UserProfile | null;
|
|
2913
|
-
|
|
2914
|
-
Array of References with Default
|
|
2915
|
-
|
|
2916
|
-
@Field.Prop(() => [File], { default: [] })
|
|
2917
|
-
attachments: File[];
|
|
2918
|
-
|
|
2919
|
-
Enum with Default and Validation
|
|
2920
|
-
|
|
2921
|
-
@Field.Prop(() => String, {
|
|
2922
|
-
enum: StatusType,
|
|
2923
|
-
default: "pending",
|
|
2924
|
-
validate: (value) => ["pending", "active", "completed"].includes(value)
|
|
2925
|
-
})
|
|
2926
|
-
status: StatusType;
|
|
2927
|
-
|
|
2928
|
-
Dynamic Default with Constraints
|
|
2929
|
-
|
|
2930
|
-
@Field.Prop(() => Date, {
|
|
2931
|
-
default: () => dayjs().add(7, "days"),
|
|
2932
|
-
validate: (date) => date > dayjs().toDate()
|
|
2933
|
-
})
|
|
2934
|
-
expiresAt: Dayjs;
|
|
2935
|
-
|
|
2936
|
-
Special Use Cases
|
|
2937
|
-
|
|
2938
|
-
Computed Fields
|
|
2939
|
-
|
|
2940
|
-
@Field.Prop(() => Int, { compute: (doc) => doc.items.reduce((sum, item) => sum + item.price, 0) })
|
|
2941
|
-
totalPrice: number;
|
|
2942
|
-
|
|
2943
|
-
Virtual Fields (not stored in database)
|
|
2944
|
-
|
|
2945
|
-
@Field.Prop(() => String, { virtual: true })
|
|
2946
|
-
get fullName(): string {
|
|
2947
|
-
return \`\${this.firstName} \${this.lastName}\`;
|
|
2948
|
-
}
|
|
2949
|
-
|
|
2950
|
-
Combined Validators
|
|
2951
|
-
|
|
2952
|
-
@Field.Prop(() => String, {
|
|
2953
|
-
validators: [
|
|
2954
|
-
{ validator: (v) => v.length >= 8, message: "Password must be at least 8 characters" },
|
|
2955
|
-
{ validator: (v) => /[A-Z]/.test(v), message: "Password must contain uppercase letter" },
|
|
2956
|
-
{ validator: (v) => /[0-9]/.test(v), message: "Password must contain a number" }
|
|
2957
|
-
]
|
|
2958
|
-
})
|
|
2959
|
-
password: string;
|
|
2960
|
-
|
|
2961
|
-
Custom Field Types with Formatting
|
|
2962
|
-
|
|
2963
|
-
@Field.Prop(() => String, {
|
|
2964
|
-
type: "phone",
|
|
2965
|
-
format: (value) => value.replace(/(d{3})(d{4})(d{4})/, "$1-$2-$3")
|
|
2966
|
-
})
|
|
2967
|
-
phone: string;
|
|
2968
|
-
|
|
2969
|
-
Best Practices for Field Decorators
|
|
2970
|
-
|
|
2971
|
-
1. Be Explicit with Types: Always specify the correct type function that matches the TypeScript type.
|
|
2972
|
-
2. Set Appropriate Defaults: Provide sensible default values for fields that might be omitted during creation.
|
|
2973
|
-
3. Use Nullability Correctly: Only mark fields as nullable if they can legitimately be null in your domain model.
|
|
2974
|
-
4. Add Validation Constraints: Include appropriate min/max/regex constraints to ensure data integrity.
|
|
2975
|
-
5. Document Special Fields: Add comments for fields with special business logic or validation requirements.
|
|
2976
|
-
6. Group Related Fields: Keep related fields together for better readability.
|
|
2977
|
-
7. Use Enums Consistently: Always use enumOf for enumerated values and reference them correctly.
|
|
2978
|
-
8. Limit Secrets: Only use @Field.Secret for truly sensitive data.
|
|
2979
|
-
9. Consistent Naming: Use clear, descriptive names for fields that reflect their domain purpose.
|
|
2980
|
-
10. Type References: When referencing other models, import them correctly and use their proper type.
|
|
2981
|
-
|
|
2982
|
-
By following these guidelines and leveraging the full power of field decorators with their options, you can create robust, type-safe
|
|
2983
|
-
schemas that enforce your domain rules at the data layer.
|
|
2984
|
-
`;
|
|
2985
|
-
var requestScalarConstant = ({
|
|
2986
|
-
sysName,
|
|
2987
|
-
modelName,
|
|
2988
|
-
modelDesc,
|
|
2989
|
-
modelSchemaDesign,
|
|
2990
|
-
boilerplate,
|
|
2991
|
-
otherConstants
|
|
2992
|
-
}) => `
|
|
2993
|
-
\uB108\uB294 Akan.js\uB77C\uB294 \uC0AC\uB0B4 \uD504\uB808\uC784\uC6CC\uD06C\uB85C Typescript \uAE30\uBC18 \uD504\uB85C\uADF8\uB7A8\uC744 \uC791\uC131\uD558\uB294 \uC2DC\uB2C8\uC5B4 \uAC1C\uBC1C\uC790\uC57C.
|
|
2994
|
-
\uB2E4\uC74C\uC758 \uBC30\uACBD \uC815\uBCF4\uB97C \uBC14\uD0D5\uC73C\uB85C ${modelName}.constant.ts \uD30C\uC77C\uC744 \uC791\uC131\uD574\uC918.
|
|
2995
|
-
|
|
2996
|
-
1. Akan.js \uD504\uB808\uC784\uC6CC\uD06C\uC5D0 \uB300\uD55C \uAC1C\uC694
|
|
2997
|
-
${frameworkAbstract}
|
|
2998
|
-
|
|
2999
|
-
2. <model>.constant.ts \uD30C\uC77C\uC5D0 \uB300\uD55C \uAC1C\uC694
|
|
3000
|
-
${scalarConstantDescription}
|
|
3001
|
-
|
|
3002
|
-
3. <model.constant.ts \uD30C\uC77C\uC758 Field \uC791\uC131\uBC95
|
|
3003
|
-
${howToSetFieldInModelConstant}
|
|
3004
|
-
|
|
3005
|
-
4. \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8 \uB0B4 \uB2E4\uB978 constant.ts \uD30C\uC77C\uB4E4\uC5D0 \uB300\uD55C \uC608\uC2DC
|
|
3006
|
-
${otherConstants.map(
|
|
3007
|
-
(constant) => `
|
|
3008
|
-
Example file: ${constant.path}
|
|
3009
|
-
\`\`\`
|
|
3010
|
-
${constant.content}
|
|
3011
|
-
\`\`\`
|
|
3012
|
-
`
|
|
3013
|
-
).join("\n")}
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
\uC704 \uB0B4\uC6A9\uB4E4\uC744 \uBC14\uD0D5\uC73C\uB85C \uD30C\uC2F1\uD558\uAE30 \uC27D\uAC8C \uC544\uB798\uC5D0 \uBCF4\uC77C\uB7EC\uD50C\uB808\uC774\uD2B8\uC5D0 \uB9DE\uAC8C \uC815\uB9AC\uD574\uC11C \uC918
|
|
3017
|
-
|
|
3018
|
-
Application name: ${sysName}
|
|
3019
|
-
Model name: ${modelName}
|
|
3020
|
-
Model description: ${modelDesc}
|
|
3021
|
-
Model schema design: ${modelSchemaDesign}
|
|
3022
|
-
|
|
3023
|
-
Target filename: ${modelName}.constant.ts
|
|
3024
|
-
\`\`\`
|
|
3025
|
-
${boilerplate}
|
|
3026
|
-
\`\`\`
|
|
3027
2478
|
`;
|
|
3028
2479
|
|
|
3029
2480
|
// pkgs/@akanjs/cli/src/application/application.prompt.ts
|
|
@@ -3213,7 +2664,7 @@ var ApplicationRunner = class {
|
|
|
3213
2664
|
NEXT_PUBLIC_SERVE_DOMAIN: processEnv.NEXT_PUBLIC_SERVE_DOMAIN ?? "localhost",
|
|
3214
2665
|
NEXT_PUBLIC_ENV: processEnv.NEXT_PUBLIC_ENV ?? "debug",
|
|
3215
2666
|
NEXT_PUBLIC_OPERATION_MODE: processEnv.NEXT_PUBLIC_OPERATION_MODE ?? "local",
|
|
3216
|
-
NEXT_PUBLIC_LOG_LEVEL: processEnv.NEXT_PUBLIC_LOG_LEVEL ?? "
|
|
2667
|
+
NEXT_PUBLIC_LOG_LEVEL: processEnv.NEXT_PUBLIC_LOG_LEVEL ?? "log",
|
|
3217
2668
|
NEXT_PUBLIC_APP_NAME: app.name,
|
|
3218
2669
|
APP_OPERATION_MODE: processEnv.APP_OPERATION_MODE ?? "local",
|
|
3219
2670
|
AKAN_WORKSPACE_ROOT: app.workspace.workspaceRoot,
|
|
@@ -3869,12 +3320,14 @@ var PackageRunner = class {
|
|
|
3869
3320
|
main: "./index.js",
|
|
3870
3321
|
engines: { node: ">=22" },
|
|
3871
3322
|
dependencies,
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3323
|
+
...["@akanjs/config", "@akanjs/cli"].includes(pkg.name) ? {} : {
|
|
3324
|
+
exports: {
|
|
3325
|
+
".": {
|
|
3326
|
+
require: pkgJson.type === "module" ? "./index.cjs" : "./index.js",
|
|
3327
|
+
import: pkgJson.type === "module" ? "./index.js" : "./index.mjs"
|
|
3328
|
+
},
|
|
3329
|
+
...pkgJson.exports ?? {}
|
|
3330
|
+
}
|
|
3878
3331
|
}
|
|
3879
3332
|
};
|
|
3880
3333
|
if (buildResult.outputFiles)
|
|
@@ -4068,11 +3521,13 @@ CloudCommand = __decorateClass([
|
|
|
4068
3521
|
|
|
4069
3522
|
// pkgs/@akanjs/cli/src/library/library.command.ts
|
|
4070
3523
|
var LibraryCommand = class {
|
|
3524
|
+
libraryScript = new LibraryScript();
|
|
4071
3525
|
async createLibrary(name, workspace) {
|
|
4072
3526
|
}
|
|
4073
3527
|
async removeLibrary(lib, workspace) {
|
|
4074
3528
|
}
|
|
4075
3529
|
async scanLibrary(lib) {
|
|
3530
|
+
await this.libraryScript.scanLibrary(lib);
|
|
4076
3531
|
}
|
|
4077
3532
|
async buildLibrary(lib) {
|
|
4078
3533
|
}
|
|
@@ -4105,9 +3560,6 @@ LibraryCommand = __decorateClass([
|
|
|
4105
3560
|
Commands()
|
|
4106
3561
|
], LibraryCommand);
|
|
4107
3562
|
|
|
4108
|
-
// pkgs/@akanjs/cli/src/module/module.script.ts
|
|
4109
|
-
var import_prompts8 = require("@inquirer/prompts");
|
|
4110
|
-
|
|
4111
3563
|
// pkgs/@akanjs/cli/src/module/module.runner.ts
|
|
4112
3564
|
var import_output_parsers2 = require("@langchain/core/output_parsers");
|
|
4113
3565
|
var import_prompts7 = require("@langchain/core/prompts");
|
|
@@ -4283,19 +3735,6 @@ var ModuleScript = class {
|
|
|
4283
3735
|
)).flat()
|
|
4284
3736
|
];
|
|
4285
3737
|
const { constant, dictionary } = await this.#runner.createScalarTemplate(sys2, name);
|
|
4286
|
-
const scalarDescription = await (0, import_prompts8.input)({ message: "Enter the model scalar description" });
|
|
4287
|
-
const scalarSchemaDescription = await (0, import_prompts8.input)({ message: "What fields and schema design do you want?" });
|
|
4288
|
-
const scalarConstantRequest = requestScalarConstant({
|
|
4289
|
-
sysName: sys2.name,
|
|
4290
|
-
modelName: name,
|
|
4291
|
-
modelDesc: scalarDescription,
|
|
4292
|
-
modelSchemaDesign: scalarSchemaDescription,
|
|
4293
|
-
boilerplate: constant.content,
|
|
4294
|
-
otherConstants: randomPicks(scalarConstantExampleFiles, Math.min(10, scalarConstantExampleFiles.length))
|
|
4295
|
-
});
|
|
4296
|
-
const response = await streamAi(scalarConstantRequest, (chunk) => {
|
|
4297
|
-
process.stdout.write(chunk);
|
|
4298
|
-
});
|
|
4299
3738
|
}
|
|
4300
3739
|
async createService(workspace, name) {
|
|
4301
3740
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "commonjs",
|
|
3
3
|
"name": "@akanjs/cli",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.57",
|
|
5
5
|
"bin": {
|
|
6
6
|
"akan": "index.js"
|
|
7
7
|
},
|
|
@@ -48,11 +48,5 @@
|
|
|
48
48
|
"vite": "^6.3.4",
|
|
49
49
|
"vite-plugin-node-polyfills": "^0.23.0",
|
|
50
50
|
"vite-tsconfig-paths": "^5.1.4"
|
|
51
|
-
},
|
|
52
|
-
"exports": {
|
|
53
|
-
".": {
|
|
54
|
-
"require": "./index.js",
|
|
55
|
-
"import": "./index.mjs"
|
|
56
|
-
}
|
|
57
51
|
}
|
|
58
52
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Lib, Workspace } from "@akanjs/devkit";
|
|
2
|
+
import { LibraryScript } from "./library.script";
|
|
2
3
|
export declare class LibraryCommand {
|
|
4
|
+
libraryScript: LibraryScript;
|
|
3
5
|
createLibrary(name: string, workspace: Workspace): Promise<void>;
|
|
4
6
|
removeLibrary(lib: Lib, workspace: Workspace): Promise<void>;
|
|
5
7
|
scanLibrary(lib: Lib): Promise<void>;
|