@classytic/arc 1.0.0 → 1.0.8
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/README.md +65 -35
- package/bin/arc.js +118 -103
- package/dist/BaseController-nNRS3vpA.d.ts +233 -0
- package/dist/adapters/index.d.ts +2 -2
- package/dist/{arcCorePlugin-DTPWXcZN.d.ts → arcCorePlugin-CAjBQtZB.d.ts} +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/cli/commands/generate.d.ts +16 -0
- package/dist/cli/commands/generate.js +334 -0
- package/dist/cli/commands/init.d.ts +24 -0
- package/dist/cli/commands/init.js +2425 -0
- package/dist/cli/index.d.ts +4 -43
- package/dist/cli/index.js +3160 -411
- package/dist/core/index.d.ts +220 -0
- package/dist/core/index.js +2764 -0
- package/dist/{createApp-pzUAkzbz.d.ts → createApp-CjN9zZSL.d.ts} +1 -1
- package/dist/docs/index.js +19 -11
- package/dist/factory/index.d.ts +4 -4
- package/dist/factory/index.js +6 -23
- package/dist/hooks/index.d.ts +1 -1
- package/dist/{index-DkAW8BXh.d.ts → index-D5QTob1X.d.ts} +32 -12
- package/dist/index.d.ts +7 -203
- package/dist/index.js +108 -113
- package/dist/org/index.d.ts +1 -1
- package/dist/permissions/index.js +5 -2
- package/dist/plugins/index.d.ts +2 -2
- package/dist/presets/index.d.ts +6 -6
- package/dist/presets/index.js +3 -1
- package/dist/presets/multiTenant.d.ts +1 -1
- package/dist/registry/index.d.ts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +6 -23
- package/dist/types/index.d.ts +1 -1
- package/dist/{types-0IPhH_NR.d.ts → types-zpN48n6B.d.ts} +1 -1
- package/dist/utils/index.d.ts +28 -4
- package/dist/utils/index.js +17 -8
- package/package.json +8 -14
package/dist/index.js
CHANGED
|
@@ -2286,30 +2286,30 @@ var BaseController = class _BaseController {
|
|
|
2286
2286
|
/**
|
|
2287
2287
|
* Build service context from IRequestContext
|
|
2288
2288
|
*/
|
|
2289
|
-
_buildContext(
|
|
2290
|
-
const parsed = this.queryParser.parse(
|
|
2291
|
-
const arcContext =
|
|
2292
|
-
const selectString = this._selectToString(parsed.select) ??
|
|
2289
|
+
_buildContext(req) {
|
|
2290
|
+
const parsed = this.queryParser.parse(req.query);
|
|
2291
|
+
const arcContext = req.metadata;
|
|
2292
|
+
const selectString = this._selectToString(parsed.select) ?? req.query?.select;
|
|
2293
2293
|
const sanitizedSelect = this._sanitizeSelect(selectString, this.schemaOptions);
|
|
2294
2294
|
return {
|
|
2295
|
-
user:
|
|
2296
|
-
organizationId: arcContext?.organizationId ?? void 0,
|
|
2295
|
+
user: req.user,
|
|
2296
|
+
organizationId: arcContext?.organizationId ?? req.organizationId ?? void 0,
|
|
2297
2297
|
select: sanitizedSelect ? sanitizedSelect.split(/\s+/) : void 0,
|
|
2298
2298
|
populate: this._sanitizePopulate(parsed.populate, this.schemaOptions),
|
|
2299
|
-
lean: this._parseLean(
|
|
2299
|
+
lean: this._parseLean(req.query?.lean)
|
|
2300
2300
|
};
|
|
2301
2301
|
}
|
|
2302
2302
|
/**
|
|
2303
2303
|
* Parse query into QueryOptions using queryParser
|
|
2304
2304
|
*/
|
|
2305
|
-
_parseQueryOptions(
|
|
2306
|
-
const parsed = this.queryParser.parse(
|
|
2307
|
-
const arcContext =
|
|
2305
|
+
_parseQueryOptions(req) {
|
|
2306
|
+
const parsed = this.queryParser.parse(req.query);
|
|
2307
|
+
const arcContext = req.metadata;
|
|
2308
2308
|
delete parsed.filters._policyFilters;
|
|
2309
2309
|
const limit = Math.min(Math.max(1, parsed.limit || this.defaultLimit), this.maxLimit);
|
|
2310
2310
|
const page = parsed.after ? void 0 : parsed.page ? Math.max(1, parsed.page) : 1;
|
|
2311
2311
|
const sortString = parsed.sort ? Object.entries(parsed.sort).map(([k, v]) => v === -1 ? `-${k}` : k).join(",") : this.defaultSort;
|
|
2312
|
-
const selectString = this._selectToString(parsed.select) ??
|
|
2312
|
+
const selectString = this._selectToString(parsed.select) ?? req.query?.select;
|
|
2313
2313
|
return {
|
|
2314
2314
|
page,
|
|
2315
2315
|
limit,
|
|
@@ -2320,23 +2320,24 @@ var BaseController = class _BaseController {
|
|
|
2320
2320
|
// MongoKit features
|
|
2321
2321
|
search: parsed.search,
|
|
2322
2322
|
after: parsed.after,
|
|
2323
|
-
user:
|
|
2324
|
-
organizationId: arcContext?.organizationId,
|
|
2323
|
+
user: req.user,
|
|
2324
|
+
organizationId: arcContext?.organizationId ?? req.organizationId,
|
|
2325
2325
|
context: arcContext
|
|
2326
2326
|
};
|
|
2327
2327
|
}
|
|
2328
2328
|
/**
|
|
2329
2329
|
* Apply org and policy filters
|
|
2330
2330
|
*/
|
|
2331
|
-
_applyFilters(options,
|
|
2331
|
+
_applyFilters(options, req) {
|
|
2332
2332
|
const filters = { ...options.filters };
|
|
2333
|
-
const arcContext =
|
|
2333
|
+
const arcContext = req.metadata;
|
|
2334
2334
|
const policyFilters = arcContext?._policyFilters;
|
|
2335
2335
|
if (policyFilters) {
|
|
2336
2336
|
Object.assign(filters, policyFilters);
|
|
2337
2337
|
}
|
|
2338
|
-
|
|
2339
|
-
|
|
2338
|
+
const orgId = arcContext?.organizationId ?? req.organizationId;
|
|
2339
|
+
if (orgId) {
|
|
2340
|
+
filters.organizationId = orgId;
|
|
2340
2341
|
}
|
|
2341
2342
|
return { ...options, filters };
|
|
2342
2343
|
}
|
|
@@ -2344,15 +2345,16 @@ var BaseController = class _BaseController {
|
|
|
2344
2345
|
* Build filter for single-item operations (get/update/delete)
|
|
2345
2346
|
* Combines ID filter with policy/org filters for proper security enforcement
|
|
2346
2347
|
*/
|
|
2347
|
-
_buildIdFilter(id,
|
|
2348
|
+
_buildIdFilter(id, req) {
|
|
2348
2349
|
const filter = { _id: id };
|
|
2349
|
-
const arcContext =
|
|
2350
|
+
const arcContext = req.metadata;
|
|
2350
2351
|
const policyFilters = arcContext?._policyFilters;
|
|
2351
2352
|
if (policyFilters) {
|
|
2352
2353
|
Object.assign(filter, policyFilters);
|
|
2353
2354
|
}
|
|
2354
|
-
|
|
2355
|
-
|
|
2355
|
+
const orgId = arcContext?.organizationId ?? req.organizationId;
|
|
2356
|
+
if (orgId) {
|
|
2357
|
+
filter.organizationId = orgId;
|
|
2356
2358
|
}
|
|
2357
2359
|
return filter;
|
|
2358
2360
|
}
|
|
@@ -2436,8 +2438,8 @@ var BaseController = class _BaseController {
|
|
|
2436
2438
|
* Validates that fetched item satisfies all policy constraints
|
|
2437
2439
|
* Supports MongoDB query operators: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $regex, $and, $or
|
|
2438
2440
|
*/
|
|
2439
|
-
_checkPolicyFilters(item,
|
|
2440
|
-
const arcContext =
|
|
2441
|
+
_checkPolicyFilters(item, req) {
|
|
2442
|
+
const arcContext = req.metadata;
|
|
2441
2443
|
const policyFilters = arcContext?._policyFilters;
|
|
2442
2444
|
if (!policyFilters) return true;
|
|
2443
2445
|
if (policyFilters.$and && Array.isArray(policyFilters.$and)) {
|
|
@@ -2520,8 +2522,8 @@ var BaseController = class _BaseController {
|
|
|
2520
2522
|
return String(itemOrgId) === String(arcContext.organizationId);
|
|
2521
2523
|
}
|
|
2522
2524
|
/** Check ownership for update/delete (ownedByUser preset) */
|
|
2523
|
-
_checkOwnership(item,
|
|
2524
|
-
const ownershipCheck =
|
|
2525
|
+
_checkOwnership(item, req) {
|
|
2526
|
+
const ownershipCheck = req.metadata?._ownershipCheck;
|
|
2525
2527
|
if (!item || !ownershipCheck) return true;
|
|
2526
2528
|
const { field, userId } = ownershipCheck;
|
|
2527
2529
|
const itemOwnerId = item[field];
|
|
@@ -2532,8 +2534,8 @@ var BaseController = class _BaseController {
|
|
|
2532
2534
|
* Get hook system from context (instance-scoped) or fall back to global singleton
|
|
2533
2535
|
* This allows proper isolation when running multiple app instances (e.g., in tests)
|
|
2534
2536
|
*/
|
|
2535
|
-
_getHooks(
|
|
2536
|
-
const arcMeta =
|
|
2537
|
+
_getHooks(req) {
|
|
2538
|
+
const arcMeta = req.metadata?.arc;
|
|
2537
2539
|
return arcMeta?.hooks ?? hookSystem;
|
|
2538
2540
|
}
|
|
2539
2541
|
// ============================================================================
|
|
@@ -2543,9 +2545,9 @@ var BaseController = class _BaseController {
|
|
|
2543
2545
|
* List resources with filtering, pagination, sorting
|
|
2544
2546
|
* Implements IController.list()
|
|
2545
2547
|
*/
|
|
2546
|
-
async list(
|
|
2547
|
-
const options = this._parseQueryOptions(
|
|
2548
|
-
const filteredOptions = this._applyFilters(options,
|
|
2548
|
+
async list(req) {
|
|
2549
|
+
const options = this._parseQueryOptions(req);
|
|
2550
|
+
const filteredOptions = this._applyFilters(options, req);
|
|
2549
2551
|
const result = await this.repository.getAll(filteredOptions);
|
|
2550
2552
|
if (Array.isArray(result)) {
|
|
2551
2553
|
return {
|
|
@@ -2572,8 +2574,8 @@ var BaseController = class _BaseController {
|
|
|
2572
2574
|
* Get single resource by ID
|
|
2573
2575
|
* Implements IController.get()
|
|
2574
2576
|
*/
|
|
2575
|
-
async get(
|
|
2576
|
-
const id =
|
|
2577
|
+
async get(req) {
|
|
2578
|
+
const id = req.params.id;
|
|
2577
2579
|
if (!id) {
|
|
2578
2580
|
return {
|
|
2579
2581
|
success: false,
|
|
@@ -2581,11 +2583,11 @@ var BaseController = class _BaseController {
|
|
|
2581
2583
|
status: 400
|
|
2582
2584
|
};
|
|
2583
2585
|
}
|
|
2584
|
-
const options = this._parseQueryOptions(
|
|
2585
|
-
const arcContext =
|
|
2586
|
+
const options = this._parseQueryOptions(req);
|
|
2587
|
+
const arcContext = req.metadata;
|
|
2586
2588
|
try {
|
|
2587
2589
|
const item = await this.repository.getById(id, options);
|
|
2588
|
-
if (!item || !this._checkOrgScope(item, arcContext) || !this._checkPolicyFilters(item,
|
|
2590
|
+
if (!item || !this._checkOrgScope(item, arcContext) || !this._checkPolicyFilters(item, req)) {
|
|
2589
2591
|
return {
|
|
2590
2592
|
success: false,
|
|
2591
2593
|
error: "Resource not found",
|
|
@@ -2612,18 +2614,18 @@ var BaseController = class _BaseController {
|
|
|
2612
2614
|
* Create new resource
|
|
2613
2615
|
* Implements IController.create()
|
|
2614
2616
|
*/
|
|
2615
|
-
async create(
|
|
2616
|
-
const data = { ...
|
|
2617
|
-
const arcContext =
|
|
2617
|
+
async create(req) {
|
|
2618
|
+
const data = { ...req.body };
|
|
2619
|
+
const arcContext = req.metadata;
|
|
2618
2620
|
if (arcContext?.organizationId) {
|
|
2619
2621
|
data.organizationId = arcContext.organizationId;
|
|
2620
2622
|
}
|
|
2621
|
-
const userId = getUserId(
|
|
2623
|
+
const userId = getUserId(req.user);
|
|
2622
2624
|
if (userId) {
|
|
2623
2625
|
data.createdBy = userId;
|
|
2624
2626
|
}
|
|
2625
|
-
const hooks = this._getHooks(
|
|
2626
|
-
const user =
|
|
2627
|
+
const hooks = this._getHooks(req);
|
|
2628
|
+
const user = req.user;
|
|
2627
2629
|
let processedData = data;
|
|
2628
2630
|
if (this.resourceName) {
|
|
2629
2631
|
processedData = await hooks.executeBefore(this.resourceName, "create", data, {
|
|
@@ -2652,8 +2654,8 @@ var BaseController = class _BaseController {
|
|
|
2652
2654
|
* Update existing resource
|
|
2653
2655
|
* Implements IController.update()
|
|
2654
2656
|
*/
|
|
2655
|
-
async update(
|
|
2656
|
-
const id =
|
|
2657
|
+
async update(req) {
|
|
2658
|
+
const id = req.params.id;
|
|
2657
2659
|
if (!id) {
|
|
2658
2660
|
return {
|
|
2659
2661
|
success: false,
|
|
@@ -2661,9 +2663,9 @@ var BaseController = class _BaseController {
|
|
|
2661
2663
|
status: 400
|
|
2662
2664
|
};
|
|
2663
2665
|
}
|
|
2664
|
-
const data = { ...
|
|
2665
|
-
const arcContext =
|
|
2666
|
-
const user =
|
|
2666
|
+
const data = { ...req.body };
|
|
2667
|
+
const arcContext = req.metadata;
|
|
2668
|
+
const user = req.user;
|
|
2667
2669
|
const userId = getUserId(user);
|
|
2668
2670
|
if (userId) {
|
|
2669
2671
|
data.updatedBy = userId;
|
|
@@ -2676,14 +2678,14 @@ var BaseController = class _BaseController {
|
|
|
2676
2678
|
status: 404
|
|
2677
2679
|
};
|
|
2678
2680
|
}
|
|
2679
|
-
if (!this._checkOrgScope(existing, arcContext) || !this._checkPolicyFilters(existing,
|
|
2681
|
+
if (!this._checkOrgScope(existing, arcContext) || !this._checkPolicyFilters(existing, req)) {
|
|
2680
2682
|
return {
|
|
2681
2683
|
success: false,
|
|
2682
2684
|
error: "Resource not found",
|
|
2683
2685
|
status: 404
|
|
2684
2686
|
};
|
|
2685
2687
|
}
|
|
2686
|
-
if (!this._checkOwnership(existing,
|
|
2688
|
+
if (!this._checkOwnership(existing, req)) {
|
|
2687
2689
|
return {
|
|
2688
2690
|
success: false,
|
|
2689
2691
|
error: "You do not have permission to modify this resource",
|
|
@@ -2691,7 +2693,7 @@ var BaseController = class _BaseController {
|
|
|
2691
2693
|
status: 403
|
|
2692
2694
|
};
|
|
2693
2695
|
}
|
|
2694
|
-
const hooks = this._getHooks(
|
|
2696
|
+
const hooks = this._getHooks(req);
|
|
2695
2697
|
let processedData = data;
|
|
2696
2698
|
if (this.resourceName) {
|
|
2697
2699
|
processedData = await hooks.executeBefore(this.resourceName, "update", data, {
|
|
@@ -2729,8 +2731,8 @@ var BaseController = class _BaseController {
|
|
|
2729
2731
|
* Delete resource
|
|
2730
2732
|
* Implements IController.delete()
|
|
2731
2733
|
*/
|
|
2732
|
-
async delete(
|
|
2733
|
-
const id =
|
|
2734
|
+
async delete(req) {
|
|
2735
|
+
const id = req.params.id;
|
|
2734
2736
|
if (!id) {
|
|
2735
2737
|
return {
|
|
2736
2738
|
success: false,
|
|
@@ -2738,8 +2740,8 @@ var BaseController = class _BaseController {
|
|
|
2738
2740
|
status: 400
|
|
2739
2741
|
};
|
|
2740
2742
|
}
|
|
2741
|
-
const arcContext =
|
|
2742
|
-
const user =
|
|
2743
|
+
const arcContext = req.metadata;
|
|
2744
|
+
const user = req.user;
|
|
2743
2745
|
const existing = await this.repository.getById(id);
|
|
2744
2746
|
if (!existing) {
|
|
2745
2747
|
return {
|
|
@@ -2748,14 +2750,14 @@ var BaseController = class _BaseController {
|
|
|
2748
2750
|
status: 404
|
|
2749
2751
|
};
|
|
2750
2752
|
}
|
|
2751
|
-
if (!this._checkOrgScope(existing, arcContext) || !this._checkPolicyFilters(existing,
|
|
2753
|
+
if (!this._checkOrgScope(existing, arcContext) || !this._checkPolicyFilters(existing, req)) {
|
|
2752
2754
|
return {
|
|
2753
2755
|
success: false,
|
|
2754
2756
|
error: "Resource not found",
|
|
2755
2757
|
status: 404
|
|
2756
2758
|
};
|
|
2757
2759
|
}
|
|
2758
|
-
if (!this._checkOwnership(existing,
|
|
2760
|
+
if (!this._checkOwnership(existing, req)) {
|
|
2759
2761
|
return {
|
|
2760
2762
|
success: false,
|
|
2761
2763
|
error: "You do not have permission to delete this resource",
|
|
@@ -2763,7 +2765,7 @@ var BaseController = class _BaseController {
|
|
|
2763
2765
|
status: 403
|
|
2764
2766
|
};
|
|
2765
2767
|
}
|
|
2766
|
-
const hooks = this._getHooks(
|
|
2768
|
+
const hooks = this._getHooks(req);
|
|
2767
2769
|
if (this.resourceName) {
|
|
2768
2770
|
await hooks.executeBefore(this.resourceName, "delete", existing, {
|
|
2769
2771
|
user,
|
|
@@ -2800,8 +2802,9 @@ var BaseController = class _BaseController {
|
|
|
2800
2802
|
// Preset Methods (framework-agnostic versions)
|
|
2801
2803
|
// ============================================================================
|
|
2802
2804
|
/** Get resource by slug (slugLookup preset) */
|
|
2803
|
-
async getBySlug(
|
|
2804
|
-
|
|
2805
|
+
async getBySlug(req) {
|
|
2806
|
+
const repo = this.repository;
|
|
2807
|
+
if (!repo.getBySlug) {
|
|
2805
2808
|
return {
|
|
2806
2809
|
success: false,
|
|
2807
2810
|
error: "Slug lookup not implemented",
|
|
@@ -2809,10 +2812,10 @@ var BaseController = class _BaseController {
|
|
|
2809
2812
|
};
|
|
2810
2813
|
}
|
|
2811
2814
|
const slugField = this._presetFields.slugField ?? "slug";
|
|
2812
|
-
const slug =
|
|
2813
|
-
const options = this._parseQueryOptions(
|
|
2814
|
-
const arcContext =
|
|
2815
|
-
const item = await
|
|
2815
|
+
const slug = req.params[slugField] ?? req.params.slug;
|
|
2816
|
+
const options = this._parseQueryOptions(req);
|
|
2817
|
+
const arcContext = req.metadata;
|
|
2818
|
+
const item = await repo.getBySlug(slug, options);
|
|
2816
2819
|
if (!item || !this._checkOrgScope(item, arcContext)) {
|
|
2817
2820
|
return {
|
|
2818
2821
|
success: false,
|
|
@@ -2827,17 +2830,18 @@ var BaseController = class _BaseController {
|
|
|
2827
2830
|
};
|
|
2828
2831
|
}
|
|
2829
2832
|
/** Get soft-deleted resources (softDelete preset) */
|
|
2830
|
-
async getDeleted(
|
|
2831
|
-
|
|
2833
|
+
async getDeleted(req) {
|
|
2834
|
+
const repo = this.repository;
|
|
2835
|
+
if (!repo.getDeleted) {
|
|
2832
2836
|
return {
|
|
2833
2837
|
success: false,
|
|
2834
2838
|
error: "Soft delete not implemented",
|
|
2835
2839
|
status: 501
|
|
2836
2840
|
};
|
|
2837
2841
|
}
|
|
2838
|
-
const options = this._parseQueryOptions(
|
|
2839
|
-
const filteredOptions = this._applyFilters(options,
|
|
2840
|
-
const result = await
|
|
2842
|
+
const options = this._parseQueryOptions(req);
|
|
2843
|
+
const filteredOptions = this._applyFilters(options, req);
|
|
2844
|
+
const result = await repo.getDeleted(filteredOptions);
|
|
2841
2845
|
if (Array.isArray(result)) {
|
|
2842
2846
|
return {
|
|
2843
2847
|
success: true,
|
|
@@ -2860,15 +2864,16 @@ var BaseController = class _BaseController {
|
|
|
2860
2864
|
};
|
|
2861
2865
|
}
|
|
2862
2866
|
/** Restore soft-deleted resource (softDelete preset) */
|
|
2863
|
-
async restore(
|
|
2864
|
-
|
|
2867
|
+
async restore(req) {
|
|
2868
|
+
const repo = this.repository;
|
|
2869
|
+
if (!repo.restore) {
|
|
2865
2870
|
return {
|
|
2866
2871
|
success: false,
|
|
2867
2872
|
error: "Restore not implemented",
|
|
2868
2873
|
status: 501
|
|
2869
2874
|
};
|
|
2870
2875
|
}
|
|
2871
|
-
const id =
|
|
2876
|
+
const id = req.params.id;
|
|
2872
2877
|
if (!id) {
|
|
2873
2878
|
return {
|
|
2874
2879
|
success: false,
|
|
@@ -2876,7 +2881,7 @@ var BaseController = class _BaseController {
|
|
|
2876
2881
|
status: 400
|
|
2877
2882
|
};
|
|
2878
2883
|
}
|
|
2879
|
-
const item = await
|
|
2884
|
+
const item = await repo.restore(id);
|
|
2880
2885
|
if (!item) {
|
|
2881
2886
|
return {
|
|
2882
2887
|
success: false,
|
|
@@ -2892,17 +2897,18 @@ var BaseController = class _BaseController {
|
|
|
2892
2897
|
};
|
|
2893
2898
|
}
|
|
2894
2899
|
/** Get hierarchical tree (tree preset) */
|
|
2895
|
-
async getTree(
|
|
2896
|
-
|
|
2900
|
+
async getTree(req) {
|
|
2901
|
+
const repo = this.repository;
|
|
2902
|
+
if (!repo.getTree) {
|
|
2897
2903
|
return {
|
|
2898
2904
|
success: false,
|
|
2899
2905
|
error: "Tree structure not implemented",
|
|
2900
2906
|
status: 501
|
|
2901
2907
|
};
|
|
2902
2908
|
}
|
|
2903
|
-
const options = this._parseQueryOptions(
|
|
2904
|
-
const filteredOptions = this._applyFilters(options,
|
|
2905
|
-
const tree = await
|
|
2909
|
+
const options = this._parseQueryOptions(req);
|
|
2910
|
+
const filteredOptions = this._applyFilters(options, req);
|
|
2911
|
+
const tree = await repo.getTree(filteredOptions);
|
|
2906
2912
|
return {
|
|
2907
2913
|
success: true,
|
|
2908
2914
|
data: tree,
|
|
@@ -2910,8 +2916,9 @@ var BaseController = class _BaseController {
|
|
|
2910
2916
|
};
|
|
2911
2917
|
}
|
|
2912
2918
|
/** Get children of parent (tree preset) */
|
|
2913
|
-
async getChildren(
|
|
2914
|
-
|
|
2919
|
+
async getChildren(req) {
|
|
2920
|
+
const repo = this.repository;
|
|
2921
|
+
if (!repo.getChildren) {
|
|
2915
2922
|
return {
|
|
2916
2923
|
success: false,
|
|
2917
2924
|
error: "Tree structure not implemented",
|
|
@@ -2919,10 +2926,10 @@ var BaseController = class _BaseController {
|
|
|
2919
2926
|
};
|
|
2920
2927
|
}
|
|
2921
2928
|
const parentField = this._presetFields.parentField ?? "parent";
|
|
2922
|
-
const parentId =
|
|
2923
|
-
const options = this._parseQueryOptions(
|
|
2924
|
-
const filteredOptions = this._applyFilters(options,
|
|
2925
|
-
const children = await
|
|
2929
|
+
const parentId = req.params[parentField] ?? req.params.parent ?? req.params.id;
|
|
2930
|
+
const options = this._parseQueryOptions(req);
|
|
2931
|
+
const filteredOptions = this._applyFilters(options, req);
|
|
2932
|
+
const children = await repo.getChildren(parentId, filteredOptions);
|
|
2926
2933
|
return {
|
|
2927
2934
|
success: true,
|
|
2928
2935
|
data: children,
|
|
@@ -2974,13 +2981,15 @@ function createRequestContext(req) {
|
|
|
2974
2981
|
const user = reqWithExtras.user;
|
|
2975
2982
|
return {
|
|
2976
2983
|
...user,
|
|
2984
|
+
// Normalize ID for MongoDB compatibility
|
|
2977
2985
|
id: String(user._id ?? user.id),
|
|
2978
|
-
_id: user._id ?? user.id
|
|
2979
|
-
//
|
|
2980
|
-
|
|
2986
|
+
_id: user._id ?? user.id
|
|
2987
|
+
// Preserve original role/roles/permissions as-is
|
|
2988
|
+
// Devs can define their own authorization structure
|
|
2981
2989
|
};
|
|
2982
2990
|
})() : void 0,
|
|
2983
|
-
|
|
2991
|
+
organizationId: reqWithExtras.organizationId,
|
|
2992
|
+
metadata: {
|
|
2984
2993
|
...reqWithExtras.context,
|
|
2985
2994
|
// Include Arc metadata for hook execution
|
|
2986
2995
|
arc: reqWithExtras.arc,
|
|
@@ -3028,8 +3037,8 @@ function sendControllerResponse(reply, response, request) {
|
|
|
3028
3037
|
}
|
|
3029
3038
|
function createFastifyHandler(controllerMethod) {
|
|
3030
3039
|
return async (req, reply) => {
|
|
3031
|
-
const
|
|
3032
|
-
const response = await controllerMethod(
|
|
3040
|
+
const requestContext = createRequestContext(req);
|
|
3041
|
+
const response = await controllerMethod(requestContext);
|
|
3033
3042
|
sendControllerResponse(reply, response, req);
|
|
3034
3043
|
};
|
|
3035
3044
|
}
|
|
@@ -3297,15 +3306,16 @@ function allowPublic() {
|
|
|
3297
3306
|
return check;
|
|
3298
3307
|
}
|
|
3299
3308
|
function requireAuth() {
|
|
3300
|
-
|
|
3309
|
+
const check = (ctx) => {
|
|
3301
3310
|
if (!ctx.user) {
|
|
3302
3311
|
return { granted: false, reason: "Authentication required" };
|
|
3303
3312
|
}
|
|
3304
3313
|
return true;
|
|
3305
3314
|
};
|
|
3315
|
+
return check;
|
|
3306
3316
|
}
|
|
3307
3317
|
function requireRoles(roles, options) {
|
|
3308
|
-
|
|
3318
|
+
const check = (ctx) => {
|
|
3309
3319
|
if (!ctx.user) {
|
|
3310
3320
|
return { granted: false, reason: "Authentication required" };
|
|
3311
3321
|
}
|
|
@@ -3321,6 +3331,8 @@ function requireRoles(roles, options) {
|
|
|
3321
3331
|
reason: `Required roles: ${roles.join(", ")}`
|
|
3322
3332
|
};
|
|
3323
3333
|
};
|
|
3334
|
+
check._roles = roles;
|
|
3335
|
+
return check;
|
|
3324
3336
|
}
|
|
3325
3337
|
function requireOwnership(ownerField = "userId", options) {
|
|
3326
3338
|
return (ctx) => {
|
|
@@ -4545,9 +4557,7 @@ async function loadPlugin(name, logger) {
|
|
|
4545
4557
|
const err = error;
|
|
4546
4558
|
const isModuleNotFound = err.message.includes("Cannot find module") || err.message.includes("Cannot find package") || err.message.includes("MODULE_NOT_FOUND") || err.message.includes("Could not resolve");
|
|
4547
4559
|
if (isModuleNotFound && OPTIONAL_PLUGINS.has(name)) {
|
|
4548
|
-
logger?.warn(
|
|
4549
|
-
`ℹ️ Optional plugin '${name}' skipped (${packageName} not installed)`
|
|
4550
|
-
);
|
|
4560
|
+
logger?.warn(`ℹ️ Optional plugin '${name}' skipped (${packageName} not installed)`);
|
|
4551
4561
|
return null;
|
|
4552
4562
|
}
|
|
4553
4563
|
if (isModuleNotFound) {
|
|
@@ -4586,10 +4596,7 @@ async function createApp(options) {
|
|
|
4586
4596
|
});
|
|
4587
4597
|
if (config.helmet !== false) {
|
|
4588
4598
|
const helmet = await loadPlugin("helmet");
|
|
4589
|
-
await fastify.register(
|
|
4590
|
-
helmet,
|
|
4591
|
-
config.helmet ?? {}
|
|
4592
|
-
);
|
|
4599
|
+
await fastify.register(helmet, config.helmet ?? {});
|
|
4593
4600
|
fastify.log.info("✅ Helmet (security headers) enabled");
|
|
4594
4601
|
} else {
|
|
4595
4602
|
fastify.log.warn("⚠️ Helmet disabled - security headers not applied");
|
|
@@ -4609,20 +4616,14 @@ async function createApp(options) {
|
|
|
4609
4616
|
}
|
|
4610
4617
|
if (config.rateLimit !== false) {
|
|
4611
4618
|
const rateLimit = await loadPlugin("rateLimit");
|
|
4612
|
-
await fastify.register(
|
|
4613
|
-
rateLimit,
|
|
4614
|
-
config.rateLimit ?? { max: 100, timeWindow: "1 minute" }
|
|
4615
|
-
);
|
|
4619
|
+
await fastify.register(rateLimit, config.rateLimit ?? { max: 100, timeWindow: "1 minute" });
|
|
4616
4620
|
fastify.log.info("✅ Rate limiting enabled");
|
|
4617
4621
|
} else {
|
|
4618
4622
|
fastify.log.warn("⚠️ Rate limiting disabled");
|
|
4619
4623
|
}
|
|
4620
4624
|
if (config.underPressure !== false) {
|
|
4621
4625
|
const underPressure = await loadPlugin("underPressure");
|
|
4622
|
-
await fastify.register(
|
|
4623
|
-
underPressure,
|
|
4624
|
-
config.underPressure ?? { exposeStatusRoute: true }
|
|
4625
|
-
);
|
|
4626
|
+
await fastify.register(underPressure, config.underPressure ?? { exposeStatusRoute: true });
|
|
4626
4627
|
fastify.log.info("✅ Health monitoring (under-pressure) enabled");
|
|
4627
4628
|
} else {
|
|
4628
4629
|
fastify.log.info("ℹ️ Health monitoring disabled");
|
|
@@ -4642,10 +4643,7 @@ async function createApp(options) {
|
|
|
4642
4643
|
files: 10
|
|
4643
4644
|
}
|
|
4644
4645
|
};
|
|
4645
|
-
await fastify.register(multipart, {
|
|
4646
|
-
...multipartDefaults,
|
|
4647
|
-
...config.multipart
|
|
4648
|
-
});
|
|
4646
|
+
await fastify.register(multipart, { ...multipartDefaults, ...config.multipart });
|
|
4649
4647
|
fastify.log.info("✅ Multipart (file uploads) enabled");
|
|
4650
4648
|
}
|
|
4651
4649
|
}
|
|
@@ -4658,10 +4656,7 @@ async function createApp(options) {
|
|
|
4658
4656
|
encoding: "utf8",
|
|
4659
4657
|
runFirst: true
|
|
4660
4658
|
};
|
|
4661
|
-
await fastify.register(rawBody, {
|
|
4662
|
-
...rawBodyDefaults,
|
|
4663
|
-
...config.rawBody
|
|
4664
|
-
});
|
|
4659
|
+
await fastify.register(rawBody, { ...rawBodyDefaults, ...config.rawBody });
|
|
4665
4660
|
fastify.log.info("✅ Raw body parsing enabled");
|
|
4666
4661
|
}
|
|
4667
4662
|
}
|
package/dist/org/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RouteHandlerMethod, FastifyPluginAsync } from 'fastify';
|
|
2
|
-
import {
|
|
2
|
+
import { b as RequestContext, Z as OrgScopeOptions, z as RouteHandler } from '../index-D5QTob1X.js';
|
|
3
3
|
import { U as UserBase } from '../types-B99TBmFV.js';
|
|
4
4
|
import 'mongoose';
|
|
5
5
|
|
|
@@ -5,15 +5,16 @@ function allowPublic() {
|
|
|
5
5
|
return check;
|
|
6
6
|
}
|
|
7
7
|
function requireAuth() {
|
|
8
|
-
|
|
8
|
+
const check = (ctx) => {
|
|
9
9
|
if (!ctx.user) {
|
|
10
10
|
return { granted: false, reason: "Authentication required" };
|
|
11
11
|
}
|
|
12
12
|
return true;
|
|
13
13
|
};
|
|
14
|
+
return check;
|
|
14
15
|
}
|
|
15
16
|
function requireRoles(roles, options) {
|
|
16
|
-
|
|
17
|
+
const check = (ctx) => {
|
|
17
18
|
if (!ctx.user) {
|
|
18
19
|
return { granted: false, reason: "Authentication required" };
|
|
19
20
|
}
|
|
@@ -29,6 +30,8 @@ function requireRoles(roles, options) {
|
|
|
29
30
|
reason: `Required roles: ${roles.join(", ")}`
|
|
30
31
|
};
|
|
31
32
|
};
|
|
33
|
+
check._roles = roles;
|
|
34
|
+
return check;
|
|
32
35
|
}
|
|
33
36
|
function requireOwnership(ownerField = "userId", options) {
|
|
34
37
|
return (ctx) => {
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { k as ArcCore, A as ArcCorePluginOptions, G as GracefulShutdownOptions, b as HealthCheck, H as HealthOptions, R as RequestIdOptions, T as TracingOptions, f as arcCorePlugin, j as arcCorePluginFn, d as createSpan, e as gracefulShutdownPlugin, g as gracefulShutdownPluginFn, a as healthPlugin, h as healthPluginFn, i as isTracingAvailable, _ as requestIdPlugin, r as requestIdPluginFn, t as traced, c as tracingPlugin } from '../arcCorePlugin-
|
|
1
|
+
export { k as ArcCore, A as ArcCorePluginOptions, G as GracefulShutdownOptions, b as HealthCheck, H as HealthOptions, R as RequestIdOptions, T as TracingOptions, f as arcCorePlugin, j as arcCorePluginFn, d as createSpan, e as gracefulShutdownPlugin, g as gracefulShutdownPluginFn, a as healthPlugin, h as healthPluginFn, i as isTracingAvailable, _ as requestIdPlugin, r as requestIdPluginFn, t as traced, c as tracingPlugin } from '../arcCorePlugin-CAjBQtZB.js';
|
|
2
2
|
import { FastifyInstance, FastifyRequest } from 'fastify';
|
|
3
|
-
import '../index-
|
|
3
|
+
import '../index-D5QTob1X.js';
|
|
4
4
|
import 'mongoose';
|
|
5
5
|
import '../types-B99TBmFV.js';
|
|
6
6
|
|
package/dist/presets/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MultiTenantOptions } from './multiTenant.js';
|
|
2
2
|
export { default as multiTenantPreset } from './multiTenant.js';
|
|
3
|
-
import {
|
|
3
|
+
import { f as PresetResult, a as IRequestContext, c as IControllerResponse, P as PaginatedResult, A as AnyRecord, l as ResourceConfig } from '../index-D5QTob1X.js';
|
|
4
4
|
import 'mongoose';
|
|
5
5
|
import 'fastify';
|
|
6
6
|
import '../types-B99TBmFV.js';
|
|
@@ -142,12 +142,12 @@ interface ISoftDeleteController<TDoc = unknown> {
|
|
|
142
142
|
* Get all soft-deleted items
|
|
143
143
|
* Called by: GET /deleted
|
|
144
144
|
*/
|
|
145
|
-
getDeleted(
|
|
145
|
+
getDeleted(req: IRequestContext): Promise<IControllerResponse<PaginatedResult<TDoc>>>;
|
|
146
146
|
/**
|
|
147
147
|
* Restore a soft-deleted item by ID
|
|
148
148
|
* Called by: POST /:id/restore
|
|
149
149
|
*/
|
|
150
|
-
restore(
|
|
150
|
+
restore(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
|
|
151
151
|
}
|
|
152
152
|
/**
|
|
153
153
|
* Slug Lookup Preset Interface
|
|
@@ -179,7 +179,7 @@ interface ISlugLookupController<TDoc = unknown> {
|
|
|
179
179
|
* Get a resource by its slug
|
|
180
180
|
* Called by: GET /slug/:slug
|
|
181
181
|
*/
|
|
182
|
-
getBySlug(
|
|
182
|
+
getBySlug(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
|
|
183
183
|
}
|
|
184
184
|
/**
|
|
185
185
|
* Tree Preset Interface
|
|
@@ -213,12 +213,12 @@ interface ITreeController<TDoc = unknown> {
|
|
|
213
213
|
* Get the full hierarchical tree
|
|
214
214
|
* Called by: GET /tree
|
|
215
215
|
*/
|
|
216
|
-
getTree(
|
|
216
|
+
getTree(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
|
|
217
217
|
/**
|
|
218
218
|
* Get direct children of a parent node
|
|
219
219
|
* Called by: GET /:parent/children
|
|
220
220
|
*/
|
|
221
|
-
getChildren(
|
|
221
|
+
getChildren(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
|
|
222
222
|
}
|
|
223
223
|
/**
|
|
224
224
|
* Owned By User Preset
|
package/dist/presets/index.js
CHANGED
|
@@ -5,7 +5,7 @@ function allowPublic() {
|
|
|
5
5
|
return check;
|
|
6
6
|
}
|
|
7
7
|
function requireRoles(roles, options) {
|
|
8
|
-
|
|
8
|
+
const check = (ctx) => {
|
|
9
9
|
if (!ctx.user) {
|
|
10
10
|
return { granted: false, reason: "Authentication required" };
|
|
11
11
|
}
|
|
@@ -18,6 +18,8 @@ function requireRoles(roles, options) {
|
|
|
18
18
|
reason: `Required roles: ${roles.join(", ")}`
|
|
19
19
|
};
|
|
20
20
|
};
|
|
21
|
+
check._roles = roles;
|
|
22
|
+
return check;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
// src/presets/softDelete.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as RequestWithExtras, e as CrudRouteKey, f as PresetResult } from '../index-D5QTob1X.js';
|
|
2
2
|
import 'mongoose';
|
|
3
3
|
import 'fastify';
|
|
4
4
|
import '../types-B99TBmFV.js';
|
package/dist/registry/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { i as IntrospectionPluginOptions } from '../index-D5QTob1X.js';
|
|
2
|
+
export { k as RegisterOptions, j as ResourceRegistry, r as resourceRegistry } from '../index-D5QTob1X.js';
|
|
3
3
|
import { FastifyPluginAsync } from 'fastify';
|
|
4
4
|
import 'mongoose';
|
|
5
5
|
import '../types-B99TBmFV.js';
|