akanjs 2.0.0-beta.0 → 2.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/cli/application/application.command.ts +11 -3
  2. package/cli/guidelines/databaseModule/databaseModule.instruction.md +1 -1
  3. package/cli/guidelines/modelConstant/modelConstant.instruction.md +5 -5
  4. package/cli/guidelines/modelDocument/modelDocument.instruction.md +34 -61
  5. package/cli/guidelines/modelService/modelService.instruction.md +1 -1
  6. package/cli/index.js +160 -63
  7. package/cli/package/package.runner.ts +24 -7
  8. package/cli/package/package.script.ts +2 -2
  9. package/cli/templates/app/page/_index.tsx +200 -76
  10. package/cli/templates/app/page/_layout.tsx +0 -1
  11. package/cli/templates/module/__Model__.Zone.tsx +1 -1
  12. package/cli/templates/module/__model__.document.ts +1 -1
  13. package/cli/templates/workspaceRoot/.gitignore.template +1 -11
  14. package/cli/templates/workspaceRoot/biome.json.template +16 -0
  15. package/cli/workspace/workspace.command.ts +2 -7
  16. package/cli/workspace/workspace.runner.ts +1 -7
  17. package/cli/workspace/workspace.script.ts +14 -8
  18. package/client/csrTypes.ts +1 -1
  19. package/constant/fieldInfo.ts +1 -1
  20. package/devkit/capacitor.base.config.ts +1 -1
  21. package/devkit/capacitorApp.ts +5 -1
  22. package/devkit/commandDecorators/argMeta.ts +28 -14
  23. package/devkit/commandDecorators/command.ts +41 -15
  24. package/devkit/commandDecorators/commandBuilder.ts +78 -42
  25. package/devkit/commandDecorators/helpFormatter.ts +7 -4
  26. package/devkit/executors.ts +2 -3
  27. package/devkit/frontendBuild/cssCompiler.ts +9 -3
  28. package/devkit/incrementalBuilder/incrementalBuilder.proc.ts +2 -1
  29. package/devkit/lint/no-deep-internal-import.grit +25 -0
  30. package/devkit/mobile/mobileTarget.ts +48 -8
  31. package/devkit/src/capacitorApp.ts +277 -0
  32. package/devkit/transforms/barrelImportsPlugin.ts +6 -0
  33. package/package.json +3 -1
  34. package/server/hmr/clientScript.ts +8 -5
  35. package/server/resolver/resolver.contract.fixture.ts +1 -1
  36. package/ui/Field.tsx +0 -1
  37. package/ui/Portal.tsx +2 -0
  38. package/ui/System/CSR.tsx +6 -5
  39. package/ui/System/SSR.tsx +1 -1
  40. package/ui/System/SelectLanguage.tsx +1 -1
  41. package/webkit/bootCsr.tsx +8 -5
  42. package/cli/templates/app/common/commonLogic.ts +0 -12
  43. package/cli/templates/app/common/index.ts +0 -10
  44. package/cli/templates/app/srvkit/backendLogic.ts +0 -12
  45. package/cli/templates/app/srvkit/index.ts +0 -10
  46. package/cli/templates/app/ui/UiComponent.ts +0 -16
  47. package/cli/templates/app/ui/index.ts +0 -10
  48. package/cli/templates/app/webkit/frontendLogic.ts +0 -12
  49. package/cli/templates/app/webkit/index.ts +0 -10
  50. package/cli/templates/module/index.tsx +0 -44
  51. /package/cli/templates/app/public/{favicon.ico → favicon.ico.template} +0 -0
  52. /package/cli/templates/app/public/{logo.png → logo.png.template} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { select } from "@inquirer/prompts";
2
- import { App, command, Exec, Sys, Workspace } from "akanjs/devkit";
2
+ import { App, command, Exec, getMobileTargetChoices, Sys, Workspace } from "akanjs/devkit";
3
3
 
4
4
  import { ApplicationScript } from "./application.script";
5
5
 
@@ -53,7 +53,11 @@ export class ApplicationCommand extends command("application", [ApplicationScrip
53
53
  }),
54
54
  buildIos: target({ short: true, desc: "Build iOS app with Capacitor" })
55
55
  .with(App)
