@opensaas/stack-core 0.26.0 → 0.27.1

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 (73) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +54 -12
  3. package/dist/access/access-filter.d.ts +18 -1
  4. package/dist/access/access-filter.d.ts.map +1 -1
  5. package/dist/access/access-filter.js +62 -5
  6. package/dist/access/access-filter.js.map +1 -1
  7. package/dist/access/access-filter.test.d.ts +2 -0
  8. package/dist/access/access-filter.test.d.ts.map +1 -0
  9. package/dist/access/access-filter.test.js +116 -0
  10. package/dist/access/access-filter.test.js.map +1 -0
  11. package/dist/access/field-visibility.js.map +1 -1
  12. package/dist/access/index.d.ts +1 -1
  13. package/dist/access/index.d.ts.map +1 -1
  14. package/dist/access/index.js +1 -1
  15. package/dist/access/index.js.map +1 -1
  16. package/dist/access/multi-column-read-write.test.js.map +1 -1
  17. package/dist/config/label.d.ts +22 -0
  18. package/dist/config/label.d.ts.map +1 -0
  19. package/dist/config/label.js +48 -0
  20. package/dist/config/label.js.map +1 -0
  21. package/dist/config/plugin-engine.js.map +1 -1
  22. package/dist/config/types.d.ts +19 -5
  23. package/dist/config/types.d.ts.map +1 -1
  24. package/dist/context/index.d.ts +7 -0
  25. package/dist/context/index.d.ts.map +1 -1
  26. package/dist/context/index.js +42 -4
  27. package/dist/context/index.js.map +1 -1
  28. package/dist/context/nested-operations.js.map +1 -1
  29. package/dist/context/transaction-boundary.d.ts.map +1 -1
  30. package/dist/context/write-pipeline.d.ts.map +1 -1
  31. package/dist/context/write-pipeline.js.map +1 -1
  32. package/dist/fields/calendar-day.test.js +133 -7
  33. package/dist/fields/calendar-day.test.js.map +1 -1
  34. package/dist/fields/format-prisma-default.js.map +1 -1
  35. package/dist/fields/index.d.ts +7 -3
  36. package/dist/fields/index.d.ts.map +1 -1
  37. package/dist/fields/index.js +37 -8
  38. package/dist/fields/index.js.map +1 -1
  39. package/dist/hooks/index.d.ts.map +1 -1
  40. package/dist/hooks/index.js.map +1 -1
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +8 -0
  44. package/dist/index.js.map +1 -1
  45. package/dist/query/index.d.ts.map +1 -1
  46. package/dist/query/relationship-options.d.ts +26 -0
  47. package/dist/query/relationship-options.d.ts.map +1 -0
  48. package/dist/query/relationship-options.js +43 -0
  49. package/dist/query/relationship-options.js.map +1 -0
  50. package/dist/query/relationship-options.test.d.ts +2 -0
  51. package/dist/query/relationship-options.test.d.ts.map +1 -0
  52. package/dist/query/relationship-options.test.js +121 -0
  53. package/dist/query/relationship-options.test.js.map +1 -0
  54. package/dist/utils/password.d.ts.map +1 -1
  55. package/dist/utils/password.js.map +1 -1
  56. package/dist/validation/schema.js.map +1 -1
  57. package/package.json +6 -5
  58. package/src/access/access-filter.test.ts +149 -0
  59. package/src/access/access-filter.ts +82 -9
  60. package/src/access/index.ts +5 -1
  61. package/src/config/label.ts +58 -0
  62. package/src/config/types.ts +20 -13
  63. package/src/context/index.ts +57 -5
  64. package/src/context/write-pipeline.ts +1 -2
  65. package/src/fields/calendar-day.test.ts +158 -7
  66. package/src/fields/index.ts +39 -11
  67. package/src/hooks/index.ts +1 -2
  68. package/src/index.ts +11 -0
  69. package/src/query/relationship-options.test.ts +157 -0
  70. package/src/query/relationship-options.ts +70 -0
  71. package/tests/context.test.ts +220 -0
  72. package/tests/label.test.ts +135 -0
  73. package/tsconfig.tsbuildinfo +1 -1
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,8CAA8C;AAC9C,EAAE;AACF,kEAAkE;AAClE,gEAAgE;AAChE,gEAAgE;AAChE,6DAA6D;AAC7D,yEAAyE;AACzE,kEAAkE;AAElE,kBAAkB;AAClB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAuBhD,kBAAkB;AAClB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAO/C,0EAA0E;AAC1E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5E,gDAAgD;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAElD,uEAAuE;AACvE,4EAA4E;AAC5E,6EAA6E;AAC7E,oEAAoE;AACpE,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AAGxF,qEAAqE;AACrE,wEAAwE;AACxE,4EAA4E;AAC5E,6EAA6E;AAC7E,+EAA+E;AAC/E,gEAAgE;AAChE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,8CAA8C;AAC9C,EAAE;AACF,kEAAkE;AAClE,gEAAgE;AAChE,gEAAgE;AAChE,6DAA6D;AAC7D,yEAAyE;AACzE,kEAAkE;AAElE,kBAAkB;AAClB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAuBhD,kBAAkB;AAClB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAO/C,0EAA0E;AAC1E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5E,0EAA0E;AAC1E,yEAAyE;AACzE,2DAA2D;AAC3D,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEnE,gDAAgD;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAElD,uEAAuE;AACvE,4EAA4E;AAC5E,6EAA6E;AAC7E,oEAAoE;AACpE,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AAGxF,qEAAqE;AACrE,wEAAwE;AACxE,4EAA4E;AAC5E,6EAA6E;AAC7E,+EAA+E;AAC/E,gEAAgE;AAChE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAGxE,qEAAqE;AACrE,6EAA6E;AAC7E,yEAAyE;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { OpenSaasConfig } from '../config/types.js';
2
+ import { type QueryRunnerContext } from './index.js';
3
+ export interface RelationshipOption {
4
+ id: string;
5
+ label: string;
6
+ }
7
+ export interface RelationshipOptionsArgs {
8
+ /** Filters the label field via `contains` when it is a text field. */
9
+ search?: string;
10
+ /** Bounds the primary (search-scoped) window. @default 50 */
11
+ take?: number;
12
+ /** Always unioned into the result, even outside the search/take window. */
13
+ selectedIds?: string[];
14
+ }
15
+ /**
16
+ * Bounded, projected fetch of `{ id, label }` options for a relationship
17
+ * editor — the read primitive behind the `relationshipOptions` serverAction
18
+ * op. Selects only `id` and the resolved label field (via
19
+ * {@link getLabelFieldName}), so the fragment carries no relation keys and
20
+ * `buildIncludeWithAccessControl`'s depth-5 auto-include never runs.
21
+ *
22
+ * Operation-level `query` access on `relatedListKey` still applies — a denied
23
+ * list resolves to `[]` (via the underlying access-controlled `findMany`).
24
+ */
25
+ export declare function getRelationshipOptions(context: QueryRunnerContext, config: OpenSaasConfig, relatedListKey: string, args?: RelationshipOptionsArgs): Promise<RelationshipOption[]>;
26
+ //# sourceMappingURL=relationship-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationship-options.d.ts","sourceRoot":"","sources":["../../src/query/relationship-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExD,OAAO,EAA4B,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAI9E,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,6DAA6D;IAC7D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,cAAc,EACtB,cAAc,EAAE,MAAM,EACtB,IAAI,GAAE,uBAA4B,GACjC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAkC/B"}
@@ -0,0 +1,43 @@
1
+ import { getLabelFieldName, getItemLabel } from '../config/label.js';
2
+ import { defineFragment, runQuery } from './index.js';
3
+ const DEFAULT_TAKE = 50;
4
+ /**
5
+ * Bounded, projected fetch of `{ id, label }` options for a relationship
6
+ * editor — the read primitive behind the `relationshipOptions` serverAction
7
+ * op. Selects only `id` and the resolved label field (via
8
+ * {@link getLabelFieldName}), so the fragment carries no relation keys and
9
+ * `buildIncludeWithAccessControl`'s depth-5 auto-include never runs.
10
+ *
11
+ * Operation-level `query` access on `relatedListKey` still applies — a denied
12
+ * list resolves to `[]` (via the underlying access-controlled `findMany`).
13
+ */
14
+ export async function getRelationshipOptions(context, config, relatedListKey, args = {}) {
15
+ const relatedListConfig = config.lists[relatedListKey];
16
+ if (!relatedListConfig)
17
+ return [];
18
+ const labelField = getLabelFieldName(relatedListConfig);
19
+ const fragment = defineFragment()({
20
+ id: true,
21
+ [labelField]: true,
22
+ });
23
+ const { search, take = DEFAULT_TAKE, selectedIds = [] } = args;
24
+ const labelFieldConfig = relatedListConfig.fields[labelField];
25
+ const where = search && labelFieldConfig?.type === 'text' ? { [labelField]: { contains: search } } : undefined;
26
+ const primary = await runQuery(context, relatedListKey, fragment, {
27
+ where,
28
+ orderBy: { [labelField]: 'asc' },
29
+ take,
30
+ });
31
+ const seenIds = new Set(primary.map((item) => item.id));
32
+ const missingSelectedIds = selectedIds.filter((id) => !seenIds.has(id));
33
+ const selected = missingSelectedIds.length
34
+ ? await runQuery(context, relatedListKey, fragment, {
35
+ where: { id: { in: missingSelectedIds } },
36
+ })
37
+ : [];
38
+ return [...primary, ...selected].map((item) => ({
39
+ id: item.id,
40
+ label: getItemLabel(relatedListConfig, item),
41
+ }));
42
+ }
43
+ //# sourceMappingURL=relationship-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationship-options.js","sourceRoot":"","sources":["../../src/query/relationship-options.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACpE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAA2B,MAAM,YAAY,CAAA;AAE9E,MAAM,YAAY,GAAG,EAAE,CAAA;AAgBvB;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAA2B,EAC3B,MAAsB,EACtB,cAAsB,EACtB,IAAI,GAA4B,EAAE;IAElC,MAAM,iBAAiB,GAAG,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;IACtD,IAAI,CAAC,iBAAiB;QAAE,OAAO,EAAE,CAAA;IAEjC,MAAM,UAAU,GAAG,iBAAiB,CAAC,iBAAiB,CAAC,CAAA;IACvD,MAAM,QAAQ,GAAG,cAAc,EAA2B,CAAC;QACzD,EAAE,EAAE,IAAI;QACR,CAAC,UAAU,CAAC,EAAE,IAAI;KACnB,CAAC,CAAA;IAEF,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,YAAY,EAAE,WAAW,GAAG,EAAE,EAAE,GAAG,IAAI,CAAA;IAC9D,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,MAAM,CAAC,UAAU,CAAkC,CAAA;IAC9F,MAAM,KAAK,GACT,MAAM,IAAI,gBAAgB,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IAElG,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE;QAChE,KAAK;QACL,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE;QAChC,IAAI;KACL,CAAC,CAAA;IAEF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAE,IAAuB,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3E,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;IAEvE,MAAM,QAAQ,GAAG,kBAAkB,CAAC,MAAM;QACxC,CAAC,CAAC,MAAM,QAAQ,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE;YAChD,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,kBAAkB,EAAE,EAAE;SAC1C,CAAC;QACJ,CAAC,CAAC,EAAE,CAAA;IAEN,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC9C,EAAE,EAAG,IAAuB,CAAC,EAAE;QAC/B,KAAK,EAAE,YAAY,CAAC,iBAAiB,EAAE,IAA+B,CAAC;KACxE,CAAC,CAAC,CAAA;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=relationship-options.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationship-options.test.d.ts","sourceRoot":"","sources":["../../src/query/relationship-options.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,121 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { getRelationshipOptions } from './relationship-options.js';
3
+ function makeDelegate(rows) {
4
+ return {
5
+ findMany: vi.fn(async (_args) => rows),
6
+ findFirst: vi.fn(async (_args) => rows[0] ?? null),
7
+ };
8
+ }
9
+ function makeContext(delegates) {
10
+ return { db: delegates };
11
+ }
12
+ const authors = [
13
+ { id: 'a1', name: 'Ada Lovelace' },
14
+ { id: 'a2', name: 'Alan Turing' },
15
+ { id: 'a3', name: 'Grace Hopper' },
16
+ ];
17
+ function makeConfig() {
18
+ return {
19
+ db: { provider: 'sqlite', url: 'file:./test.db' },
20
+ lists: {
21
+ Author: {
22
+ fields: {
23
+ name: { type: 'text' },
24
+ },
25
+ access: { operation: { query: () => true } },
26
+ },
27
+ NumericLabel: {
28
+ fields: {
29
+ rank: { type: 'integer' },
30
+ },
31
+ ui: { labelField: 'rank' },
32
+ access: { operation: { query: () => true } },
33
+ },
34
+ },
35
+ };
36
+ }
37
+ describe('getRelationshipOptions', () => {
38
+ it('returns { id, label }[] via a scalar-only fragment with no nested include', async () => {
39
+ const delegate = makeDelegate(authors);
40
+ const context = makeContext({ author: delegate });
41
+ const config = makeConfig();
42
+ const result = await getRelationshipOptions(context, config, 'Author', {});
43
+ expect(result).toEqual([
44
+ { id: 'a1', label: 'Ada Lovelace' },
45
+ { id: 'a2', label: 'Alan Turing' },
46
+ { id: 'a3', label: 'Grace Hopper' },
47
+ ]);
48
+ const call = delegate.findMany.mock.calls[0][0];
49
+ expect(call.include).toBeUndefined();
50
+ });
51
+ it('bounds the result by take', async () => {
52
+ const delegate = makeDelegate(authors.slice(0, 2));
53
+ const context = makeContext({ author: delegate });
54
+ const config = makeConfig();
55
+ await getRelationshipOptions(context, config, 'Author', { take: 2 });
56
+ expect(delegate.findMany).toHaveBeenCalledWith(expect.objectContaining({ take: 2 }));
57
+ });
58
+ it('orders by the label field ascending and filters via contains on a text label field', async () => {
59
+ const delegate = makeDelegate([authors[0]]);
60
+ const context = makeContext({ author: delegate });
61
+ const config = makeConfig();
62
+ await getRelationshipOptions(context, config, 'Author', { search: 'Ada' });
63
+ expect(delegate.findMany).toHaveBeenCalledWith(expect.objectContaining({
64
+ where: { name: { contains: 'Ada' } },
65
+ orderBy: { name: 'asc' },
66
+ }));
67
+ });
68
+ it('does not filter (first-N) when the label field is not a text field', async () => {
69
+ const rows = [{ id: 'n1', rank: 1 }];
70
+ const delegate = makeDelegate(rows);
71
+ const context = makeContext({ numericLabel: delegate });
72
+ const config = makeConfig();
73
+ await getRelationshipOptions(context, config, 'NumericLabel', { search: '1' });
74
+ const call = delegate.findMany.mock.calls[0][0];
75
+ expect(call.where).toBeUndefined();
76
+ expect(call.orderBy).toEqual({ rank: 'asc' });
77
+ });
78
+ it('unions currently-selected ids even when beyond take / not matching search', async () => {
79
+ // The bounded/search-scoped query only returns a1 (mimicking take:1 + search).
80
+ const primaryDelegate = makeDelegate([authors[0]]);
81
+ const context = makeContext({ author: primaryDelegate });
82
+ const config = makeConfig();
83
+ // The selected-ids query (a separate findMany call) resolves a3, which fell
84
+ // outside the primary window.
85
+ primaryDelegate.findMany.mockImplementationOnce(async () => [authors[0]]);
86
+ primaryDelegate.findMany.mockImplementationOnce(async () => [authors[2]]);
87
+ const result = await getRelationshipOptions(context, config, 'Author', {
88
+ take: 1,
89
+ selectedIds: ['a3'],
90
+ });
91
+ expect(result).toEqual([
92
+ { id: 'a1', label: 'Ada Lovelace' },
93
+ { id: 'a3', label: 'Grace Hopper' },
94
+ ]);
95
+ const selectedCall = primaryDelegate.findMany.mock.calls[1][0];
96
+ expect(selectedCall.where).toEqual({ id: { in: ['a3'] } });
97
+ });
98
+ it('does not re-query when the selected id is already within the primary window', async () => {
99
+ const delegate = makeDelegate([authors[0]]);
100
+ const context = makeContext({ author: delegate });
101
+ const config = makeConfig();
102
+ await getRelationshipOptions(context, config, 'Author', { selectedIds: ['a1'] });
103
+ expect(delegate.findMany).toHaveBeenCalledTimes(1);
104
+ });
105
+ it('returns [] when the related list query access is denied (findMany returns [])', async () => {
106
+ const delegate = makeDelegate([]);
107
+ const context = makeContext({ author: delegate });
108
+ const config = makeConfig();
109
+ const result = await getRelationshipOptions(context, config, 'Author', {
110
+ selectedIds: ['a1'],
111
+ });
112
+ expect(result).toEqual([]);
113
+ });
114
+ it('returns [] when the related list does not exist in config', async () => {
115
+ const context = makeContext({});
116
+ const config = makeConfig();
117
+ const result = await getRelationshipOptions(context, config, 'Missing', {});
118
+ expect(result).toEqual([]);
119
+ });
120
+ });
121
+ //# sourceMappingURL=relationship-options.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationship-options.test.js","sourceRoot":"","sources":["../../src/query/relationship-options.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAA;AAIlE,SAAS,YAAY,CAAC,IAAoC;IACxD,OAAO;QACL,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,KAAe,EAAE,EAAE,CAAC,IAAI,CAAC;QAChD,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,KAAe,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;KAC7D,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAClB,SAA0D;IAE1D,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,CAAA;AAC1B,CAAC;AAED,MAAM,OAAO,GAAG;IACd,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE;IAClC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE;IACjC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE;CACnC,CAAA;AAED,SAAS,UAAU;IACjB,OAAO;QACL,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,gBAAgB,EAAE;QACjD,KAAK,EAAE;YACL,MAAM,EAAE;gBACN,MAAM,EAAE;oBACN,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;iBACvB;gBACD,MAAM,EAAE,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;aAC7C;YACD,YAAY,EAAE;gBACZ,MAAM,EAAE;oBACN,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;iBAC1B;gBACD,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE;gBAC1B,MAAM,EAAE,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE;aAC7C;SACF;KAC2B,CAAA;AAChC,CAAC;AAED,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;QACzF,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;QACtC,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;QACjD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;QAE3B,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAA;QAE1E,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE;YACnC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;YAClC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE;SACpC,CAAC,CAAA;QAEF,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAA4B,CAAA;QAC1E,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,CAAA;IACtC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAClD,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;QACjD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;QAE3B,MAAM,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;QAEpE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IACtF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oFAAoF,EAAE,KAAK,IAAI,EAAE;QAClG,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC3C,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;QACjD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;QAE3B,MAAM,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;QAE1E,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CAC5C,MAAM,CAAC,gBAAgB,CAAC;YACtB,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;YACpC,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;SACzB,CAAC,CACH,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,MAAM,IAAI,GAAG,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;QACpC,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;QACnC,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;QAE3B,MAAM,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;QAE9E,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAA4B,CAAA;QAC1E,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAA;QAClC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;QACzF,+EAA+E;QAC/E,MAAM,eAAe,GAAG,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAClD,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;QACxD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;QAE3B,4EAA4E;QAC5E,8BAA8B;QAC9B,eAAe,CAAC,QAAQ,CAAC,sBAAsB,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACzE,eAAe,CAAC,QAAQ,CAAC,sBAAsB,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAEzE,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;YACrE,IAAI,EAAE,CAAC;YACP,WAAW,EAAE,CAAC,IAAI,CAAC;SACpB,CAAC,CAAA;QAEF,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE;YACnC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE;SACpC,CAAC,CAAA;QAEF,MAAM,YAAY,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAA4B,CAAA;QACzF,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;IAC5D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;QAC3F,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC3C,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;QACjD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;QAE3B,MAAM,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAEhF,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;IACpD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+EAA+E,EAAE,KAAK,IAAI,EAAE;QAC7F,MAAM,QAAQ,GAAG,YAAY,CAAC,EAAE,CAAC,CAAA;QACjC,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;QACjD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;QAE3B,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;YACrE,WAAW,EAAE,CAAC,IAAI,CAAC;SACpB,CAAC,CAAA;QAEF,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,CAAC,CAAA;QAC/B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;QAE3B,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,CAAA;QAE3E,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../src/utils/password.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,UAAU,GAAE,MAA4B,GACvC,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,eAAe,CACnC,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAMvD;AAED;;;;;;;;;;GAUG;AACH,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,MAAM;IAMzC;;;;;OAKG;IACG,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAItD;;;OAGG;IACH,QAAQ,IAAI,MAAM;IAIlB;;;OAGG;IACH,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAO1C;;;OAGG;IACH,MAAM,IAAI,MAAM;IAIhB;;;OAGG;IACH,OAAO,IAAI,MAAM;CAGlB"}
1
+ {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../src/utils/password.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,UAAU,GAAE,MAA4B,GACvC,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,eAAe,CACnC,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAMvD;AAED;;;;;;;;;;GAUG;AACH,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,MAAM,EAIxC;IAED;;;;;OAKG;IACG,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAErD;IAED;;;OAGG;IACH,QAAQ,IAAI,MAAM,CAEjB;IAED;;;OAGG;IACH,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKzC;IAED;;;OAGG;IACH,MAAM,IAAI,MAAM,CAEf;IAED;;;OAGG;IACH,OAAO,IAAI,MAAM,CAEhB;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"password.js","sourceRoot":"","sources":["../../src/utils/password.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,UAAU,CAAA;AAE7B;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,EAAE,CAAA;AAE9B;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,aAAqB,EACrB,aAAqB,mBAAmB;IAExC,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;AAC/C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,aAAqB,EACrB,cAAsB;IAEtB,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,OAAO,cAAc,KAAK,QAAQ,EAAE,CAAC;QAC5E,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9D,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,CAAC;QACH,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,cAAc,CAAC,CAAA;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,4CAA4C;QAC5C,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAA;QACnD,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAE3C,uEAAuE;IACvE,uCAAuC;IACvC,OAAO,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC/C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,OAAO,cAAc;IACI;IAA7B,YAA6B,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;QACvC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;QACpE,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CAAC,aAAqB;QACjC,OAAO,eAAe,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;IAClD,CAAC;IAED;;;OAGG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,IAAI,CAAA;IAClB,CAAC;IAED;;;OAGG;IACH,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAY;QAC/B,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC,IAAI,CAAA;QAClB,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAA;IAClB,CAAC;IAED;;;OAGG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,IAAI,CAAA;IAClB,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAA;IAClB,CAAC;CACF"}
1
+ {"version":3,"file":"password.js","sourceRoot":"","sources":["../../src/utils/password.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,UAAU,CAAA;AAE7B;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,EAAE,CAAA;AAE9B;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,aAAqB,EACrB,UAAU,GAAW,mBAAmB;IAExC,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;AAC/C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,aAAqB,EACrB,cAAsB;IAEtB,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,OAAO,cAAc,KAAK,QAAQ,EAAE,CAAC;QAC5E,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9D,OAAO,KAAK,CAAA;IACd,CAAC;IAED,IAAI,CAAC;QACH,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,cAAc,CAAC,CAAA;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,4CAA4C;QAC5C,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAA;QACnD,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAE3C,uEAAuE;IACvE,uCAAuC;IACvC,OAAO,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC/C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,OAAO,cAAc;IACI,IAAI;IAAjC,YAA6B,IAAY;oBAAZ,IAAI;QAC/B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;QACpE,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CAAC,aAAqB;QACjC,OAAO,eAAe,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;IAClD,CAAC;IAED;;;OAGG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,IAAI,CAAA;IAClB,CAAC;IAED;;;OAGG;IACH,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAY;QAC/B,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC,IAAI,CAAA;QAClB,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAA;IAClB,CAAC;IAED;;;OAGG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,IAAI,CAAA;IAClB,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAA;IAClB,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/validation/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,YAAyC,EACzC,YAAiC,QAAQ;IAEzC,MAAM,KAAK,GAAiC,EAAE,CAAA;IAE9C,KAAK,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACpE,wDAAwD;QACxD,+DAA+D;QAC/D,IACE,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC;YACpD,WAAW,CAAC,IAAI,KAAK,cAAc;YACnC,WAAW,CAAC,OAAO,EACnB,CAAC;YACD,SAAQ;QACV,CAAC;QAED,mCAAmC;QACnC,IAAI,WAAW,CAAC,YAAY,EAAE,CAAC;YAC7B,KAAK,CAAC,SAAS,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;QACnE,CAAC;aAAM,CAAC;YACN,4DAA4D;YAC5D,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAA;QACvC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,IAA6B,EAC7B,YAAyC,EACzC,YAAiC,QAAQ;IAEzC,MAAM,MAAM,GAAG,iBAAiB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;IAEzD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IAErC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC1B,CAAC;IAED,sDAAsD;IACtD,MAAM,MAAM,GAA2B,EAAE,CAAA;IACzC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACtC,MAAM,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,OAAO,CAAA;IACnC,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AACnC,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/validation/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,YAAyC,EACzC,SAAS,GAAwB,QAAQ;IAEzC,MAAM,KAAK,GAAiC,EAAE,CAAA;IAE9C,KAAK,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACpE,wDAAwD;QACxD,+DAA+D;QAC/D,IACE,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC;YACpD,WAAW,CAAC,IAAI,KAAK,cAAc;YACnC,WAAW,CAAC,OAAO,EACnB,CAAC;YACD,SAAQ;QACV,CAAC;QAED,mCAAmC;QACnC,IAAI,WAAW,CAAC,YAAY,EAAE,CAAC;YAC7B,KAAK,CAAC,SAAS,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;QACnE,CAAC;aAAM,CAAC;YACN,4DAA4D;YAC5D,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAA;QACvC,CAAC;IACH,CAAC;IAED,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACxB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,IAA6B,EAC7B,YAAyC,EACzC,SAAS,GAAwB,QAAQ;IAEzC,MAAM,MAAM,GAAG,iBAAiB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;IAEzD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IAErC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC1B,CAAC;IAED,sDAAsD;IACtD,MAAM,MAAM,GAA2B,EAAE,CAAA;IACzC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACtC,MAAM,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,OAAO,CAAA;IACnC,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AACnC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opensaas/stack-core",
3
- "version": "0.26.0",
3
+ "version": "0.27.1",
4
4
  "description": "Core stack for OpenSaas - schema definition, access control, and runtime utilities",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -57,10 +57,11 @@
57
57
  },
58
58
  "devDependencies": {
59
59
  "@prisma/client": "^7.8.0",
60
- "@types/node": "^25.9.1",
61
- "@vitest/coverage-v8": "^4.0.18",
62
- "typescript": "^5.9.3",
63
- "vitest": "^4.1.0"
60
+ "@types/node": "^26.1.1",
61
+ "@typescript/native": "npm:typescript@^7.0.2",
62
+ "@vitest/coverage-v8": "^4.1.10",
63
+ "typescript": "npm:@typescript/typescript6@^6.0.2",
64
+ "vitest": "^4.1.10"
64
65
  },
65
66
  "scripts": {
66
67
  "build": "tsc",
@@ -0,0 +1,149 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { buildIncludeWithAccessControl, mergeIncludeWithAccessControl } from './access-filter.js'
3
+ import type { OpenSaasConfig, FieldConfig } from '../config/types.js'
4
+ import type { AccessContext } from './types.js'
5
+
6
+ /**
7
+ * Regression coverage for the cyclic readable-relationship auto-include.
8
+ *
9
+ * On a relationship graph that contains a cycle (A → B → C → A) the depth-first
10
+ * auto-include used to descend the cycle on every branch to `MAX_DEPTH`, and
11
+ * `mergeIncludeWithAccessControl` re-expanded any bare-`true` leaf back into that
12
+ * same auto-include. The resulting include tree was deep/large enough to
13
+ * stack-overflow downstream processing (the RSC serializer). The fix seeds a
14
+ * cycle guard with the root list and stops the walk at cycle back-edges, so a
15
+ * relation that closes a cycle comes back FLAT (own columns only).
16
+ */
17
+
18
+ // A relationship field pointing at another list.
19
+ function rel(ref: string, many = false): FieldConfig {
20
+ return { type: 'relationship', ref, many } as unknown as FieldConfig
21
+ }
22
+
23
+ // A cyclic config: A → B → C → A (plus a scalar on each list).
24
+ function cyclicConfig(): OpenSaasConfig {
25
+ const allowQuery = () => true
26
+ return {
27
+ db: { provider: 'sqlite', url: 'file:./dev.db' },
28
+ lists: {
29
+ A: {
30
+ fields: { name: { type: 'text' } as FieldConfig, b: rel('B.a') },
31
+ access: { operation: { query: allowQuery } },
32
+ },
33
+ B: {
34
+ fields: { name: { type: 'text' } as FieldConfig, c: rel('C.b') },
35
+ access: { operation: { query: allowQuery } },
36
+ },
37
+ C: {
38
+ fields: { name: { type: 'text' } as FieldConfig, a: rel('A.c') },
39
+ access: { operation: { query: allowQuery } },
40
+ },
41
+ },
42
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- minimal config for unit test
43
+ } as any
44
+ }
45
+
46
+ function makeContext(): AccessContext {
47
+ return {
48
+ session: null,
49
+ _isSudo: false,
50
+ _resolveOutputCounter: { depth: 0 },
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- minimal context for unit test
52
+ } as any
53
+ }
54
+
55
+ // Measure the maximum nesting depth of an include tree.
56
+ function includeDepth(include: unknown): number {
57
+ if (!include || typeof include !== 'object') return 0
58
+ let max = 0
59
+ for (const value of Object.values(include as Record<string, unknown>)) {
60
+ if (value && typeof value === 'object') {
61
+ const nested = (value as { include?: unknown }).include
62
+ if (nested) max = Math.max(max, 1 + includeDepth(nested))
63
+ else max = Math.max(max, 1)
64
+ } else {
65
+ max = Math.max(max, 1)
66
+ }
67
+ }
68
+ return max
69
+ }
70
+
71
+ describe('buildIncludeWithAccessControl — cyclic graph', () => {
72
+ it('stops re-descending a relationship cycle instead of walking to MAX_DEPTH', async () => {
73
+ const config = cyclicConfig()
74
+ const include = await buildIncludeWithAccessControl(
75
+ config.lists.A.fields,
76
+ { session: null, context: makeContext() },
77
+ config,
78
+ 0,
79
+ ['A'],
80
+ )
81
+
82
+ // A → B → C, then C.a closes the cycle back to A → flat (no further nesting).
83
+ expect(include).toEqual({
84
+ b: { include: { c: { include: { a: true } } } },
85
+ })
86
+ // Three distinct lists → depth 3, not the old MAX_DEPTH=5 (which on a cycle
87
+ // could recurse A→B→C→A→B).
88
+ expect(includeDepth(include)).toBe(3)
89
+ })
90
+
91
+ it('flattens a self-referential relationship to a single level', async () => {
92
+ const allowQuery = () => true
93
+ const config = {
94
+ db: { provider: 'sqlite', url: 'file:./dev.db' },
95
+ lists: {
96
+ Category: {
97
+ fields: {
98
+ name: { type: 'text' } as FieldConfig,
99
+ parent: rel('Category.children'),
100
+ children: rel('Category.parent', true),
101
+ },
102
+ access: { operation: { query: allowQuery } },
103
+ },
104
+ },
105
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- minimal config for unit test
106
+ } as any as OpenSaasConfig
107
+
108
+ const include = await buildIncludeWithAccessControl(
109
+ config.lists.Category.fields,
110
+ { session: null, context: makeContext() },
111
+ config,
112
+ 0,
113
+ ['Category'],
114
+ )
115
+
116
+ // Both self-references come back flat — no infinite parent/children descent.
117
+ expect(include).toEqual({ parent: true, children: true })
118
+ expect(includeDepth(include)).toBe(1)
119
+ })
120
+ })
121
+
122
+ describe('mergeIncludeWithAccessControl — bare-true leaf on a cyclic graph', () => {
123
+ it('does not re-expand a bare-true leaf beyond the cycle-bounded auto-include', async () => {
124
+ const config = cyclicConfig()
125
+ const accessControlledInclude = await buildIncludeWithAccessControl(
126
+ config.lists.A.fields,
127
+ { session: null, context: makeContext() },
128
+ config,
129
+ 0,
130
+ ['A'],
131
+ )
132
+
133
+ // Caller asks for A → b with a bare-`true` leaf. The merge must keep the
134
+ // access-controlled (cycle-bounded) nested include rather than re-expanding
135
+ // the leaf into an unbounded auto-include.
136
+ const merged = mergeIncludeWithAccessControl(
137
+ { b: true },
138
+ accessControlledInclude,
139
+ config.lists.A.fields,
140
+ config,
141
+ )
142
+
143
+ expect(merged).toEqual({
144
+ b: { include: { c: { include: { a: true } } } },
145
+ })
146
+ // Still bounded to the acyclic path length.
147
+ expect(includeDepth(merged)).toBeLessThanOrEqual(3)
148
+ })
149
+ })
@@ -30,6 +30,10 @@ export async function buildIncludeWithAccessControl(
30
30
  },
31
31
  config: OpenSaasConfig,
32
32
  depth: number = 0,
33
+ // List names already on the path from the root to here. Used to detect
34
+ // relationship cycles (A → B → … → A) and stop the auto-include from
35
+ // re-descending them. Seed it with the root list name at the call site.
36
+ visitedLists: readonly string[] = [],
33
37
  ) {
34
38
  const MAX_DEPTH = 5
35
39
  if (depth >= MAX_DEPTH) {
@@ -75,16 +79,31 @@ export async function buildIncludeWithAccessControl(
75
79
  includeEntry.where = accessResult
76
80
  }
77
81
 
78
- // Recursively build nested includes
79
- const nestedInclude = await buildIncludeWithAccessControl(
80
- relatedConfig.listConfig.fields,
81
- args,
82
- config,
83
- depth + 1,
84
- )
82
+ // Cycle guard: if the related list already appears on the path from the
83
+ // root, DO NOT auto-include its relationships again. On a cyclic
84
+ // readable-relationship graph (A → B → … → A) the depth-first walk would
85
+ // otherwise re-descend the cycle on every branch, and — combined with the
86
+ // bare-`true` leaf re-expansion in `mergeIncludeWithAccessControl` — build
87
+ // an include tree deep/large enough to overflow the call stack in
88
+ // downstream processing (the RSC serializer's recursive `Map.set`). This
89
+ // extends the SF-20 (#566) fix: a bare-`true` leaf must resolve to a
90
+ // genuine single-level fetch, not a re-expansion of the full auto-include.
91
+ // The relation itself is still included (as a FLAT fetch of its own
92
+ // columns); only its onward relationships are pruned at the back-edge.
93
+ const relatedListName = relatedConfig.listName
94
+ if (!visitedLists.includes(relatedListName)) {
95
+ // Recursively build nested includes
96
+ const nestedInclude = await buildIncludeWithAccessControl(
97
+ relatedConfig.listConfig.fields,
98
+ args,
99
+ config,
100
+ depth + 1,
101
+ [...visitedLists, relatedListName],
102
+ )
85
103
 
86
- if (nestedInclude && Object.keys(nestedInclude).length > 0) {
87
- includeEntry.include = nestedInclude
104
+ if (nestedInclude && Object.keys(nestedInclude).length > 0) {
105
+ includeEntry.include = nestedInclude
106
+ }
88
107
  }
89
108
 
90
109
  // Add to include object
@@ -251,3 +270,57 @@ export function mergeIncludeWithAccessControl(
251
270
 
252
271
  return merged
253
272
  }
273
+
274
+ /**
275
+ * Remove keys that correspond to `virtual` fields from a Prisma `include`
276
+ * object, recursing into nested relationship includes using the related
277
+ * list's field configs.
278
+ *
279
+ * Virtual fields are computed in JavaScript (via `resolveOutput` in
280
+ * `field-visibility.ts`) and have no database column. Naming one in `include`
281
+ * type-checks — the generated `Include` type lists every field the config
282
+ * declares — but Prisma throws `Unknown field '<name>' for include statement`
283
+ * at runtime. This is applied as the final step on whatever `include` a read
284
+ * op ends up with (fragment-built, access-controlled merge, or sudo
285
+ * passthrough) so a virtual key never reaches the Prisma client, regardless
286
+ * of which path produced it. The virtual value is still computed
287
+ * unconditionally by `filterReadableFields`, so stripping the include key has
288
+ * no effect on whether the value appears in the result (#628).
289
+ */
290
+ export function stripVirtualFieldsFromInclude(
291
+ include: Record<string, unknown> | undefined,
292
+ fieldConfigs: Record<string, FieldConfig>,
293
+ config: OpenSaasConfig,
294
+ ): Record<string, unknown> | undefined {
295
+ if (!include) return include
296
+
297
+ const result: Record<string, unknown> = {}
298
+
299
+ for (const [key, value] of Object.entries(include)) {
300
+ const fieldConfig = fieldConfigs[key]
301
+
302
+ // Virtual fields have no database column — drop them from the include.
303
+ if (fieldConfig?.virtual) continue
304
+
305
+ const isDeclaredRelationship =
306
+ fieldConfig?.type === 'relationship' && 'ref' in fieldConfig && !!fieldConfig.ref
307
+ const entry = asEntryObject(value)
308
+
309
+ if (isDeclaredRelationship && entry?.include) {
310
+ const relatedConfig = getRelatedListConfig(fieldConfig.ref as string, config)
311
+ if (relatedConfig) {
312
+ const nestedInclude = stripVirtualFieldsFromInclude(
313
+ entry.include,
314
+ relatedConfig.listConfig.fields,
315
+ config,
316
+ )
317
+ result[key] = { ...(value as Record<string, unknown>), include: nestedInclude }
318
+ continue
319
+ }
320
+ }
321
+
322
+ result[key] = value
323
+ }
324
+
325
+ return result
326
+ }
@@ -22,6 +22,10 @@ export {
22
22
  // Canonical field-level access evaluation (shared by read and write paths).
23
23
  export { checkFieldAccess, filterWritableFields } from './field-access.js'
24
24
  // Phase 1 — Access Filter (pre-query row/relation scoping).
25
- export { buildIncludeWithAccessControl, mergeIncludeWithAccessControl } from './access-filter.js'
25
+ export {
26
+ buildIncludeWithAccessControl,
27
+ mergeIncludeWithAccessControl,
28
+ stripVirtualFieldsFromInclude,
29
+ } from './access-filter.js'
26
30
  // Phase 2 — Field Visibility (post-query field stripping + resolveOutput).
27
31
  export { filterReadableFields } from './field-visibility.js'
@@ -0,0 +1,58 @@
1
+ import type { ListConfig } from './types.js'
2
+
3
+ /**
4
+ * Resolve the field name that represents a list's rows as a single label —
5
+ * the projection half of the label seam. `getItemLabel` reads exactly the
6
+ * field this returns, so the field chosen for projection can never drift
7
+ * from the field used for rendering.
8
+ *
9
+ * Fallback order: configured `ui.labelField` → `name` → `title` → `id`
10
+ * (first field that exists on the list).
11
+ *
12
+ * @throws if `ui.labelField` is set but does not reference a declared,
13
+ * non-relationship field on the list.
14
+ */
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ListConfig must accept any TypeInfo
16
+ export function getLabelFieldName(listConfig: ListConfig<any>): string {
17
+ const configured = listConfig.ui?.labelField
18
+
19
+ if (configured !== undefined) {
20
+ const field = listConfig.fields[configured]
21
+ if (!field) {
22
+ throw new Error(
23
+ `ui.labelField "${configured}" does not reference a field declared on this list.`,
24
+ )
25
+ }
26
+ if (field.type === 'relationship') {
27
+ throw new Error(
28
+ `ui.labelField "${configured}" must reference a scalar field, not a relationship.`,
29
+ )
30
+ }
31
+ return configured
32
+ }
33
+
34
+ if ('name' in listConfig.fields) return 'name'
35
+ if ('title' in listConfig.fields) return 'title'
36
+ return 'id'
37
+ }
38
+
39
+ /**
40
+ * Resolve the display label for a single row — the render half of the label
41
+ * seam. Reads the field `getLabelFieldName` resolves, falling back to `id`
42
+ * when that field is missing from the row (e.g. stripped by field-level
43
+ * access).
44
+ */
45
+ export function getItemLabel(
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- ListConfig must accept any TypeInfo
47
+ listConfig: ListConfig<any>,
48
+ item: Record<string, unknown>,
49
+ ): string {
50
+ const fieldName = getLabelFieldName(listConfig)
51
+ const value = Object.prototype.hasOwnProperty.call(item, fieldName) ? item[fieldName] : undefined
52
+
53
+ if (value === undefined || value === null) {
54
+ return String(item.id)
55
+ }
56
+
57
+ return String(value)
58
+ }