@things-factory/shell 10.0.0-zeta.8 → 10.0.3
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/client/entries/public/home.js +1 -1
- package/client/themes/app-theme.css +8 -24
- package/client/themes/calendar-theme.css +0 -7
- package/client/themes/grist-theme.css +13 -37
- package/client/themes/layout-theme.css +3 -23
- package/client/themes/report-theme.css +0 -9
- package/client/themes/theme-base.css +30 -0
- package/client/themes/tooltip-theme.css +0 -4
- package/dist-server/bootstrap-hooks.d.ts +51 -0
- package/dist-server/bootstrap-hooks.js +39 -0
- package/dist-server/bootstrap-hooks.js.map +1 -0
- package/dist-server/index.d.ts +1 -0
- package/dist-server/index.js +1 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/initializers/database.js +4 -1
- package/dist-server/initializers/database.js.map +1 -1
- package/dist-server/migrations/1785369600000-IndexDomainOwner.d.ts +5 -0
- package/dist-server/migrations/1785369600000-IndexDomainOwner.js +49 -0
- package/dist-server/migrations/1785369600000-IndexDomainOwner.js.map +1 -0
- package/dist-server/server-dev.js +13 -10
- package/dist-server/server-dev.js.map +1 -1
- package/dist-server/server.js +12 -8
- package/dist-server/server.js.map +1 -1
- package/dist-server/service/domain/domain-mutation.js +3 -2
- package/dist-server/service/domain/domain-mutation.js.map +1 -1
- package/dist-server/service/domain/domain.js +12 -1
- package/dist-server/service/domain/domain.js.map +1 -1
- package/dist-server/service/env-var/env-var-mutation.js +6 -1
- package/dist-server/service/env-var/env-var-mutation.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/dist-server/typeorm/get-data-encryption-key.js +11 -1
- package/dist-server/typeorm/get-data-encryption-key.js.map +1 -1
- package/dist-server/utils/apply-domain-filter.d.ts +17 -0
- package/dist-server/utils/apply-domain-filter.js +30 -0
- package/dist-server/utils/apply-domain-filter.js.map +1 -0
- package/dist-server/utils/condition-builder.js +15 -7
- package/dist-server/utils/condition-builder.js.map +1 -1
- package/dist-server/utils/get-query-builder-from-list-params.d.ts +39 -9
- package/dist-server/utils/get-query-builder-from-list-params.js +83 -40
- package/dist-server/utils/get-query-builder-from-list-params.js.map +1 -1
- package/dist-server/utils/index.d.ts +1 -0
- package/dist-server/utils/index.js +1 -0
- package/dist-server/utils/index.js.map +1 -1
- package/dist-server/utils/list-params-converter.js +8 -6
- package/dist-server/utils/list-params-converter.js.map +1 -1
- package/dist-server/utils/list-query-builder.js +2 -14
- package/dist-server/utils/list-query-builder.js.map +1 -1
- package/jest.config.js +5 -0
- package/package.json +12 -12
- package/tests/domain-owner-index.test.ts +121 -0
- package/tests/env-var-tenant-isolation.test.ts +118 -0
- package/tests/get-query-builder-features.test.ts +229 -0
- package/tests/list-param-operators.test.ts +87 -0
- package/tests/manifest-contract.test.ts +38 -0
- package/client/store.ts +0 -15
|
@@ -83,7 +83,7 @@ export class HomePage extends LitElement {
|
|
|
83
83
|
var descriptionMeta = document.querySelector('meta[name="application-description"]')
|
|
84
84
|
|
|
85
85
|
this._applicationMeta = {
|
|
86
|
-
icon: iconLink ? iconLink.href :
|
|
86
|
+
icon: iconLink ? iconLink.href : undefined,
|
|
87
87
|
title: titleMeta ? titleMeta.content : 'Things Factory',
|
|
88
88
|
description: descriptionMeta ? descriptionMeta.content : 'Reimagining Software'
|
|
89
89
|
}
|
|
@@ -12,7 +12,10 @@ body {
|
|
|
12
12
|
|
|
13
13
|
/* common style */
|
|
14
14
|
--border-radius: 4px;
|
|
15
|
-
|
|
15
|
+
/* 라이트/다크 모두 대비되는 캐럿 — 별도 .dark override 불필요 */
|
|
16
|
+
caret-color: var(--md-sys-color-on-surface);
|
|
17
|
+
|
|
18
|
+
--border-dim-color: 1px solid var(--md-sys-color-outline-variant);
|
|
16
19
|
--border-light-color: 1px solid rgba(255, 255, 255, 0.3);
|
|
17
20
|
|
|
18
21
|
--box-shadow: 2px 2px 3px 0px rgba(0, 0, 0, 0.1);
|
|
@@ -40,7 +43,6 @@ body {
|
|
|
40
43
|
--title-margin: var(--margin-narrow) 0;
|
|
41
44
|
--title-font: bold 24px var(--theme-font);
|
|
42
45
|
--title-text-color: var(--md-sys-color-secondary);
|
|
43
|
-
--title-font-mobile: bold 20px var(--theme-font);
|
|
44
46
|
|
|
45
47
|
--page-description-margin: var(--margin-narrow) 0 var(--margin-wide) 0;
|
|
46
48
|
--page-description-font: normal var(--fontsize-default) / 1.2rem var(--theme-font);
|
|
@@ -54,19 +56,9 @@ body {
|
|
|
54
56
|
/* icon style */
|
|
55
57
|
--icon-tiny-size: var(--icon-size-medium, 24px);
|
|
56
58
|
--icon-default-size: var(--icon-size-large, 32px);
|
|
57
|
-
--icon-big-size: var(--icon-size-huge, 48px);
|
|
58
|
-
--icon-default-color: var(--md-sys-color-on-primary);
|
|
59
59
|
|
|
60
60
|
/* material design component themes */
|
|
61
|
-
--mdc-theme-on-primary: var(--md-sys-color-on-primary);
|
|
62
|
-
--mdc-theme-primary: var(--secondary-text-color);
|
|
63
|
-
--mdc-theme-on-secondary: var(--md-sys-color-on-primary);
|
|
64
|
-
--mdc-theme-secondary: var(--md-sys-color-primary);
|
|
65
|
-
--mdc-button-outline-color: var(--md-sys-color-primary);
|
|
66
61
|
--mdc-danger-button-primary-color: var(--status-danger-color);
|
|
67
|
-
--mdc-danger-button-outline-color: var(--status-danger-color);
|
|
68
|
-
--mdc-button-outline-width: 1px;
|
|
69
|
-
--mdc-button-horizontal-padding: 16px;
|
|
70
62
|
|
|
71
63
|
/* button style */
|
|
72
64
|
--button-background-color: var(--md-sys-color-surface-variant);
|
|
@@ -81,8 +73,6 @@ body {
|
|
|
81
73
|
--button-active-box-shadow: 1px 1px 1px 0px rgba(0, 0, 0, 0.2);
|
|
82
74
|
--button-activ-border: 1px solid var(--md-sys-color-primary);
|
|
83
75
|
--button-activ-background-color: var(--md-sys-color-primary);
|
|
84
|
-
--button-activ-color: var(--md-sys-color-on-primary);
|
|
85
|
-
--iconbtn-padding: var(--padding-narrow);
|
|
86
76
|
|
|
87
77
|
--button-primary-background-color: var(--md-sys-color-primary);
|
|
88
78
|
--button-primary-active-background-color: var(--status-success-color);
|
|
@@ -99,9 +89,9 @@ body {
|
|
|
99
89
|
|
|
100
90
|
--tr-background-color: var(--md-sys-color-surface-variant);
|
|
101
91
|
--tr-background-odd-color: rgba(255, 255, 255, 0.4);
|
|
102
|
-
--tr-background-hover-color:
|
|
103
|
-
--td-border-line: 1px solid
|
|
104
|
-
--td-border-bottom: 1px solid
|
|
92
|
+
--tr-background-hover-color: var(--md-sys-color-secondary-container);
|
|
93
|
+
--td-border-line: 1px solid var(--md-sys-color-outline-variant);
|
|
94
|
+
--td-border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
|
105
95
|
--td-padding: var(--padding-default);
|
|
106
96
|
--td-font: normal 13px var(--theme-font);
|
|
107
97
|
--td-color: var(--md-sys-color-secondary);
|
|
@@ -114,10 +104,9 @@ body {
|
|
|
114
104
|
--label-text-transform: capitalize;
|
|
115
105
|
--input-margin: var(--margin-narrow) 0;
|
|
116
106
|
--input-padding: 6px 2px;
|
|
117
|
-
--input-min-width: 200px;
|
|
118
107
|
--input-font: normal var(--fontsize-default) var(--theme-font);
|
|
119
108
|
--input-hint-font: normal var(--fontsize-small) var(--theme-font);
|
|
120
|
-
--input-hint-color:
|
|
109
|
+
--input-hint-color: var(--md-sys-color-on-surface-variant);
|
|
121
110
|
--input-container-max-width: 900px;
|
|
122
111
|
--fieldset-margin: var(--padding-wide) 0;
|
|
123
112
|
--fieldset-padding: 0 var(--padding-wide) var(--padding-wide) var(--padding-wide);
|
|
@@ -126,12 +115,7 @@ body {
|
|
|
126
115
|
--legend-font: bold 16px var(--theme-font);
|
|
127
116
|
}
|
|
128
117
|
|
|
129
|
-
body.dark {
|
|
130
|
-
caret-color: white;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
118
|
html {
|
|
134
|
-
--scene-theme-font-family: 'Roboto', Helvetica;
|
|
135
119
|
}
|
|
136
120
|
|
|
137
121
|
@media only screen and (max-width: 460px) {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
body {
|
|
2
|
-
--ox-calendar-padding: var(--padding-default);
|
|
3
2
|
|
|
4
3
|
/* monthly common color */
|
|
5
|
-
--calendar-monthly-text-color: var(--md-sys-color-secondary);
|
|
6
4
|
--calendar-monthly-border: 1px solid rgba(0, 0, 0, 0.1);
|
|
7
5
|
--calendar-monthly-border-width: 0 1px 1px 0px;
|
|
8
6
|
|
|
@@ -13,7 +11,6 @@ body {
|
|
|
13
11
|
--calendar-current-month-color: var(--md-sys-color-on-surface);
|
|
14
12
|
--calendar-monthly-label-align: left;
|
|
15
13
|
--calendar-monthly-label-padding: var(--padding-narrow) 0;
|
|
16
|
-
--calendar-monthly-label-color: var(--md-sys-color-secondary);
|
|
17
14
|
--calendar-monthly-opacity: 0.5;
|
|
18
15
|
--calendar-monthly-date-label-background-color: var(--status-danger-color);
|
|
19
16
|
--calendar-monthly-date-label-margin: var(--margin-narrow);
|
|
@@ -21,7 +18,6 @@ body {
|
|
|
21
18
|
--calendar-monthly-date-label-color: var(--md-sys-color-on-primary);
|
|
22
19
|
|
|
23
20
|
--calendar-monthly-background-color: #f4f4f4;
|
|
24
|
-
--calendar-monthly-event-border-radius: var(--border-radius);
|
|
25
21
|
--calendar-monthly-event-margin: var(--padding-narrow) 0 0 0;
|
|
26
22
|
--calendar-monthly-event-padding: 2px var(--padding-default);
|
|
27
23
|
--calendar-monthly-event-border: 3px solid #ccc;
|
|
@@ -39,7 +35,6 @@ body {
|
|
|
39
35
|
--calendar-current-week-color: var(--md-sys-color-on-surface);
|
|
40
36
|
--calendar-weekly-label-align: center;
|
|
41
37
|
--calendar-weekly-label-padding: var(--padding-narrow) 0;
|
|
42
|
-
--calendar-weekly-label-color: var(--md-sys-color-secondary);
|
|
43
38
|
--calendar-weekly-opacity: 0.5;
|
|
44
39
|
--calendar-weekly-date-label-background-color: var(--status-danger-color);
|
|
45
40
|
--calendar-weekly-date-label-margin: var(--margin-narrow);
|
|
@@ -47,7 +42,6 @@ body {
|
|
|
47
42
|
--calendar-weekly-date-label-color: var(--md-sys-color-on-primary);
|
|
48
43
|
|
|
49
44
|
--calendar-weekly-background-color: #f4f4f4;
|
|
50
|
-
--calendar-weekly-event-border-radius: var(--border-radius);
|
|
51
45
|
--calendar-weekly-event-margin: var(--padding-narrow) 0 0 0;
|
|
52
46
|
--calendar-weekly-event-padding: 2px var(--padding-default);
|
|
53
47
|
--calendar-weekly-event-border: 3px solid #ccc;
|
|
@@ -56,6 +50,5 @@ body {
|
|
|
56
50
|
|
|
57
51
|
@media only screen and (max-width: 460px) {
|
|
58
52
|
body {
|
|
59
|
-
--calendar-monthly-text-color: tomato;
|
|
60
53
|
}
|
|
61
54
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
body {
|
|
2
|
-
|
|
2
|
+
/* 토큰 파생 — 라이트/다크가 자동 정합되므로 별도 .dark override 불필요 */
|
|
3
|
+
--grid-container-border-color: 1px solid var(--md-sys-color-outline-variant);
|
|
3
4
|
--grid-container-border-width: 1px 0;
|
|
4
5
|
--grid-wrap-container-border: 0px solid transparent;
|
|
5
6
|
--grid-wrap-container-border-width: 0;
|
|
@@ -9,7 +10,6 @@ body {
|
|
|
9
10
|
--grist-title-border: none;
|
|
10
11
|
--grist-title-font: var(--md-sys-typescale-label-large-weight, var(--md-ref-typeface-weight-medium, 500)) 1.1em
|
|
11
12
|
var(--theme-font, 'Roboto');
|
|
12
|
-
--grist-title-color: var(--md-sys-color-on-surface);
|
|
13
13
|
--grist-title-icon-color: var(--md-sys-color-on-surface-variant);
|
|
14
14
|
--grist-title-icon-margin: 0 3px 2px 0;
|
|
15
15
|
--grist-title-icon-size: var(--md-sys-typescale-label-large-size, 0.875rem);
|
|
@@ -18,15 +18,14 @@ body {
|
|
|
18
18
|
--grist-object-editor-font: normal 1em var(--theme-font, 'Roboto');
|
|
19
19
|
--grist-object-editor-color: var(--md-sys-color-on-surface);
|
|
20
20
|
|
|
21
|
-
--grist-input-progress-border: 1px solid
|
|
22
|
-
--grist-input-progress-background:
|
|
23
|
-
--grist-input-progress-bar-background: var(--md-sys-color-primary-
|
|
21
|
+
--grist-input-progress-border: 1px solid var(--md-sys-color-outline-variant);
|
|
22
|
+
--grist-input-progress-background: var(--md-sys-color-surface-container-high);
|
|
23
|
+
--grist-input-progress-bar-background: var(--md-sys-color-primary-container);
|
|
24
24
|
--grist-input-progress-bar-color: var(--md-sys-color-on-surface-variant);
|
|
25
25
|
|
|
26
26
|
--grid-header-background-color: var(--md-sys-color-surface-container-low);
|
|
27
27
|
--grid-header-top-border: 2px solid var(--md-sys-color-primary);
|
|
28
28
|
--grid-header-bottom-border: var(--grid-container-border-color);
|
|
29
|
-
--grid-header-border-color: var(--md-sys-color-outline);
|
|
30
29
|
--grid-header-padding: var(--spacing-small) var(--spacing-tiny);
|
|
31
30
|
--grid-header-sorter-size: 18px;
|
|
32
31
|
--grid-header-splitter-border: var(--grid-container-border-color);
|
|
@@ -46,16 +45,14 @@ body {
|
|
|
46
45
|
--grid-record-odd-background-color: var(--md-sys-color-surface-container-low);
|
|
47
46
|
--grid-record-padding: var(--spacing-small) var(--spacing-medium);
|
|
48
47
|
--grid-record-color: var(--md-sys-color-on-surface-variant);
|
|
49
|
-
--grid-record-color-hover: var(--md-sys-color-primary);
|
|
50
48
|
--grid-record-wide-fontsize: var(--md-sys-typescale-label-large-size, 0.875rem);
|
|
51
49
|
--grid-record-selected-background-color: var(--md-sys-color-primary-container);
|
|
52
50
|
--grid-record-selected-color: var(--md-sys-color-on-primary-container);
|
|
53
|
-
--grid-record-focused-border: 1px solid var(--md-sys-color-outline-variant);
|
|
54
|
-
--grid-record-focused-cell-background-color: var(--md-sys-color-secondary-container);
|
|
55
51
|
--grid-record-focused-cell-border: 1px dashed var(--md-sys-color-outline);
|
|
56
52
|
--grid-record-focused-box-shadow: 0px 2px 0px 0px rgb(0 0 0 / 10%);
|
|
57
|
-
|
|
58
|
-
--grid-record-emphasized-color: var(--md-sys-color-
|
|
53
|
+
/* -fixed 는 라이트/다크 동일(고정)이라 다크에서 잔존 → 적응형 -container 짝으로 */
|
|
54
|
+
--grid-record-emphasized-background-color: var(--md-sys-color-secondary-container);
|
|
55
|
+
--grid-record-emphasized-color: var(--md-sys-color-on-secondary-container);
|
|
59
56
|
--grid-record-editing-background-color: var(--md-sys-color-inverse-primary);
|
|
60
57
|
--grid-record-editing-border: 1px dashed rgba(var(--md-sys-color-primary-rgb), 0.4);
|
|
61
58
|
--grid-record-fontsize: var(--md-sys-typescale-label-large-size, 0.875rem);
|
|
@@ -70,13 +67,11 @@ body {
|
|
|
70
67
|
--grid-footer-background-color: var(--md-sys-color-surface-container-low);
|
|
71
68
|
--grid-footer-font-size: var(--md-sys-typescale-label-large-size, 0.875rem);
|
|
72
69
|
--grid-footer-color: var(--md-sys-color-primary);
|
|
73
|
-
--grid-footer-limit-color: var(--md-
|
|
74
|
-
--grid-footer-inactive-color: var(--md-
|
|
70
|
+
--grid-footer-limit-color: var(--md-sys-color-on-surface-variant);
|
|
71
|
+
--grid-footer-inactive-color: var(--md-sys-color-on-surface-variant);
|
|
75
72
|
--grid-footer-padding: var(--spacing-small) var(--spacing-medium);
|
|
76
73
|
|
|
77
74
|
--data-list-background-color: var(--md-sys-color-surface-container-lowest);
|
|
78
|
-
--data-list-item-margin: var(--spacing-medium);
|
|
79
|
-
--data-list-item-padding: var(--spacing-medium) var(--spacing-large);
|
|
80
75
|
--data-list-item-border-bottom: var(--grid-container-border-color);
|
|
81
76
|
--data-list-item-name-font: bold 1.1em var(--theme-font, 'Roboto');
|
|
82
77
|
--data-list-item-name-color: var(--md-sys-color-secondary);
|
|
@@ -84,47 +79,34 @@ body {
|
|
|
84
79
|
--data-list-item-disc-color: var(--md-sys-color-on-tertiary-container);
|
|
85
80
|
--data-list-item-etc-label-font: bold 1em/1em var(--theme-font, 'Roboto');
|
|
86
81
|
--data-list-item-etc-font: normal 0.9em/1em var(--theme-font, 'Roboto');
|
|
87
|
-
--data-list-item-etc-color: var(--md-
|
|
88
|
-
--data-list-item-icon-font: normal 1em/1em;
|
|
89
|
-
--data-list-item-icon-color: var(--md-sys-color-on-secondary);
|
|
82
|
+
--data-list-item-etc-color: var(--md-sys-color-on-surface-variant);
|
|
90
83
|
--data-list-selected-background-color: var(--grid-record-selected-background-color);
|
|
91
84
|
--data-list-fab-position-horizontal: 15px;
|
|
92
85
|
--data-list-fab-position-vertical: 15px;
|
|
93
86
|
--data-list-fab-color: var(--md-sys-color-primary);
|
|
94
87
|
--data-list-fab-shadow: var(--box-shadow);
|
|
95
88
|
|
|
96
|
-
--data-card-background-color: var(--md-sys-color-surface-container);
|
|
97
89
|
--data-card-record-card-background-color: var(--md-sys-color-surface-container-lowest);
|
|
98
90
|
--data-card-record-card-border: var(--grid-container-border-color);
|
|
99
91
|
--data-card-record-card-border-hover: 1px solid var(--md-sys-color-primary);
|
|
100
92
|
--data-card-record-card-boxshadow-hover: 1px 1px 2px 1px rgba(0, 0, 0, 0.15);
|
|
101
|
-
--data-card-record-card-selected-border: 1px solid var(--md-sys-color-primary);
|
|
102
93
|
--data-card-record-card-border-radius: var(--md-sys-shape-corner-medium);
|
|
103
94
|
--data-card-item-margin: var(--spacing-medium);
|
|
104
|
-
--data-card-item-padding: var(--spacing-medium) var(--spacing-large);
|
|
105
|
-
--data-card-item-border-bottom: var(--grid-container-border-color);
|
|
106
95
|
--data-card-item-name-font: bold 1.1em var(--theme-font, 'Roboto');
|
|
107
96
|
--data-card-item-name-color: var(--md-sys-color-secondary);
|
|
108
|
-
--data-card-item-name-label-font: normal 0.65em/0.8em var(--theme-font, 'Roboto');
|
|
109
|
-
--data-card-item-name-label-color: var(--md-sys-color-secondary);
|
|
110
97
|
--data-card-item-disc-font: normal 0.9em var(--theme-font, 'Roboto');
|
|
111
98
|
--data-card-item-disc-color: var(--md-sys-color-tertiary);
|
|
112
99
|
--data-card-item-etc-label-font: normal 1em/1em var(--theme-font, 'Roboto');
|
|
113
100
|
--data-card-item-etc-font: normal 0.9em/1em var(--theme-font, 'Roboto');
|
|
114
|
-
--data-card-item-etc-color: var(--md-
|
|
115
|
-
--data-card-item-icon-font: normal 1em/1em;
|
|
116
|
-
--data-card-item-icon-color: var(--md-sys-color-on-secondary);
|
|
101
|
+
--data-card-item-etc-color: var(--md-sys-color-on-surface-variant);
|
|
117
102
|
--data-card-item-btn-border: var(--grid-container-border-color);
|
|
118
103
|
--data-card-item-btn-border-radius: var(--md-sys-shape-corner-small);
|
|
119
104
|
--data-card-item-btn-padding: var(--spacing-small);
|
|
120
|
-
--data-card-selected-background-color: var(--grid-record-selected-background-color);
|
|
121
105
|
--data-card-fab-position-horizontal: 15px;
|
|
122
106
|
--data-card-fab-position-vertical: 15px;
|
|
123
107
|
--data-card-fab-color: var(--md-sys-color-primary);
|
|
124
108
|
--data-card-fab-shadow: var(--box-shadow);
|
|
125
109
|
--data-card-thumbnail-height: 140px;
|
|
126
|
-
--data-card-thumbnail-border-bottom: var(--grid-container-border-color);
|
|
127
|
-
--data-card-attachimg-height: 70px;
|
|
128
110
|
|
|
129
111
|
--record-view-background-color: var(--md-sys-color-surface-container);
|
|
130
112
|
--record-view-gap: var(--spacing-small) 0;
|
|
@@ -140,12 +122,10 @@ body {
|
|
|
140
122
|
--record-view-edit-border-bottom: 2px solid var(--md-sys-color-primary);
|
|
141
123
|
--record-view-item-padding: var(--spacing-medium);
|
|
142
124
|
|
|
143
|
-
--record-view-footer-background: var(--md-
|
|
125
|
+
--record-view-footer-background: var(--md-sys-color-on-surface-variant);
|
|
144
126
|
--record-view-footer-button-border: var(--grid-container-border-color);
|
|
145
127
|
--record-view-footer-button-border-width: 0 0 0 1px;
|
|
146
|
-
--record-view-footer-button-font: 17px;
|
|
147
128
|
--record-view-footer-button-color: var(--md-sys-color-surface);
|
|
148
|
-
--record-view-footer-iconbutton-size: 35px;
|
|
149
129
|
--record-view-footer-focus-background: var(--md-sys-color-primary);
|
|
150
130
|
|
|
151
131
|
--ox-grist-padding: var(--spacing-medium);
|
|
@@ -166,10 +146,6 @@ body {
|
|
|
166
146
|
}
|
|
167
147
|
@media (min-width: 461px) and (max-width: 1024px) {
|
|
168
148
|
body {
|
|
169
|
-
--data-card-create-form-padding: 7px;
|
|
170
149
|
}
|
|
171
150
|
}
|
|
172
151
|
|
|
173
|
-
body.dark {
|
|
174
|
-
--grid-container-border-color: 1px solid rgba(255, 255, 255, 0.09);
|
|
175
|
-
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
body {
|
|
2
2
|
--header-bar-background-color: var(--md-sys-color-primary);
|
|
3
|
-
--header-bar-icon-size: var(--icon-default-size);
|
|
4
3
|
--header-bar-title: bold 17.5px var(--theme-font);
|
|
5
4
|
--header-bar-color: var(--md-sys-color-on-primary);
|
|
6
5
|
--header-bar-height: 42px;
|
|
@@ -11,18 +10,7 @@ body {
|
|
|
11
10
|
--group-bar-textbutton: 16px/32px var(--theme-font);
|
|
12
11
|
--group-bar-textbutton-active: bold var(--group-bar-textbutton);
|
|
13
12
|
--group-bar-active-line-color: var(--md-sys-color-on-secondary-container);
|
|
14
|
-
--group-bar-line: solid 3px
|
|
15
|
-
|
|
16
|
-
--footer-bar-border-top: 1px solid rgba(0, 0, 0, 0.2);
|
|
17
|
-
|
|
18
|
-
--aside-background-color: var(--md-sys-color-secondary-container);
|
|
19
|
-
--aside-list-textbtton: 18px var(--theme-font);
|
|
20
|
-
--aside-list-icon: var(--icon-default-size);
|
|
21
|
-
--aside-list-bottom-line: var(--md-sys-color-outline);
|
|
22
|
-
--aside-list-detail-background-color: #fff;
|
|
23
|
-
--aside-list-detail-text: 14px var(--md-sys-color-on-secondary-container);
|
|
24
|
-
|
|
25
|
-
--footer-bar-border-top: 1px solid rgba(0, 0, 0, 0.2);
|
|
13
|
+
--group-bar-line: solid 3px var(--md-sys-color-outline);
|
|
26
14
|
|
|
27
15
|
--button-container-margin: inintial;
|
|
28
16
|
--button-container-padding: 0 var(--padding-default) var(--padding-wide) var(--padding-default);
|
|
@@ -32,8 +20,6 @@ body {
|
|
|
32
20
|
--button-container-button-background-color: var(--md-sys-color-secondary);
|
|
33
21
|
--button-container-button-border-radius: var(--button-border-radius);
|
|
34
22
|
--button-container-button-margin: var(--button-margin);
|
|
35
|
-
--button-container-button-font: bold var(--fontsize-large) var(--theme-font);
|
|
36
|
-
--button-container-button-color: var(--md-sys-color-on-primary);
|
|
37
23
|
--button-container-button-height: initial;
|
|
38
24
|
--button-container-button-border: var(--button-border);
|
|
39
25
|
|
|
@@ -48,16 +34,10 @@ body {
|
|
|
48
34
|
--overlay-center-normal-height: 50%;
|
|
49
35
|
--overlay-center-large-width: 75%;
|
|
50
36
|
--overlay-center-large-height: 75%;
|
|
51
|
-
--overlay-header-height: var(--header-bar-height);
|
|
52
|
-
--overlay-header-background-color: var(--header-bar-background-color);
|
|
53
|
-
--overlay-header-color: #fff;
|
|
54
|
-
--overlay-header-font: var(--header-bar-title);
|
|
55
|
-
--overlay-background-color: rgba(0, 0, 0, 0.5);
|
|
56
|
-
--overlay-margin-bottom: 0px;
|
|
57
37
|
|
|
58
38
|
/* components - resize splitter style */
|
|
59
|
-
--splitter-background-color:
|
|
60
|
-
--splitter-hover-background-color:
|
|
39
|
+
--splitter-background-color: var(--md-sys-color-surface-variant);
|
|
40
|
+
--splitter-hover-background-color: var(--md-sys-color-surface-variant);
|
|
61
41
|
}
|
|
62
42
|
|
|
63
43
|
@media only screen and (max-width: 460px) {
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
body {
|
|
2
2
|
--report-background-color: var(--md-sys-color-background);
|
|
3
3
|
--report-padding: 15px;
|
|
4
|
-
--report-title-margin: 0 0 0 10px;
|
|
5
|
-
--report-title-border: none;
|
|
6
|
-
--report-title-color: var(--md-sys-color-secondary);
|
|
7
|
-
--report-title-icon-color: var(--md-sys-color-primary);
|
|
8
|
-
--report-title-icon-margin: 0 3px 2px 0;
|
|
9
|
-
--report-title-icon-size: 14px;
|
|
10
|
-
--report-title-with-grid-padding: 0;
|
|
11
4
|
--report-component-border-radius: var(--border-radius);
|
|
12
5
|
|
|
13
6
|
--report-header-background-color: var(--md-sys-color-surface);
|
|
14
|
-
--report-header-border: 1px solid var(--report-header-border-color);
|
|
15
7
|
--report-header-border-color: var(--md-sys-color-outline);
|
|
16
8
|
--report-header-padding: 5px 0 5px 5px;
|
|
17
9
|
--report-header-color: var(--secondary-text-color);
|
|
@@ -19,7 +11,6 @@ body {
|
|
|
19
11
|
--report-header-fontsize: 13px;
|
|
20
12
|
|
|
21
13
|
--report-record-background-color: #fff;
|
|
22
|
-
--report-record-odd-background-color: #f6f6f6;
|
|
23
14
|
--report-record-field-padding: 7px 10px;
|
|
24
15
|
--report-record-field-border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
|
25
16
|
--report-record-wide-fontsize: 13px;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* theme-base — 모든 앱이 공유하는 테마 기반 규칙.
|
|
3
|
+
*
|
|
4
|
+
* [왜 이 파일이 따로 있는가]
|
|
5
|
+
* builder 의 ThemeOverridePlugin 은 테마를 **파일명 단위로 완전 대체**한다(병합이 아님).
|
|
6
|
+
* 즉 앱이 `themes/light.css` 를 가지면 shell 의 `light.css` 는 빌드에서 제외된다.
|
|
7
|
+
* 그래서 공통 규칙을 light/dark 에 넣으면 앱마다 복제해야 하고, 누락이 필연적이다.
|
|
8
|
+
* (실제로 `color-scheme` 이 6개 앱에서 누락되어 있었다.)
|
|
9
|
+
*
|
|
10
|
+
* `theme-base.css` 는 **어떤 앱도 같은 이름으로 override 하지 않는 파일**이므로 항상 번들에 포함된다.
|
|
11
|
+
* → 공통 불변 규칙은 여기 한 곳에만 두면 전 앱에 적용된다.
|
|
12
|
+
*
|
|
13
|
+
* [넣는 것] 브랜드와 무관하게 항상 성립해야 하는 규칙(테마 스킴, 공통 접근성 기본값 등)
|
|
14
|
+
* [넣지 않는 것] 브랜드 색값 — 그것은 각 앱의 `light.css` / `dark.css` 소관(49개 md-sys 슬롯)
|
|
15
|
+
*
|
|
16
|
+
* 참고: v10/UI-PILOT-THEME-CONSISTENCY.md §3.5
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
* UA 네이티브 표면(스크롤바·폼 컨트롤·초기 배경)을 앱 테마와 일치시킨다.
|
|
21
|
+
* 선언이 없으면 다크 테마에서 native input/textarea/select·스크롤바가 밝은 OS 크롬으로 렌더된다.
|
|
22
|
+
* 색값이 아니라 스킴 선언이므로 브랜드 팔레트와 무관하게 공통 적용 가능하다.
|
|
23
|
+
*/
|
|
24
|
+
.light {
|
|
25
|
+
color-scheme: light;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.dark {
|
|
29
|
+
color-scheme: dark;
|
|
30
|
+
}
|
|
@@ -3,9 +3,5 @@ body {
|
|
|
3
3
|
--tooltip-background-color: rgba(0, 0, 0, 0.7);
|
|
4
4
|
--tooltip-font: bold 11px var(--theme-font);
|
|
5
5
|
/*
|
|
6
|
-
--tooltip-left-positon-left: auto;
|
|
7
|
-
--tooltip-left-position-top: 7px;
|
|
8
|
-
--tooltip-left-position-right: 110%;
|
|
9
|
-
--tooltip-left-position-animation: tooltip-left 0.3s ease-out 0s 1 normal;
|
|
10
6
|
*/
|
|
11
7
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Koa from 'koa';
|
|
2
|
+
import Router from 'koa-router';
|
|
3
|
+
/**
|
|
4
|
+
* 부트스트랩 훅 레지스트리 (P1: 타입드 모듈 매니페스트 — 3단계).
|
|
5
|
+
*
|
|
6
|
+
* shell 은 부트스트랩 과정에서 `process` EventEmitter 로 일련의 라이프사이클 이벤트를 emit 하고,
|
|
7
|
+
* 각 모듈은 이를 listen 해 라우터/미들웨어/구독을 등록한다. 이 파일은 그 문자열 이벤트명과
|
|
8
|
+
* 페이로드를 한곳에서 타입으로 고정한다.
|
|
9
|
+
*
|
|
10
|
+
* 원칙(하위호환):
|
|
11
|
+
* - 내부는 여전히 동일한 `process.emit/on` 을 사용한다 → 기존 136개 모듈의
|
|
12
|
+
* `process.on('bootstrap-module-*', ...)` 는 그대로 동작한다(무변경).
|
|
13
|
+
* - shell 의 emit 측을 `emitHook` 으로 전환해 이벤트명 오타·페이로드 시그니처를 컴파일 체크한다.
|
|
14
|
+
* - 모듈은 원하면 `onHook` 으로 자발적 전환 가능(강제 아님).
|
|
15
|
+
*/
|
|
16
|
+
/** 부트스트랩 훅 이름 상수 (오타 방지용 단일 소스). */
|
|
17
|
+
export declare const BOOTSTRAP_HOOKS: {
|
|
18
|
+
readonly moduleSubscription: "bootstrap-module-subscription";
|
|
19
|
+
readonly collectSsoMiddleware: "bootstrap-collect-sso-middleware";
|
|
20
|
+
readonly globalPublicRoute: "bootstrap-module-global-public-route";
|
|
21
|
+
readonly globalPrivateRoute: "bootstrap-module-global-private-route";
|
|
22
|
+
readonly domainPublicRoute: "bootstrap-module-domain-public-route";
|
|
23
|
+
readonly domainPrivateRoute: "bootstrap-module-domain-private-route";
|
|
24
|
+
readonly moduleStart: "bootstrap-module-start";
|
|
25
|
+
readonly clientRebuilt: "client-rebuilt";
|
|
26
|
+
};
|
|
27
|
+
/** module-start 훅 페이로드. */
|
|
28
|
+
export interface BootstrapModuleStartPayload {
|
|
29
|
+
app: Koa;
|
|
30
|
+
config: any;
|
|
31
|
+
builtSchema: any;
|
|
32
|
+
httpServer: any;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 훅 이벤트명 → emit/on 인자 튜플 매핑.
|
|
36
|
+
* (동적 수집 지점인 middleware/collection 인자는 any 로 둔다.)
|
|
37
|
+
*/
|
|
38
|
+
export interface BootstrapHookArgs {
|
|
39
|
+
'bootstrap-module-subscription': [app: Koa, subscriptionMiddleware: any];
|
|
40
|
+
'bootstrap-collect-sso-middleware': [value: null, ssoMiddlewares: any[]];
|
|
41
|
+
'bootstrap-module-global-public-route': [app: Koa, router: Router];
|
|
42
|
+
'bootstrap-module-global-private-route': [app: Koa, router: Router];
|
|
43
|
+
'bootstrap-module-domain-public-route': [app: Koa, router: Router];
|
|
44
|
+
'bootstrap-module-domain-private-route': [app: Koa, router: Router];
|
|
45
|
+
'bootstrap-module-start': [payload: BootstrapModuleStartPayload];
|
|
46
|
+
'client-rebuilt': [app: Koa, outputFileSystem: any];
|
|
47
|
+
}
|
|
48
|
+
/** 부트스트랩 훅을 타입 안전하게 emit 한다(내부적으로 process.emit). */
|
|
49
|
+
export declare function emitHook<K extends keyof BootstrapHookArgs>(name: K, ...args: BootstrapHookArgs[K]): void;
|
|
50
|
+
/** 부트스트랩 훅을 타입 안전하게 구독한다(내부적으로 process.on). 기존 process.on 과 병존. */
|
|
51
|
+
export declare function onHook<K extends keyof BootstrapHookArgs>(name: K, handler: (...args: BootstrapHookArgs[K]) => void): void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BOOTSTRAP_HOOKS = void 0;
|
|
4
|
+
exports.emitHook = emitHook;
|
|
5
|
+
exports.onHook = onHook;
|
|
6
|
+
/**
|
|
7
|
+
* 부트스트랩 훅 레지스트리 (P1: 타입드 모듈 매니페스트 — 3단계).
|
|
8
|
+
*
|
|
9
|
+
* shell 은 부트스트랩 과정에서 `process` EventEmitter 로 일련의 라이프사이클 이벤트를 emit 하고,
|
|
10
|
+
* 각 모듈은 이를 listen 해 라우터/미들웨어/구독을 등록한다. 이 파일은 그 문자열 이벤트명과
|
|
11
|
+
* 페이로드를 한곳에서 타입으로 고정한다.
|
|
12
|
+
*
|
|
13
|
+
* 원칙(하위호환):
|
|
14
|
+
* - 내부는 여전히 동일한 `process.emit/on` 을 사용한다 → 기존 136개 모듈의
|
|
15
|
+
* `process.on('bootstrap-module-*', ...)` 는 그대로 동작한다(무변경).
|
|
16
|
+
* - shell 의 emit 측을 `emitHook` 으로 전환해 이벤트명 오타·페이로드 시그니처를 컴파일 체크한다.
|
|
17
|
+
* - 모듈은 원하면 `onHook` 으로 자발적 전환 가능(강제 아님).
|
|
18
|
+
*/
|
|
19
|
+
/** 부트스트랩 훅 이름 상수 (오타 방지용 단일 소스). */
|
|
20
|
+
exports.BOOTSTRAP_HOOKS = {
|
|
21
|
+
moduleSubscription: 'bootstrap-module-subscription',
|
|
22
|
+
collectSsoMiddleware: 'bootstrap-collect-sso-middleware',
|
|
23
|
+
globalPublicRoute: 'bootstrap-module-global-public-route',
|
|
24
|
+
globalPrivateRoute: 'bootstrap-module-global-private-route',
|
|
25
|
+
domainPublicRoute: 'bootstrap-module-domain-public-route',
|
|
26
|
+
domainPrivateRoute: 'bootstrap-module-domain-private-route',
|
|
27
|
+
moduleStart: 'bootstrap-module-start',
|
|
28
|
+
clientRebuilt: 'client-rebuilt'
|
|
29
|
+
};
|
|
30
|
+
/** 부트스트랩 훅을 타입 안전하게 emit 한다(내부적으로 process.emit). */
|
|
31
|
+
function emitHook(name, ...args) {
|
|
32
|
+
;
|
|
33
|
+
process.emit(name, ...args);
|
|
34
|
+
}
|
|
35
|
+
/** 부트스트랩 훅을 타입 안전하게 구독한다(내부적으로 process.on). 기존 process.on 과 병존. */
|
|
36
|
+
function onHook(name, handler) {
|
|
37
|
+
process.on(name, handler);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=bootstrap-hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap-hooks.js","sourceRoot":"","sources":["../server/bootstrap-hooks.ts"],"names":[],"mappings":";;;AAqDA,4BAEC;AAGD,wBAKC;AA5DD;;;;;;;;;;;;GAYG;AAEH,oCAAoC;AACvB,QAAA,eAAe,GAAG;IAC7B,kBAAkB,EAAE,+BAA+B;IACnD,oBAAoB,EAAE,kCAAkC;IACxD,iBAAiB,EAAE,sCAAsC;IACzD,kBAAkB,EAAE,uCAAuC;IAC3D,iBAAiB,EAAE,sCAAsC;IACzD,kBAAkB,EAAE,uCAAuC;IAC3D,WAAW,EAAE,wBAAwB;IACrC,aAAa,EAAE,gBAAgB;CACvB,CAAA;AAyBV,oDAAoD;AACpD,SAAgB,QAAQ,CAAoC,IAAO,EAAE,GAAG,IAA0B;IAChG,CAAC;IAAC,OAAe,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAA;AACvC,CAAC;AAED,mEAAmE;AACnE,SAAgB,MAAM,CACpB,IAAO,EACP,OAAgD;IAEhD,OAAO,CAAC,EAAE,CAAC,IAAW,EAAE,OAAc,CAAC,CAAA;AACzC,CAAC","sourcesContent":["import Koa from 'koa'\nimport Router from 'koa-router'\n\n/**\n * 부트스트랩 훅 레지스트리 (P1: 타입드 모듈 매니페스트 — 3단계).\n *\n * shell 은 부트스트랩 과정에서 `process` EventEmitter 로 일련의 라이프사이클 이벤트를 emit 하고,\n * 각 모듈은 이를 listen 해 라우터/미들웨어/구독을 등록한다. 이 파일은 그 문자열 이벤트명과\n * 페이로드를 한곳에서 타입으로 고정한다.\n *\n * 원칙(하위호환):\n * - 내부는 여전히 동일한 `process.emit/on` 을 사용한다 → 기존 136개 모듈의\n * `process.on('bootstrap-module-*', ...)` 는 그대로 동작한다(무변경).\n * - shell 의 emit 측을 `emitHook` 으로 전환해 이벤트명 오타·페이로드 시그니처를 컴파일 체크한다.\n * - 모듈은 원하면 `onHook` 으로 자발적 전환 가능(강제 아님).\n */\n\n/** 부트스트랩 훅 이름 상수 (오타 방지용 단일 소스). */\nexport const BOOTSTRAP_HOOKS = {\n moduleSubscription: 'bootstrap-module-subscription',\n collectSsoMiddleware: 'bootstrap-collect-sso-middleware',\n globalPublicRoute: 'bootstrap-module-global-public-route',\n globalPrivateRoute: 'bootstrap-module-global-private-route',\n domainPublicRoute: 'bootstrap-module-domain-public-route',\n domainPrivateRoute: 'bootstrap-module-domain-private-route',\n moduleStart: 'bootstrap-module-start',\n clientRebuilt: 'client-rebuilt'\n} as const\n\n/** module-start 훅 페이로드. */\nexport interface BootstrapModuleStartPayload {\n app: Koa\n config: any\n builtSchema: any\n httpServer: any\n}\n\n/**\n * 훅 이벤트명 → emit/on 인자 튜플 매핑.\n * (동적 수집 지점인 middleware/collection 인자는 any 로 둔다.)\n */\nexport interface BootstrapHookArgs {\n 'bootstrap-module-subscription': [app: Koa, subscriptionMiddleware: any]\n 'bootstrap-collect-sso-middleware': [value: null, ssoMiddlewares: any[]]\n 'bootstrap-module-global-public-route': [app: Koa, router: Router]\n 'bootstrap-module-global-private-route': [app: Koa, router: Router]\n 'bootstrap-module-domain-public-route': [app: Koa, router: Router]\n 'bootstrap-module-domain-private-route': [app: Koa, router: Router]\n 'bootstrap-module-start': [payload: BootstrapModuleStartPayload]\n 'client-rebuilt': [app: Koa, outputFileSystem: any]\n}\n\n/** 부트스트랩 훅을 타입 안전하게 emit 한다(내부적으로 process.emit). */\nexport function emitHook<K extends keyof BootstrapHookArgs>(name: K, ...args: BootstrapHookArgs[K]): void {\n ;(process as any).emit(name, ...args)\n}\n\n/** 부트스트랩 훅을 타입 안전하게 구독한다(내부적으로 process.on). 기존 process.on 과 병존. */\nexport function onHook<K extends keyof BootstrapHookArgs>(\n name: K,\n handler: (...args: BootstrapHookArgs[K]) => void\n): void {\n process.on(name as any, handler as any)\n}\n"]}
|
package/dist-server/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export * from './utils/index.js';
|
|
|
5
5
|
export * from './pubsub.js';
|
|
6
6
|
export * from './pubsub-log-transport.js';
|
|
7
7
|
export * from './middlewares/index.js';
|
|
8
|
+
export * from './bootstrap-hooks.js';
|
|
8
9
|
export * from './graphql-local-client.js';
|
|
9
10
|
export * from './service/index.js';
|
|
10
11
|
export * from './typeorm/encrypt-transform.js';
|
package/dist-server/index.js
CHANGED
|
@@ -8,6 +8,7 @@ tslib_1.__exportStar(require("./utils/index.js"), exports);
|
|
|
8
8
|
tslib_1.__exportStar(require("./pubsub.js"), exports);
|
|
9
9
|
tslib_1.__exportStar(require("./pubsub-log-transport.js"), exports);
|
|
10
10
|
tslib_1.__exportStar(require("./middlewares/index.js"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./bootstrap-hooks.js"), exports);
|
|
11
12
|
tslib_1.__exportStar(require("./graphql-local-client.js"), exports);
|
|
12
13
|
tslib_1.__exportStar(require("./service/index.js"), exports);
|
|
13
14
|
tslib_1.__exportStar(require("./typeorm/encrypt-transform.js"), exports);
|
package/dist-server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;AAAA,gEAAqC;AACrC,4EAAiD;AACjD,qEAA0C;AAC1C,2DAAgC;AAChC,sDAA2B;AAC3B,oEAAyC;AACzC,iEAAsC;AACtC,oEAAyC;AACzC,6DAAkC;AAElC,yEAA8C;AAC9C,8EAAmD;AACnD,uEAA4C;AAC5C,uEAA4C","sourcesContent":["export * from './migrations/index.js'\nexport * from './initializers/naming-strategy.js'\nexport * from './initializers/database.js'\nexport * from './utils/index.js'\nexport * from './pubsub.js'\nexport * from './pubsub-log-transport.js'\nexport * from './middlewares/index.js'\nexport * from './graphql-local-client.js'\nexport * from './service/index.js'\n\nexport * from './typeorm/encrypt-transform.js'\nexport * from './typeorm/encrypt-json-transform.js'\nexport * from './typeorm/json5-transform.js'\nexport * from './typeorm/round-transform.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;AAAA,gEAAqC;AACrC,4EAAiD;AACjD,qEAA0C;AAC1C,2DAAgC;AAChC,sDAA2B;AAC3B,oEAAyC;AACzC,iEAAsC;AACtC,+DAAoC;AACpC,oEAAyC;AACzC,6DAAkC;AAElC,yEAA8C;AAC9C,8EAAmD;AACnD,uEAA4C;AAC5C,uEAA4C","sourcesContent":["export * from './migrations/index.js'\nexport * from './initializers/naming-strategy.js'\nexport * from './initializers/database.js'\nexport * from './utils/index.js'\nexport * from './pubsub.js'\nexport * from './pubsub-log-transport.js'\nexport * from './middlewares/index.js'\nexport * from './bootstrap-hooks.js'\nexport * from './graphql-local-client.js'\nexport * from './service/index.js'\n\nexport * from './typeorm/encrypt-transform.js'\nexport * from './typeorm/encrypt-json-transform.js'\nexport * from './typeorm/json5-transform.js'\nexport * from './typeorm/round-transform.js'\n"]}
|
|
@@ -80,7 +80,10 @@ const databaseInitializer = async () => {
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
catch (e) {
|
|
83
|
-
|
|
83
|
+
/* DB 는 필수 인프라 — 초기화 실패를 삼키면 'default' DataSource 없이 부팅되어
|
|
84
|
+
이후 모든 요청이 런타임에 터진다(좀비 부팅). 실패를 전파해 즉시 중단(fail-fast)한다. */
|
|
85
|
+
env_1.logger.error('Failed to initialize database', e);
|
|
86
|
+
throw e;
|
|
84
87
|
}
|
|
85
88
|
};
|
|
86
89
|
exports.databaseInitializer = databaseInitializer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../server/initializers/database.ts"],"names":[],"mappings":";;;AAYA,sCAEC;AAOD,sCAEC;AAMD,4CAEC;AAMD,gDAEC;AAOD,sCAEC;;AAhDD,qCAA+F;AAE/F,6CAAoD;AACpD,0EAAsC;AAEtC,MAAM,WAAW,GAAmC,EAAE,CAAA;AAEtD;;;;GAIG;AACH,SAAgB,aAAa,CAAC,IAAa;IACzC,OAAO,WAAW,CAAC,IAAI,IAAI,SAAS,CAAC,CAAA;AACvC,CAAC;AAED;;;;GAIG;AACH,SAAgB,aAAa,CAAC,IAAY,EAAE,UAAsB;IAChE,WAAW,CAAC,IAAI,CAAC,GAAG,UAAU,CAAA;AAChC,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,IAAY;IAC3C,OAAO,WAAW,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC;AAED;;;GAGG;AACH,SAAgB,kBAAkB;IAChC,OAAO,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;AACjC,CAAC;AAED;;;;GAIG;AACH,SAAgB,aAAa,CAAI,MAAuB,EAAE,EAAkB;IAC1E,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAI,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,aAAa,CAAI,MAAM,CAAC,CAAA;AAC7F,CAAC;AAED;;GAEG;AACI,MAAM,mBAAmB,GAAG,KAAK,IAAI,EAAE;IAC5C,IAAI,CAAC;QACH,MAAM,oBAAoB,GAAG,YAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QAEpD,MAAM,UAAU,GAAG,MAAM,IAAA,0BAAgB,EAAC;YACxC,GAAG,sBAAS;YACZ,GAAG,oBAAoB;SACxB,CAAC,CAAA;QAEF,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpC,YAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAA;QAE7C,IAAI,oBAAoB,CAAC,IAAI,IAAI,QAAQ,IAAI,oBAAoB,CAAC,WAAW,IAAI,KAAK,EAAE,CAAC;YACvF,MAAM,UAAU,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAA;YACjD,MAAM,UAAU,CAAC,WAAW,EAAE,CAAA;YAC9B,MAAM,UAAU,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;QAClD,CAAC;QAED,IAAI,YAAM,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;YAC/B,MAAM,aAAa,GAAG,IAAI,oBAAU,CAAC;gBACnC,GAAG,sBAAS;gBACZ,GAAG,YAAM,CAAC,GAAG,CAAC,cAAc,CAAC;aAC9B,CAAC,CAAA;YACF,MAAM,aAAa,CAAC,UAAU,EAAE,CAAA;YAChC,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;YAElC,YAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAA;QACnD,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,YAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../server/initializers/database.ts"],"names":[],"mappings":";;;AAYA,sCAEC;AAOD,sCAEC;AAMD,4CAEC;AAMD,gDAEC;AAOD,sCAEC;;AAhDD,qCAA+F;AAE/F,6CAAoD;AACpD,0EAAsC;AAEtC,MAAM,WAAW,GAAmC,EAAE,CAAA;AAEtD;;;;GAIG;AACH,SAAgB,aAAa,CAAC,IAAa;IACzC,OAAO,WAAW,CAAC,IAAI,IAAI,SAAS,CAAC,CAAA;AACvC,CAAC;AAED;;;;GAIG;AACH,SAAgB,aAAa,CAAC,IAAY,EAAE,UAAsB;IAChE,WAAW,CAAC,IAAI,CAAC,GAAG,UAAU,CAAA;AAChC,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,IAAY;IAC3C,OAAO,WAAW,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC;AAED;;;GAGG;AACH,SAAgB,kBAAkB;IAChC,OAAO,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;AACjC,CAAC;AAED;;;;GAIG;AACH,SAAgB,aAAa,CAAI,MAAuB,EAAE,EAAkB;IAC1E,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAI,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,aAAa,CAAI,MAAM,CAAC,CAAA;AAC7F,CAAC;AAED;;GAEG;AACI,MAAM,mBAAmB,GAAG,KAAK,IAAI,EAAE;IAC5C,IAAI,CAAC;QACH,MAAM,oBAAoB,GAAG,YAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QAEpD,MAAM,UAAU,GAAG,MAAM,IAAA,0BAAgB,EAAC;YACxC,GAAG,sBAAS;YACZ,GAAG,oBAAoB;SACxB,CAAC,CAAA;QAEF,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpC,YAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAA;QAE7C,IAAI,oBAAoB,CAAC,IAAI,IAAI,QAAQ,IAAI,oBAAoB,CAAC,WAAW,IAAI,KAAK,EAAE,CAAC;YACvF,MAAM,UAAU,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAA;YACjD,MAAM,UAAU,CAAC,WAAW,EAAE,CAAA;YAC9B,MAAM,UAAU,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;QAClD,CAAC;QAED,IAAI,YAAM,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;YAC/B,MAAM,aAAa,GAAG,IAAI,oBAAU,CAAC;gBACnC,GAAG,sBAAS;gBACZ,GAAG,YAAM,CAAC,GAAG,CAAC,cAAc,CAAC;aAC9B,CAAC,CAAA;YACF,MAAM,aAAa,CAAC,UAAU,EAAE,CAAA;YAChC,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,CAAA;YAElC,YAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAA;QACnD,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX;oEAC4D;QAC5D,YAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE,CAAC,CAAC,CAAA;QAChD,MAAM,CAAC,CAAA;IACT,CAAC;AACH,CAAC,CAAA;AArCY,QAAA,mBAAmB,uBAqC/B","sourcesContent":["import { createConnection, DataSource, EntityManager, EntityTarget, Repository } from 'typeorm'\n\nimport { config, logger } from '@things-factory/env'\nimport ormconfig from './ormconfig.js'\n\nconst dataSources: { [name: string]: DataSource } = {}\n\n/**\n * Returns the specified DataSource by name.\n * @param {string} name - The name of the DataSource.\n * @returns {DataSource} - The DataSource with the specified name.\n */\nexport function getDataSource(name?: string): DataSource {\n return dataSources[name || 'default']\n}\n\n/**\n * Adds a new DataSource with the specified name.\n * @param {string} name - The name of the DataSource to add.\n * @param {DataSource} dataSource - The DataSource to add.\n */\nexport function addDataSource(name: string, dataSource: DataSource) {\n dataSources[name] = dataSource\n}\n\n/**\n * Removes a DataSource with the specified name.\n * @param {string} name - The name of the DataSource to remove.\n */\nexport function removeDataSource(name: string) {\n delete dataSources[name]\n}\n\n/**\n * Returns an array of all registered DataSource names.\n * @returns {string[]} - An array of DataSource names.\n */\nexport function getDataSourceNames() {\n return Object.keys(dataSources)\n}\n\n/**\n * Returns a repository for the specified entity.\n * @param {EntityTarget<X>} target - The target entity for which to get the repository.\n * @returns {Repository<X>} - The repository for the specified entity.\n */\nexport function getRepository<X>(target: EntityTarget<X>, tx?: EntityManager): Repository<X> {\n return tx ? tx.getRepository<X>(target) : getDataSource('default').getRepository<X>(target)\n}\n\n/**\n * Initializes the database connections and data sources.\n */\nexport const databaseInitializer = async () => {\n try {\n const readConnectionConfig = config.get('ormconfig')\n\n const dataSource = await createConnection({\n ...ormconfig,\n ...readConnectionConfig\n })\n\n addDataSource('default', dataSource)\n\n logger.info('Default DataSource established')\n\n if (readConnectionConfig.type == 'sqlite' && readConnectionConfig.synchronize == false) {\n await dataSource.query('PRAGMA foreign_keys=OFF')\n await dataSource.synchronize()\n await dataSource.query('PRAGMA foreign_keys=ON')\n }\n\n if (config.get('ormconfig4Tx')) {\n const dataSource4Tx = new DataSource({\n ...ormconfig,\n ...config.get('ormconfig4Tx')\n })\n await dataSource4Tx.initialize()\n addDataSource('tx', dataSource4Tx)\n\n logger.info('Transaction DataSource established')\n } else {\n addDataSource('tx', dataSource)\n }\n } catch (e) {\n /* DB 는 필수 인프라 — 초기화 실패를 삼키면 'default' DataSource 없이 부팅되어\n 이후 모든 요청이 런타임에 터진다(좀비 부팅). 실패를 전파해 즉시 중단(fail-fast)한다. */\n logger.error('Failed to initialize database', e)\n throw e\n }\n}\n"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IndexDomainOwner1785369600000 = void 0;
|
|
4
|
+
const typeorm_1 = require("typeorm");
|
|
5
|
+
/**
|
|
6
|
+
* `domains.owner` 에 인덱스를 추가한다.
|
|
7
|
+
*
|
|
8
|
+
* 소유권으로 도메인을 찾는 조회(`owner = :userId`)가 인덱스 없이는 도메인 테이블을 훑는다.
|
|
9
|
+
* 체크인 가능 도메인 목록 계산이 이 조건을 쓰므로, 테넌트가 늘어나면 로그인 경로 비용이
|
|
10
|
+
* 도메인 수에 비례해 증가한다.
|
|
11
|
+
*
|
|
12
|
+
* - non-unique 다. 한 사용자가 여러 도메인을 소유할 수 있고 값이 비어 있을 수도 있으므로
|
|
13
|
+
* unique 로 만들면 기존 데이터에서 실패한다.
|
|
14
|
+
* - 데이터는 변경하지 않는다 (인덱스는 제약이 아니다). 되돌리기는 인덱스 삭제뿐이다.
|
|
15
|
+
* - idempotent — 같은 이름의 인덱스가 이미 있으면(엔티티 선언 + synchronize 로 생성된 경우 등)
|
|
16
|
+
* 아무것도 하지 않는다.
|
|
17
|
+
* - `TableIndex` API 만 사용하므로 지원 대상 드라이버가 각자의 DDL 로 생성한다.
|
|
18
|
+
*/
|
|
19
|
+
const TABLE_NAME = 'domains';
|
|
20
|
+
const INDEX_NAME = 'ix_domain_1';
|
|
21
|
+
const COLUMN_NAMES = ['owner'];
|
|
22
|
+
class IndexDomainOwner1785369600000 {
|
|
23
|
+
async up(queryRunner) {
|
|
24
|
+
const table = await queryRunner.getTable(TABLE_NAME);
|
|
25
|
+
if (!table) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (table.indices.some(index => index.name === INDEX_NAME)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
await queryRunner.createIndex(table, new typeorm_1.TableIndex({
|
|
32
|
+
name: INDEX_NAME,
|
|
33
|
+
columnNames: COLUMN_NAMES,
|
|
34
|
+
isUnique: false
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
async down(queryRunner) {
|
|
38
|
+
const table = await queryRunner.getTable(TABLE_NAME);
|
|
39
|
+
if (!table) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (!table.indices.some(index => index.name === INDEX_NAME)) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
await queryRunner.dropIndex(table, INDEX_NAME);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.IndexDomainOwner1785369600000 = IndexDomainOwner1785369600000;
|
|
49
|
+
//# sourceMappingURL=1785369600000-IndexDomainOwner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"1785369600000-IndexDomainOwner.js","sourceRoot":"","sources":["../../server/migrations/1785369600000-IndexDomainOwner.ts"],"names":[],"mappings":";;;AAAA,qCAAqE;AAErE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,GAAG,SAAS,CAAA;AAC5B,MAAM,UAAU,GAAG,aAAa,CAAA;AAChC,MAAM,YAAY,GAAG,CAAC,OAAO,CAAC,CAAA;AAE9B,MAAa,6BAA6B;IACjC,KAAK,CAAC,EAAE,CAAC,WAAwB;QACtC,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;QACpD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAM;QACR,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC,EAAE,CAAC;YAC3D,OAAM;QACR,CAAC;QAED,MAAM,WAAW,CAAC,WAAW,CAC3B,KAAK,EACL,IAAI,oBAAU,CAAC;YACb,IAAI,EAAE,UAAU;YAChB,WAAW,EAAE,YAAY;YACzB,QAAQ,EAAE,KAAK;SAChB,CAAC,CACH,CAAA;IACH,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,WAAwB;QACxC,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;QACpD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAM;QACR,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC,EAAE,CAAC;YAC5D,OAAM;QACR,CAAC;QAED,MAAM,WAAW,CAAC,SAAS,CAAC,KAAK,EAAE,UAAU,CAAC,CAAA;IAChD,CAAC;CACF;AAjCD,sEAiCC","sourcesContent":["import { MigrationInterface, QueryRunner, TableIndex } from 'typeorm'\n\n/**\n * `domains.owner` 에 인덱스를 추가한다.\n *\n * 소유권으로 도메인을 찾는 조회(`owner = :userId`)가 인덱스 없이는 도메인 테이블을 훑는다.\n * 체크인 가능 도메인 목록 계산이 이 조건을 쓰므로, 테넌트가 늘어나면 로그인 경로 비용이\n * 도메인 수에 비례해 증가한다.\n *\n * - non-unique 다. 한 사용자가 여러 도메인을 소유할 수 있고 값이 비어 있을 수도 있으므로\n * unique 로 만들면 기존 데이터에서 실패한다.\n * - 데이터는 변경하지 않는다 (인덱스는 제약이 아니다). 되돌리기는 인덱스 삭제뿐이다.\n * - idempotent — 같은 이름의 인덱스가 이미 있으면(엔티티 선언 + synchronize 로 생성된 경우 등)\n * 아무것도 하지 않는다.\n * - `TableIndex` API 만 사용하므로 지원 대상 드라이버가 각자의 DDL 로 생성한다.\n */\nconst TABLE_NAME = 'domains'\nconst INDEX_NAME = 'ix_domain_1'\nconst COLUMN_NAMES = ['owner']\n\nexport class IndexDomainOwner1785369600000 implements MigrationInterface {\n public async up(queryRunner: QueryRunner): Promise<void> {\n const table = await queryRunner.getTable(TABLE_NAME)\n if (!table) {\n return\n }\n\n if (table.indices.some(index => index.name === INDEX_NAME)) {\n return\n }\n\n await queryRunner.createIndex(\n table,\n new TableIndex({\n name: INDEX_NAME,\n columnNames: COLUMN_NAMES,\n isUnique: false\n })\n )\n }\n\n public async down(queryRunner: QueryRunner): Promise<void> {\n const table = await queryRunner.getTable(TABLE_NAME)\n if (!table) {\n return\n }\n\n if (!table.indices.some(index => index.name === INDEX_NAME)) {\n return\n }\n\n await queryRunner.dropIndex(table, INDEX_NAME)\n }\n}\n"]}
|