56
- .option("target", String, { desc: "mobile target name or all" })
56
+ .option("target", String, {
57
+ desc: "mobile target name or all",
58
+ ask: "Select mobile target",
59
+ enum: async ({ app }) => await getMobileTargetChoices(app),
60
+ })
57
61
  .option("env", String, {
58
62
  enum: ["local", "debug", "develop", "main"],
59
63
  desc: "backend environment",
@@ -66,7 +70,11 @@ export class ApplicationCommand extends command("application", [ApplicationScrip
66
70
  }),
67
71
  buildAndroid: target({ short: true, desc: "Build Android app with Capacitor" })
68
72
  .with(App)
69
- .option("target", String, { desc: "mobile target name or all" })
73
+ .option("target", String, {
74
+ desc: "mobile target name or all",
75
+ ask: "Select mobile target",
76
+ enum: async ({ app }) => await getMobileTargetChoices(app),
77
+ })
70
78
  .option("env", String, {
71
79
  enum: ["local", "debug", "develop", "main"],
72
80
  desc: "backend environment",
@@ -94,7 +94,7 @@ Create the MongoDB schema with document methods and middleware:
94
94
 
95
95
  ```typescript
96
96
  import { dayjs } from "akanjs/base";
97
- import { beyond, by, Database, into, Loader, type SchemaOf } from "akanjs/document";
97
+ import { by, Database, into, Loader, type SchemaOf } from "akanjs/document";
98
98
  import { hashPassword } from "@libs/shared/server";
99
99
 
100
100
  import * as cnst from "../cnst";
@@ -80,7 +80,7 @@ export class Drone extends Full(DroneObject, LightDrone) {
80
80
  // 7. Insight Model
81
81
 
82
82
  export class DroneInsight {
83
- @Field.Prop(() => Int, { default: 0, accumulate: { $sum: 1 } })
83
+ @Field.Prop(() => Int, { default: 0, accumulate: {} })
84
84
  count: number;
85
85
  }
86
86
 
@@ -223,7 +223,7 @@ Insight model defines statistical fields:
223
223
 
224
224
  ```typescript
225
225
  export class DroneInsight {
226
- @Field.Prop(() => Int, { default: 0, accumulate: { $sum: 1 } })
226
+ @Field.Prop(() => Int, { default: 0, accumulate: {} })
227
227
  count: number;
228
228
  }
229
229
  ```
@@ -314,8 +314,8 @@ const drones = await this.listByName("myDrone", { sort: "alphabetical" });
314
314
  | `enum` | `any[]` | - | Enum values restriction | `@Field.Prop(()=> String, { enum: ["active","inactive"] }) status;` |
315
315
  | `minlength` | `number` | - | Minimum string length | `@Field.Prop(()=> String, { minlength: 2 }) name: string;` |
316
316
  | `maxlength` | `number` | - | Maximum string length | `@Field.Prop(()=> String, { maxlength: 30 }) title: string;` |
317
- | `query` | `object` | - | Query value for Summary fields | `@Field.Prop(() => Int, { query: { status: { $ne: 'inactive' } })` |
318
- | `accumulate` | `object` | - | Aggregation value for Insight fields | `@Field.Prop(() => Int, { accumulate: { $sum: 1 } }) count: number;` |
317
+ | `query` | `object` | - | Query value for Summary fields | `@Field.Prop(() => Int, { query: { status: { ne: "inactive" } } })` |
318
+ | `accumulate` | `object` | - | Document query filter for Insight count fields | `@Field.Prop(() => Int, { accumulate: { status: "active" } }) activeCount: number;` |
319
319
  | `example` | `any` | - | Example value for API docs | `@Field.Prop(()=> String, { example: "contact@akanjs.com" }) email;` |
320
320
  | `of` | `any` | - | Value type for Map fields | `@Field.Prop(()=> Map, { of: Date }) readAts: Map<string, Dayjs>;` |
321
321
  | `validate` | `(value) => boolean` | - | Custom validation function | `@Field.Prop(()=> String, { validate: (v)=> v.includes("@") }) email;` |
@@ -477,7 +477,7 @@ export class Drone extends Full(DroneObject, LightDrone) {
477
477
  // Insight Model
478
478
 
479
479
  export class DroneInsight {
480
- @Field.Prop(() => Int, { accumulate: { $sum: 1 } })
480
+ @Field.Prop(() => Int, { accumulate: {} })
481
481
  count: number;
482
482
  }
483
483
 
@@ -118,26 +118,14 @@ export class OrderModel extends into(Order, cnst.orderCnst) {
118
118
  .save();
119
119
  }
120
120
 
121
- // Aggregation example
121
+ // Insight-style count example
122
122
  async getOrderStatsByUser(userId: string) {
123
- const result = await this.Order.aggregate([
124
- { $match: { user: userId } },
125
- {
126
- $group: {
127
- _id: "$status",
128
- count: { $sum: 1 },
129
- totalAmount: { $sum: "$totalAmount" },
130
- },
131
- },
132
- ]);
133
-
134
- return result.reduce((acc, item) => {
135
- acc[item._id] = {
136
- count: item.count,
137
- totalAmount: item.totalAmount,
138
- };
139
- return acc;
140
- }, {});
123
+ const baseQuery = { user: userId };
124
+
125
+ return {
126
+ active: await this.count({ ...baseQuery, status: "active" }),
127
+ refunded: await this.count({ ...baseQuery, status: "refunded" }),
128
+ };
141
129
  }
142
130
  }
143
131
  ```
@@ -191,37 +179,30 @@ Indexes are crucial for query performance. Define them in the Middleware's `onSc
191
179
  - **Unique index** - Ensure field values are unique across the collection
192
180
  - **Sparse index** - Only include documents that have the indexed field
193
181
 
194
- ## How to Use MongoDB Model
182
+ ## How to Query Documents
195
183
 
196
- The Akan.js framework provides direct access to the Mongoose model, allowing you to perform standard MongoDB operations:
184
+ The Akan.js framework uses document query objects for common filtering and counting:
197
185
 
198
186
  ```typescript
199
187
  // Find operations
200
- const product = await productModel.Product.findById(id);
201
- const activeProducts = await productModel.Product.find({ status: "active" });
188
+ const product = await productModel.pickById(id);
189
+ const activeProducts = await productModel.list({ status: "active" });
202
190
 
203
191
  // Update operations
204
- await productModel.Product.updateMany({ category: "electronics" }, { $set: { onSale: true } });
192
+ await productModel.updateManyByQuery({ category: "electronics" }, { set: { onSale: true } });
205
193
 
206
- // Aggregation
207
- const stats = await productModel.Product.aggregate([
208
- { $match: { status: "active" } },
209
- {
210
- $group: {
211
- _id: "$category",
212
- count: { $sum: 1 },
213
- avgPrice: { $avg: "$price" },
214
- },
215
- },
216
- ]);
194
+ // Insight counts
195
+ const activeCount = await productModel.count({ status: "active" });
196
+ const categoryCount = await productModel.count({ category: "electronics" });
217
197
 
218
198
  // Advanced querying
219
- const products = await productModel.Product.find({
220
- price: { $gte: 100, $lte: 500 },
221
- category: { $in: ["electronics", "gadgets"] },
222
- })
223
- .sort({ rating: -1 })
224
- .limit(10);
199
+ const products = await productModel.list(
200
+ {
201
+ price: { gte: 100, lte: 500 },
202
+ category: { oneOf: ["electronics", "gadgets"] },
203
+ },
204
+ { sort: { rating: -1 }, limit: 10 },
205
+ );
225
206
  ```
226
207
 
227
208
  ## How to Use DataLoader
@@ -422,16 +403,17 @@ export class ProductModel extends into(Product, cnst.productCnst) {
422
403
  tagProductsLoader: Loader<string, Product[]>;
423
404
 
424
405
  async findPopularProducts(limit = 10) {
425
- return this.Product.find({
406
+ return this.list(
407
+ {
426
408
  status: "active",
427
- popularity: { $gte: 4 },
428
- })
429
- .sort({ popularity: -1 })
430
- .limit(limit);
409
+ popularity: { gte: 4 },
410
+ },
411
+ { sort: { popularity: -1 }, limit },
412
+ );
431
413
  }
432
414
 
433
415
  async updatePrices(categoryId: string, increasePercentage: number) {
434
- const products = await this.Product.find({ category: categoryId });
416
+ const products = await this.list({ category: categoryId });
435
417
 
436
418
  const updates = products.map((product) => {
437
419
  const newPrice = product.price * (1 + increasePercentage / 100);
@@ -441,20 +423,11 @@ export class ProductModel extends into(Product, cnst.productCnst) {
441
423
  return Promise.all(updates);
442
424
  }
443
425
 
444
- async getCategoryStats() {
445
- const result = await this.Product.aggregate([
446
- { $match: { status: "active" } },
447
- {
448
- $group: {
449
- _id: "$category",
450
- count: { $sum: 1 },
451
- avgPrice: { $avg: "$price" },
452
- minPrice: { $min: "$price" },
453
- maxPrice: { $max: "$price" },
454
- },
455
- },
456
- { $sort: { count: -1 } },
457
- ]);
426
+ async getCategoryStats(categoryId: string) {
427
+ const result = {
428
+ activeCount: await this.count({ status: "active", category: categoryId }),
429
+ popularCount: await this.count({ status: "active", category: categoryId, popularity: { gte: 4 } }),
430
+ };
458
431
 
459
432
  // Cache the results
460
433
  await this.ProductCache.set("stats", "categories", JSON.stringify(result), { expireAt: dayjs().add(1, "hour") });
@@ -644,7 +644,7 @@ export class OrderService extends DbService(db.orderDb) {
644
644
  // Return stock to inventory
645
645
  for (const item of order.items) {
646
646
  await this.productService.updateProduct(item.product, {
647
- $inc: { stock: item.quantity },
647
+ inc: { stock: item.quantity },
648
648
  });
649
649
  }
650
650