@molecule/app-bonds-default-react 1.0.0
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/LICENSE +115 -0
- package/dist/auth.d.ts +91 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +147 -0
- package/dist/bootstrap.d.ts +33 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +47 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +74 -0
- package/dist/setup.d.ts +72 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +179 -0
- package/package.json +149 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work.
|
|
38
|
+
|
|
39
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
40
|
+
form, that is based on (or derived from) the Work and for which the
|
|
41
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
42
|
+
represent, as a whole, an original work of authorship.
|
|
43
|
+
|
|
44
|
+
"Contribution" shall mean any work of authorship, including the
|
|
45
|
+
original version of the Work and any modifications or additions
|
|
46
|
+
to that Work, that is intentionally submitted to the Licensor for
|
|
47
|
+
inclusion in the Work by the copyright owner or by an individual or
|
|
48
|
+
Legal Entity authorized to submit on behalf of the copyright owner.
|
|
49
|
+
|
|
50
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
51
|
+
on behalf of whom a Contribution has been received by the Licensor and
|
|
52
|
+
subsequently incorporated within the Work.
|
|
53
|
+
|
|
54
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
55
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
56
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
57
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
58
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
59
|
+
Work and such Derivative Works in Source or Object form.
|
|
60
|
+
|
|
61
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
62
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
63
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
64
|
+
patent license to make, have made, use, offer to sell, sell, import,
|
|
65
|
+
and otherwise transfer the Work.
|
|
66
|
+
|
|
67
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
68
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
69
|
+
modifications, and in Source or Object form, provided that You
|
|
70
|
+
meet the following conditions:
|
|
71
|
+
|
|
72
|
+
(a) You must give any other recipients of the Work or
|
|
73
|
+
Derivative Works a copy of this License; and
|
|
74
|
+
|
|
75
|
+
(b) You must cause any modified files to carry prominent notices
|
|
76
|
+
stating that You changed the files; and
|
|
77
|
+
|
|
78
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
79
|
+
that You distribute, all copyright, patent, trademark, and
|
|
80
|
+
attribution notices from the Source form of the Work,
|
|
81
|
+
excluding those notices that do not pertain to any part of
|
|
82
|
+
the Derivative Works; and
|
|
83
|
+
|
|
84
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
85
|
+
distribution, then any Derivative Works that You distribute must
|
|
86
|
+
include a readable copy of the attribution notices contained
|
|
87
|
+
within such NOTICE file.
|
|
88
|
+
|
|
89
|
+
5. Submission of Contributions.
|
|
90
|
+
|
|
91
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
92
|
+
names, trademarks, service marks, or product names of the Licensor.
|
|
93
|
+
|
|
94
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
95
|
+
agreed to in writing, Licensor provides the Work on an "AS IS" BASIS,
|
|
96
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND.
|
|
97
|
+
|
|
98
|
+
8. Limitation of Liability. In no event and under no legal theory shall
|
|
99
|
+
any Contributor be liable to You for damages.
|
|
100
|
+
|
|
101
|
+
9. Accepting Warranty or Additional Liability.
|
|
102
|
+
|
|
103
|
+
Copyright 2026 Molecule Dev, Inc.
|
|
104
|
+
|
|
105
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
106
|
+
you may not use this file except in compliance with the License.
|
|
107
|
+
You may obtain a copy of the License at
|
|
108
|
+
|
|
109
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
110
|
+
|
|
111
|
+
Unless required by applicable law or agreed to in writing, software
|
|
112
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
113
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
114
|
+
See the License for the specific language governing permissions and
|
|
115
|
+
limitations under the License.
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { AuthClient, AuthClientConfig, UserProfile } from '@molecule/app-auth';
|
|
2
|
+
import type { HttpClient } from '@molecule/app-http';
|
|
3
|
+
/**
|
|
4
|
+
* Builds the default fetch-based HTTP client + wires it into
|
|
5
|
+
* `@molecule/app-http`. Replaces the per-app `bonds/http-default.ts`
|
|
6
|
+
* shipped by ~52 fleet apps.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* // bonds/http-default.ts
|
|
11
|
+
* import { createDefaultHttpClient } from '@molecule/app-bonds-default-react'
|
|
12
|
+
* import { API_BASE_URL } from '../config.js'
|
|
13
|
+
*
|
|
14
|
+
* export const { httpClient, setupHttpDefault } = createDefaultHttpClient(API_BASE_URL)
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function createDefaultHttpClient(baseURL: string): {
|
|
18
|
+
httpClient: HttpClient;
|
|
19
|
+
setupHttpDefault: () => void;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Variant of `createDefaultHttpClient` that adds a request interceptor
|
|
23
|
+
* injecting the JWT bearer token from the auth client AND (optionally)
|
|
24
|
+
* stripping a leading `/api/` from request URLs.
|
|
25
|
+
*
|
|
26
|
+
* Replaces ~20 per-app `bonds/http-default.ts` files that hand-roll
|
|
27
|
+
* this same wiring. Pass `stripApiPrefix: true` when the app uses
|
|
28
|
+
* `baseURL: '/api'` to handle pages that pass `/api/`-prefixed paths
|
|
29
|
+
* (would otherwise resolve to `/api/api/...` and 404).
|
|
30
|
+
*/
|
|
31
|
+
export declare function createDefaultHttpClientWithAuthBearer(opts: {
|
|
32
|
+
baseURL: string;
|
|
33
|
+
withCredentials?: boolean;
|
|
34
|
+
stripApiPrefix?: boolean;
|
|
35
|
+
getToken: () => string | null | undefined;
|
|
36
|
+
}): {
|
|
37
|
+
httpClient: HttpClient;
|
|
38
|
+
setupHttpDefault: () => void;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Builds the default JWT auth client + wires it into `@molecule/app-auth`.
|
|
42
|
+
*
|
|
43
|
+
* Replaces the 16-line per-app `bonds/auth-default.ts` that 93 fleet
|
|
44
|
+
* apps shipped byte-identically. Apps pass their own `authConfig`
|
|
45
|
+
* (which lives in `src/config.ts`).
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* // bonds/auth-default.ts
|
|
50
|
+
* import { createDefaultAuthClient } from '@molecule/app-bonds-default-react'
|
|
51
|
+
* import { authConfig } from '../config.js'
|
|
52
|
+
*
|
|
53
|
+
* export const { authClient, setupAuthDefault } =
|
|
54
|
+
* createDefaultAuthClient(authConfig)
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function createDefaultAuthClient<TUser extends UserProfile = UserProfile>(authConfig: AuthClientConfig): {
|
|
58
|
+
authClient: AuthClient<TUser>;
|
|
59
|
+
setupAuthDefault: () => void;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Variant of `createDefaultAuthClient` that also keeps the bonded
|
|
63
|
+
* `@molecule/app-http` client's bearer token in sync with auth events
|
|
64
|
+
* (login / register / refresh / logout). Required by apps whose http
|
|
65
|
+
* client must carry the JWT on every request — without this wiring,
|
|
66
|
+
* authed endpoints return 401 after page reloads or token refresh.
|
|
67
|
+
*
|
|
68
|
+
* Hydrates the HTTP client's token from the persisted auth state
|
|
69
|
+
* on setup, then listens for auth events to keep them aligned.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createDefaultAuthClientWithHttpSync<TUser extends UserProfile = UserProfile>(authConfig: AuthClientConfig): {
|
|
72
|
+
authClient: AuthClient<TUser>;
|
|
73
|
+
setupAuthDefault: () => void;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Most aggressive variant — bonds a fetch-based HTTP client with the
|
|
77
|
+
* given `baseURL` (so molecule pkg `useGet('/path')` calls hit
|
|
78
|
+
* `${baseURL}/path` instead of the SPA's catch-all route), AND keeps
|
|
79
|
+
* its bearer token in sync with auth events.
|
|
80
|
+
*
|
|
81
|
+
* Used by apps where molecule packages render pricing / billing /
|
|
82
|
+
* other authed JSON-fetching screens that need both behaviors.
|
|
83
|
+
*/
|
|
84
|
+
export declare function createDefaultAuthClientWithFetchClient<TUser extends UserProfile = UserProfile>(authConfig: AuthClientConfig, fetchClientOptions: {
|
|
85
|
+
baseURL: string;
|
|
86
|
+
withCredentials?: boolean;
|
|
87
|
+
}): {
|
|
88
|
+
authClient: AuthClient<TUser>;
|
|
89
|
+
setupAuthDefault: () => void;
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAOpD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG;IACxD,UAAU,EAAE,UAAU,CAAA;IACtB,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CAMA;AAED;;;;;;;;;GASG;AACH,wBAAgB,qCAAqC,CAAC,IAAI,EAAE;IAC1D,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,QAAQ,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAC1C,GAAG;IACF,UAAU,EAAE,UAAU,CAAA;IACtB,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CAmBA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW,EAC7E,UAAU,EAAE,gBAAgB,GAC3B;IACD,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,CAAA;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CAMA;AAED;;;;;;;;;GASG;AACH,wBAAgB,mCAAmC,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW,EACzF,UAAU,EAAE,gBAAgB,GAC3B;IACD,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,CAAA;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CAoBA;AAED;;;;;;;;GAQG;AACH,wBAAgB,sCAAsC,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW,EAC5F,UAAU,EAAE,gBAAgB,EAC5B,kBAAkB,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GACjE;IACD,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,CAAA;IAC7B,gBAAgB,EAAE,MAAM,IAAI,CAAA;CAC7B,CAyBA"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { createJWTAuthClient, setClient } from '@molecule/app-auth';
|
|
2
|
+
import { createFetchClient, getClient as getHttpClient, setClient as setHttpClient, } from '@molecule/app-http';
|
|
3
|
+
/**
|
|
4
|
+
* Builds the default fetch-based HTTP client + wires it into
|
|
5
|
+
* `@molecule/app-http`. Replaces the per-app `bonds/http-default.ts`
|
|
6
|
+
* shipped by ~52 fleet apps.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* // bonds/http-default.ts
|
|
11
|
+
* import { createDefaultHttpClient } from '@molecule/app-bonds-default-react'
|
|
12
|
+
* import { API_BASE_URL } from '../config.js'
|
|
13
|
+
*
|
|
14
|
+
* export const { httpClient, setupHttpDefault } = createDefaultHttpClient(API_BASE_URL)
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export function createDefaultHttpClient(baseURL) {
|
|
18
|
+
const httpClient = createFetchClient({ baseURL });
|
|
19
|
+
return {
|
|
20
|
+
httpClient,
|
|
21
|
+
setupHttpDefault: () => setHttpClient(httpClient),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Variant of `createDefaultHttpClient` that adds a request interceptor
|
|
26
|
+
* injecting the JWT bearer token from the auth client AND (optionally)
|
|
27
|
+
* stripping a leading `/api/` from request URLs.
|
|
28
|
+
*
|
|
29
|
+
* Replaces ~20 per-app `bonds/http-default.ts` files that hand-roll
|
|
30
|
+
* this same wiring. Pass `stripApiPrefix: true` when the app uses
|
|
31
|
+
* `baseURL: '/api'` to handle pages that pass `/api/`-prefixed paths
|
|
32
|
+
* (would otherwise resolve to `/api/api/...` and 404).
|
|
33
|
+
*/
|
|
34
|
+
export function createDefaultHttpClientWithAuthBearer(opts) {
|
|
35
|
+
const httpClient = createFetchClient({
|
|
36
|
+
baseURL: opts.baseURL,
|
|
37
|
+
withCredentials: opts.withCredentials,
|
|
38
|
+
});
|
|
39
|
+
httpClient.addRequestInterceptor((config) => {
|
|
40
|
+
if (opts.stripApiPrefix && typeof config.url === 'string' && config.url.startsWith('/api/')) {
|
|
41
|
+
config.url = config.url.replace(/^\/api\//, '/');
|
|
42
|
+
}
|
|
43
|
+
const token = opts.getToken();
|
|
44
|
+
if (token) {
|
|
45
|
+
config.headers = { ...config.headers, Authorization: `Bearer ${token}` };
|
|
46
|
+
}
|
|
47
|
+
return config;
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
httpClient,
|
|
51
|
+
setupHttpDefault: () => setHttpClient(httpClient),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Builds the default JWT auth client + wires it into `@molecule/app-auth`.
|
|
56
|
+
*
|
|
57
|
+
* Replaces the 16-line per-app `bonds/auth-default.ts` that 93 fleet
|
|
58
|
+
* apps shipped byte-identically. Apps pass their own `authConfig`
|
|
59
|
+
* (which lives in `src/config.ts`).
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* // bonds/auth-default.ts
|
|
64
|
+
* import { createDefaultAuthClient } from '@molecule/app-bonds-default-react'
|
|
65
|
+
* import { authConfig } from '../config.js'
|
|
66
|
+
*
|
|
67
|
+
* export const { authClient, setupAuthDefault } =
|
|
68
|
+
* createDefaultAuthClient(authConfig)
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function createDefaultAuthClient(authConfig) {
|
|
72
|
+
const authClient = createJWTAuthClient(authConfig);
|
|
73
|
+
return {
|
|
74
|
+
authClient,
|
|
75
|
+
setupAuthDefault: () => setClient(authClient),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Variant of `createDefaultAuthClient` that also keeps the bonded
|
|
80
|
+
* `@molecule/app-http` client's bearer token in sync with auth events
|
|
81
|
+
* (login / register / refresh / logout). Required by apps whose http
|
|
82
|
+
* client must carry the JWT on every request — without this wiring,
|
|
83
|
+
* authed endpoints return 401 after page reloads or token refresh.
|
|
84
|
+
*
|
|
85
|
+
* Hydrates the HTTP client's token from the persisted auth state
|
|
86
|
+
* on setup, then listens for auth events to keep them aligned.
|
|
87
|
+
*/
|
|
88
|
+
export function createDefaultAuthClientWithHttpSync(authConfig) {
|
|
89
|
+
const authClient = createJWTAuthClient(authConfig);
|
|
90
|
+
return {
|
|
91
|
+
authClient,
|
|
92
|
+
setupAuthDefault: () => {
|
|
93
|
+
setClient(authClient);
|
|
94
|
+
const initialToken = authClient.getAccessToken();
|
|
95
|
+
if (initialToken) {
|
|
96
|
+
getHttpClient().setAuthToken(initialToken);
|
|
97
|
+
}
|
|
98
|
+
authClient.addEventListener((event) => {
|
|
99
|
+
if (event.type === 'login' || event.type === 'register' || event.type === 'refresh') {
|
|
100
|
+
const token = authClient.getAccessToken();
|
|
101
|
+
if (token)
|
|
102
|
+
getHttpClient().setAuthToken(token);
|
|
103
|
+
}
|
|
104
|
+
else if (event.type === 'logout') {
|
|
105
|
+
getHttpClient().setAuthToken(null);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Most aggressive variant — bonds a fetch-based HTTP client with the
|
|
113
|
+
* given `baseURL` (so molecule pkg `useGet('/path')` calls hit
|
|
114
|
+
* `${baseURL}/path` instead of the SPA's catch-all route), AND keeps
|
|
115
|
+
* its bearer token in sync with auth events.
|
|
116
|
+
*
|
|
117
|
+
* Used by apps where molecule packages render pricing / billing /
|
|
118
|
+
* other authed JSON-fetching screens that need both behaviors.
|
|
119
|
+
*/
|
|
120
|
+
export function createDefaultAuthClientWithFetchClient(authConfig, fetchClientOptions) {
|
|
121
|
+
const authClient = createJWTAuthClient(authConfig);
|
|
122
|
+
return {
|
|
123
|
+
authClient,
|
|
124
|
+
setupAuthDefault: () => {
|
|
125
|
+
const httpClient = createFetchClient({
|
|
126
|
+
baseURL: fetchClientOptions.baseURL,
|
|
127
|
+
withCredentials: fetchClientOptions.withCredentials ?? true,
|
|
128
|
+
});
|
|
129
|
+
setHttpClient(httpClient);
|
|
130
|
+
setClient(authClient);
|
|
131
|
+
const initialToken = authClient.getAccessToken();
|
|
132
|
+
if (initialToken) {
|
|
133
|
+
httpClient.setAuthToken(initialToken);
|
|
134
|
+
}
|
|
135
|
+
authClient.addEventListener((event) => {
|
|
136
|
+
if (event.type === 'login' || event.type === 'register' || event.type === 'refresh') {
|
|
137
|
+
const token = authClient.getAccessToken();
|
|
138
|
+
if (token)
|
|
139
|
+
httpClient.setAuthToken(token);
|
|
140
|
+
}
|
|
141
|
+
else if (event.type === 'logout') {
|
|
142
|
+
httpClient.setAuthToken(null);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ComponentType } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Boot the React app: wire bonds, kick off auth initialization, mount
|
|
4
|
+
* `<App />` inside `<StrictMode>` to `#root`, and (optionally) register
|
|
5
|
+
* the PWA service worker.
|
|
6
|
+
*
|
|
7
|
+
* Replaces the 20-line per-app `src/main.tsx` that 97 fleet apps shipped
|
|
8
|
+
* byte-identically.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* // src/main.tsx
|
|
13
|
+
* import './index.css'
|
|
14
|
+
* import './theme.css'
|
|
15
|
+
*
|
|
16
|
+
* import { bootstrapApp } from '@molecule/app-bonds-default-react'
|
|
17
|
+
*
|
|
18
|
+
* import { App } from './App.js'
|
|
19
|
+
* import { authClient, setupProviders } from './bonds/index.js'
|
|
20
|
+
* import { registerPWA } from './pwa.js'
|
|
21
|
+
*
|
|
22
|
+
* bootstrapApp({ App, authClient, setupProviders, registerPWA })
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function bootstrapApp(opts: {
|
|
26
|
+
App: ComponentType;
|
|
27
|
+
authClient: {
|
|
28
|
+
initialize: () => Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
setupProviders: () => void | Promise<void>;
|
|
31
|
+
registerPWA?: () => void;
|
|
32
|
+
}): void;
|
|
33
|
+
//# sourceMappingURL=bootstrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/bootstrap.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAc,MAAM,OAAO,CAAA;AAGtD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,GAAG,EAAE,aAAa,CAAA;IAClB,UAAU,EAAE;QAAE,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAA;IAC/C,cAAc,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;CACzB,GAAG,IAAI,CAwBP"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { StrictMode } from 'react';
|
|
3
|
+
import { createRoot } from 'react-dom/client';
|
|
4
|
+
/**
|
|
5
|
+
* Boot the React app: wire bonds, kick off auth initialization, mount
|
|
6
|
+
* `<App />` inside `<StrictMode>` to `#root`, and (optionally) register
|
|
7
|
+
* the PWA service worker.
|
|
8
|
+
*
|
|
9
|
+
* Replaces the 20-line per-app `src/main.tsx` that 97 fleet apps shipped
|
|
10
|
+
* byte-identically.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* // src/main.tsx
|
|
15
|
+
* import './index.css'
|
|
16
|
+
* import './theme.css'
|
|
17
|
+
*
|
|
18
|
+
* import { bootstrapApp } from '@molecule/app-bonds-default-react'
|
|
19
|
+
*
|
|
20
|
+
* import { App } from './App.js'
|
|
21
|
+
* import { authClient, setupProviders } from './bonds/index.js'
|
|
22
|
+
* import { registerPWA } from './pwa.js'
|
|
23
|
+
*
|
|
24
|
+
* bootstrapApp({ App, authClient, setupProviders, registerPWA })
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function bootstrapApp(opts) {
|
|
28
|
+
void (async () => {
|
|
29
|
+
// Await provider wiring BEFORE the first render so components may use
|
|
30
|
+
// bonded providers from their very first effect (e.g. realtime
|
|
31
|
+
// `connect()` — several optional setups like setupAppRealtimeSocketio
|
|
32
|
+
// are async, and mounting past them races the bond registration).
|
|
33
|
+
await opts.setupProviders();
|
|
34
|
+
opts.authClient.initialize().catch((error) => {
|
|
35
|
+
// Auth session restore is best-effort at boot — the app mounts
|
|
36
|
+
// logged-out and the user can sign in; log for debuggability.
|
|
37
|
+
console.warn('bootstrapApp: authClient.initialize() failed', error);
|
|
38
|
+
});
|
|
39
|
+
createRoot(document.getElementById('root')).render(_jsx(StrictMode, { children: _jsx(opts.App, {}) }));
|
|
40
|
+
opts.registerPWA?.();
|
|
41
|
+
})().catch((error) => {
|
|
42
|
+
// A provider setup failure means the app cannot mount — surface it
|
|
43
|
+
// loudly instead of leaving a silent blank page.
|
|
44
|
+
console.error('bootstrapApp: setupProviders() failed; app not mounted', error);
|
|
45
|
+
throw error;
|
|
46
|
+
});
|
|
47
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@molecule/app-bonds-default-react` — default app-side bond wirings for the
|
|
3
|
+
* React fleet stack, replacing the byte-identical per-app files:
|
|
4
|
+
*
|
|
5
|
+
* - `bootstrapApp({ App, authClient, setupProviders, registerPWA? })` — the
|
|
6
|
+
* whole scaffolded `src/main.tsx`: awaits `setupProviders()` BEFORE the
|
|
7
|
+
* first render, kicks off `authClient.initialize()` (best-effort), mounts
|
|
8
|
+
* `<App />` in StrictMode on `#root`, then registers the PWA.
|
|
9
|
+
* - `setupAllDefaultBonds()` — wires the SEVEN universal bonds in one call:
|
|
10
|
+
* fonts-arimo, routing-react-router, storage-localstorage, styling-tailwind
|
|
11
|
+
* (registers the tailwind-merge class merger), theme-css-variables
|
|
12
|
+
* (light + dark via `getDefaultThemeProvider()`), ui-tailwind ClassMap,
|
|
13
|
+
* icons-molecule. Each also exists as an individual `setupApp*()` for apps
|
|
14
|
+
* that wire a la carte (per-app `app/src/bonds/<name>.ts` files stay 1-line
|
|
15
|
+
* re-exports of these).
|
|
16
|
+
* - Auth/http factories — `createDefaultAuthClient(authConfig)` returns
|
|
17
|
+
* `{ authClient, setupAuthDefault }`; the `...WithHttpSync` /
|
|
18
|
+
* `...WithFetchClient` variants also keep the bonded http client's bearer
|
|
19
|
+
* token in sync with auth events.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* // src/main.tsx
|
|
24
|
+
* import {
|
|
25
|
+
* bootstrapApp,
|
|
26
|
+
* createDefaultAuthClientWithHttpSync,
|
|
27
|
+
* setupAllDefaultBonds,
|
|
28
|
+
* setupAppCodeEditorMonaco,
|
|
29
|
+
* } from '@molecule/app-bonds-default-react'
|
|
30
|
+
*
|
|
31
|
+
* import { App } from './App.js'
|
|
32
|
+
* import { authConfig } from './config.js'
|
|
33
|
+
*
|
|
34
|
+
* const { authClient, setupAuthDefault } =
|
|
35
|
+
* createDefaultAuthClientWithHttpSync(authConfig)
|
|
36
|
+
*
|
|
37
|
+
* bootstrapApp({
|
|
38
|
+
* App,
|
|
39
|
+
* authClient,
|
|
40
|
+
* // Async so optional async bonds are AWAITED before the first render.
|
|
41
|
+
* setupProviders: async () => {
|
|
42
|
+
* setupAllDefaultBonds()
|
|
43
|
+
* setupAuthDefault()
|
|
44
|
+
* await setupAppCodeEditorMonaco() // only if the app uses the code editor
|
|
45
|
+
* },
|
|
46
|
+
* })
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* - `setupAllDefaultBonds()` does NOT wire the optional bonds. Those ship as
|
|
51
|
+
* separate ASYNC setups — `setupAppRealtimeSocketio`,
|
|
52
|
+
* `setupAppKeyboardShortcutsHotkeys`, `setupAppCommandPaletteCmdk`,
|
|
53
|
+
* `setupAppCodeEditorMonaco`, `setupAppVirtualScrollTanstack`,
|
|
54
|
+
* `setupAppDragDropDndkit`, `setupAppChartsChartjs`, `setupAppMapsLeaflet`,
|
|
55
|
+
* `setupAppVideoHls` — and MUST be awaited inside `setupProviders`
|
|
56
|
+
* (make it async). `bootstrapApp` awaits `setupProviders()` before mounting
|
|
57
|
+
* so bonded providers exist by a component's first effect; a fire-and-forget
|
|
58
|
+
* async setup races the mount and intermittently loses.
|
|
59
|
+
* - Plain `createDefaultAuthClient` does NOT attach the JWT to the bonded
|
|
60
|
+
* http client. If molecule packages call authed `/api` endpoints, use
|
|
61
|
+
* `createDefaultAuthClientWithHttpSync` (or `...WithFetchClient` to also
|
|
62
|
+
* bond a fetch client with a `baseURL`) — otherwise those endpoints return
|
|
63
|
+
* 401 after a page reload or token refresh.
|
|
64
|
+
* - `getDefaultThemeProvider()` constructs lazily because the CSS-variables
|
|
65
|
+
* theme provider touches `localStorage` at construction — importing this
|
|
66
|
+
* package is SSR/test-safe, but only CALL it in a DOM environment. Apps
|
|
67
|
+
* with custom themes build their own provider and skip
|
|
68
|
+
* `setupAppThemeCssVariables()`.
|
|
69
|
+
*
|
|
70
|
+
* @module
|
|
71
|
+
*/
|
|
72
|
+
export * from './auth.js';
|
|
73
|
+
export * from './bootstrap.js';
|
|
74
|
+
export * from './setup.js';
|
|
75
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AAEH,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@molecule/app-bonds-default-react` — default app-side bond wirings for the
|
|
3
|
+
* React fleet stack, replacing the byte-identical per-app files:
|
|
4
|
+
*
|
|
5
|
+
* - `bootstrapApp({ App, authClient, setupProviders, registerPWA? })` — the
|
|
6
|
+
* whole scaffolded `src/main.tsx`: awaits `setupProviders()` BEFORE the
|
|
7
|
+
* first render, kicks off `authClient.initialize()` (best-effort), mounts
|
|
8
|
+
* `<App />` in StrictMode on `#root`, then registers the PWA.
|
|
9
|
+
* - `setupAllDefaultBonds()` — wires the SEVEN universal bonds in one call:
|
|
10
|
+
* fonts-arimo, routing-react-router, storage-localstorage, styling-tailwind
|
|
11
|
+
* (registers the tailwind-merge class merger), theme-css-variables
|
|
12
|
+
* (light + dark via `getDefaultThemeProvider()`), ui-tailwind ClassMap,
|
|
13
|
+
* icons-molecule. Each also exists as an individual `setupApp*()` for apps
|
|
14
|
+
* that wire a la carte (per-app `app/src/bonds/<name>.ts` files stay 1-line
|
|
15
|
+
* re-exports of these).
|
|
16
|
+
* - Auth/http factories — `createDefaultAuthClient(authConfig)` returns
|
|
17
|
+
* `{ authClient, setupAuthDefault }`; the `...WithHttpSync` /
|
|
18
|
+
* `...WithFetchClient` variants also keep the bonded http client's bearer
|
|
19
|
+
* token in sync with auth events.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* // src/main.tsx
|
|
24
|
+
* import {
|
|
25
|
+
* bootstrapApp,
|
|
26
|
+
* createDefaultAuthClientWithHttpSync,
|
|
27
|
+
* setupAllDefaultBonds,
|
|
28
|
+
* setupAppCodeEditorMonaco,
|
|
29
|
+
* } from '@molecule/app-bonds-default-react'
|
|
30
|
+
*
|
|
31
|
+
* import { App } from './App.js'
|
|
32
|
+
* import { authConfig } from './config.js'
|
|
33
|
+
*
|
|
34
|
+
* const { authClient, setupAuthDefault } =
|
|
35
|
+
* createDefaultAuthClientWithHttpSync(authConfig)
|
|
36
|
+
*
|
|
37
|
+
* bootstrapApp({
|
|
38
|
+
* App,
|
|
39
|
+
* authClient,
|
|
40
|
+
* // Async so optional async bonds are AWAITED before the first render.
|
|
41
|
+
* setupProviders: async () => {
|
|
42
|
+
* setupAllDefaultBonds()
|
|
43
|
+
* setupAuthDefault()
|
|
44
|
+
* await setupAppCodeEditorMonaco() // only if the app uses the code editor
|
|
45
|
+
* },
|
|
46
|
+
* })
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* - `setupAllDefaultBonds()` does NOT wire the optional bonds. Those ship as
|
|
51
|
+
* separate ASYNC setups — `setupAppRealtimeSocketio`,
|
|
52
|
+
* `setupAppKeyboardShortcutsHotkeys`, `setupAppCommandPaletteCmdk`,
|
|
53
|
+
* `setupAppCodeEditorMonaco`, `setupAppVirtualScrollTanstack`,
|
|
54
|
+
* `setupAppDragDropDndkit`, `setupAppChartsChartjs`, `setupAppMapsLeaflet`,
|
|
55
|
+
* `setupAppVideoHls` — and MUST be awaited inside `setupProviders`
|
|
56
|
+
* (make it async). `bootstrapApp` awaits `setupProviders()` before mounting
|
|
57
|
+
* so bonded providers exist by a component's first effect; a fire-and-forget
|
|
58
|
+
* async setup races the mount and intermittently loses.
|
|
59
|
+
* - Plain `createDefaultAuthClient` does NOT attach the JWT to the bonded
|
|
60
|
+
* http client. If molecule packages call authed `/api` endpoints, use
|
|
61
|
+
* `createDefaultAuthClientWithHttpSync` (or `...WithFetchClient` to also
|
|
62
|
+
* bond a fetch client with a `baseURL`) — otherwise those endpoints return
|
|
63
|
+
* 401 after a page reload or token refresh.
|
|
64
|
+
* - `getDefaultThemeProvider()` constructs lazily because the CSS-variables
|
|
65
|
+
* theme provider touches `localStorage` at construction — importing this
|
|
66
|
+
* package is SSR/test-safe, but only CALL it in a DOM environment. Apps
|
|
67
|
+
* with custom themes build their own provider and skip
|
|
68
|
+
* `setupAppThemeCssVariables()`.
|
|
69
|
+
*
|
|
70
|
+
* @module
|
|
71
|
+
*/
|
|
72
|
+
export * from './auth.js';
|
|
73
|
+
export * from './bootstrap.js';
|
|
74
|
+
export * from './setup.js';
|
package/dist/setup.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default app-side bond wirings (React + Tailwind + React Router +
|
|
3
|
+
* localStorage + Arimo font + Molecule icons).
|
|
4
|
+
*
|
|
5
|
+
* Centralizes 5 byte-identical `app/src/bonds/<name>.ts` setup
|
|
6
|
+
* functions that every flagship app shipped. Per-app bond files
|
|
7
|
+
* become 1-line re-exports — `bonds/index.ts` import sites unchanged.
|
|
8
|
+
*
|
|
9
|
+
* `setupAppStylingTailwind` registers `tailwind-merge` as the class merger
|
|
10
|
+
* for `cn()`; Tailwind itself is configured via env vars and the Vite plugin.
|
|
11
|
+
* Apps wire it in `setupProviders()` alongside the others.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { createCSSVariablesThemeProvider } from '@molecule/app-theme-css-variables';
|
|
16
|
+
/** Returns (and lazily constructs) the shared default CSS-variables theme provider. */
|
|
17
|
+
export declare function getDefaultThemeProvider(): ReturnType<typeof createCSSVariablesThemeProvider>;
|
|
18
|
+
/** Wires `@molecule/app-fonts-arimo` to `@molecule/app-fonts`. */
|
|
19
|
+
export declare function setupAppFontsArimo(): void;
|
|
20
|
+
/** Wires `@molecule/app-icons-molecule` to `@molecule/app-icons`. */
|
|
21
|
+
export declare function setupAppIconsMolecule(): void;
|
|
22
|
+
/** Wires `@molecule/app-routing-react-router` to `@molecule/app-routing`. */
|
|
23
|
+
export declare function setupAppRoutingReactRouter(): void;
|
|
24
|
+
/** Wires `@molecule/app-storage-localstorage` to `@molecule/app-storage`. */
|
|
25
|
+
export declare function setupAppStorageLocalstorage(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Wires `@molecule/app-styling-tailwind`: registers `tailwind-merge` as the
|
|
28
|
+
* class merger for `@molecule/app-styling`'s `cn()`, so conflicting Tailwind
|
|
29
|
+
* utilities resolve (last wins). Tailwind itself is configured via env vars +
|
|
30
|
+
* the Vite plugin; this is the one runtime hook the framework-agnostic styling
|
|
31
|
+
* core needs so it carries no Tailwind dependency of its own.
|
|
32
|
+
*/
|
|
33
|
+
export declare function setupAppStylingTailwind(): void;
|
|
34
|
+
/** Wires the default light + dark CSS-variables theme provider to `@molecule/app-theme`. */
|
|
35
|
+
export declare function setupAppThemeCssVariables(): void;
|
|
36
|
+
/** Wires `@molecule/app-ui-tailwind` `classMap` to `@molecule/app-ui`. */
|
|
37
|
+
export declare function setupAppUiTailwind(): void;
|
|
38
|
+
/** Wires `@molecule/app-realtime-socketio` to `@molecule/app-realtime`. */
|
|
39
|
+
export declare function setupAppRealtimeSocketio(): Promise<void>;
|
|
40
|
+
/** Wires `@molecule/app-keyboard-shortcuts-hotkeys` to `@molecule/app-keyboard-shortcuts`. */
|
|
41
|
+
export declare function setupAppKeyboardShortcutsHotkeys(): Promise<void>;
|
|
42
|
+
/** Wires `@molecule/app-command-palette-cmdk` to `@molecule/app-command-palette`. */
|
|
43
|
+
export declare function setupAppCommandPaletteCmdk(): Promise<void>;
|
|
44
|
+
/** Wires `@molecule/app-code-editor-monaco` to `@molecule/app-code-editor`. */
|
|
45
|
+
export declare function setupAppCodeEditorMonaco(): Promise<void>;
|
|
46
|
+
/** Wires `@molecule/app-virtual-scroll-tanstack` to `@molecule/app-virtual-scroll`. */
|
|
47
|
+
export declare function setupAppVirtualScrollTanstack(): Promise<void>;
|
|
48
|
+
/** Wires `@molecule/app-drag-drop-dndkit` to `@molecule/app-drag-drop`. */
|
|
49
|
+
export declare function setupAppDragDropDndkit(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Wires `@molecule/app-charts-chartjs` (Chart.js) to `@molecule/app-charts` — real
|
|
52
|
+
* line/bar/pie/etc. charts instead of the core's placeholder panel.
|
|
53
|
+
*/
|
|
54
|
+
export declare function setupAppChartsChartjs(): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Wires `@molecule/app-maps-leaflet` (Leaflet + OpenStreetMap, no API key) to
|
|
57
|
+
* `@molecule/app-maps` — a real slippy map instead of the core's grey placeholder.
|
|
58
|
+
* REQUIRES `import 'leaflet/dist/leaflet.css'` once in the app entry (the scaffolded
|
|
59
|
+
* `bonds/app-maps-leaflet.ts` does this); without it tiles + markers mis-position.
|
|
60
|
+
*/
|
|
61
|
+
export declare function setupAppMapsLeaflet(): Promise<void>;
|
|
62
|
+
/** Wires `@molecule/app-video-hls` (hls.js — HLS streaming everywhere) to `@molecule/app-video`. */
|
|
63
|
+
export declare function setupAppVideoHls(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Wires all 7 universal app-side bonds in one call — fonts, routing,
|
|
66
|
+
* storage, styling, theme, UI ClassMap, icons (in that order). Auth
|
|
67
|
+
* + i18n stay per-app because they need app-specific config.
|
|
68
|
+
*
|
|
69
|
+
* Replaces 9 individual setupX() calls in per-app `bonds/index.ts`.
|
|
70
|
+
*/
|
|
71
|
+
export declare function setupAllDefaultBonds(): void;
|
|
72
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,OAAO,EACL,+BAA+B,EAGhC,MAAM,mCAAmC,CAAA;AAe1C,uFAAuF;AACvF,wBAAgB,uBAAuB,IAAI,UAAU,CAAC,OAAO,+BAA+B,CAAC,CAS5F;AAED,kEAAkE;AAClE,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,qEAAqE;AACrE,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,6EAA6E;AAC7E,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED,6EAA6E;AAC7E,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED,4FAA4F;AAC5F,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED,0EAA0E;AAC1E,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,2EAA2E;AAC3E,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM9D;AAED,8FAA8F;AAC9F,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,IAAI,CAAC,CAMtE;AAED,qFAAqF;AACrF,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAMhE;AAED,+EAA+E;AAC/E,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM9D;AAED,uFAAuF;AACvF,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,IAAI,CAAC,CAMnE;AAED,2EAA2E;AAC3E,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM5D;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAM3D;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMzD;AAED,oGAAoG;AACpG,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMtD;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAQ3C"}
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default app-side bond wirings (React + Tailwind + React Router +
|
|
3
|
+
* localStorage + Arimo font + Molecule icons).
|
|
4
|
+
*
|
|
5
|
+
* Centralizes 5 byte-identical `app/src/bonds/<name>.ts` setup
|
|
6
|
+
* functions that every flagship app shipped. Per-app bond files
|
|
7
|
+
* become 1-line re-exports — `bonds/index.ts` import sites unchanged.
|
|
8
|
+
*
|
|
9
|
+
* `setupAppStylingTailwind` registers `tailwind-merge` as the class merger
|
|
10
|
+
* for `cn()`; Tailwind itself is configured via env vars and the Vite plugin.
|
|
11
|
+
* Apps wire it in `setupProviders()` alongside the others.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { setFont } from '@molecule/app-fonts';
|
|
16
|
+
import { font as arimoFont } from '@molecule/app-fonts-arimo';
|
|
17
|
+
import { setIconSet } from '@molecule/app-icons';
|
|
18
|
+
import { iconSet as moleculeIconSet } from '@molecule/app-icons-molecule';
|
|
19
|
+
import { setRouter } from '@molecule/app-routing';
|
|
20
|
+
import { provider as reactRouterProvider } from '@molecule/app-routing-react-router';
|
|
21
|
+
import { setProvider as setStorage } from '@molecule/app-storage';
|
|
22
|
+
import { provider as localStorageProvider } from '@molecule/app-storage-localstorage';
|
|
23
|
+
import { registerTailwindClassMerger } from '@molecule/app-styling-tailwind';
|
|
24
|
+
import { setProvider as setTheme } from '@molecule/app-theme';
|
|
25
|
+
import { createCSSVariablesThemeProvider, darkTheme, lightTheme, } from '@molecule/app-theme-css-variables';
|
|
26
|
+
import { setClassMap } from '@molecule/app-ui';
|
|
27
|
+
import { classMap } from '@molecule/app-ui-tailwind';
|
|
28
|
+
/**
|
|
29
|
+
* Pre-wired default CSS-variables theme provider with light + dark
|
|
30
|
+
* themes from `@molecule/app-theme-css-variables`. Apps that need
|
|
31
|
+
* custom themes should build their own provider and skip this.
|
|
32
|
+
*
|
|
33
|
+
* Lazily constructed on first access — `createCSSVariablesThemeProvider`
|
|
34
|
+
* touches `globalThis.localStorage.getItem` during construction, which
|
|
35
|
+
* throws in non-DOM environments (SSR, unit-test runners with
|
|
36
|
+
* incomplete localStorage shims).
|
|
37
|
+
*/
|
|
38
|
+
let _defaultThemeProvider = null;
|
|
39
|
+
/** Returns (and lazily constructs) the shared default CSS-variables theme provider. */
|
|
40
|
+
export function getDefaultThemeProvider() {
|
|
41
|
+
if (!_defaultThemeProvider) {
|
|
42
|
+
_defaultThemeProvider = createCSSVariablesThemeProvider({
|
|
43
|
+
themes: [lightTheme, darkTheme],
|
|
44
|
+
defaultTheme: 'light',
|
|
45
|
+
persistKey: 'molecule-theme',
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return _defaultThemeProvider;
|
|
49
|
+
}
|
|
50
|
+
/** Wires `@molecule/app-fonts-arimo` to `@molecule/app-fonts`. */
|
|
51
|
+
export function setupAppFontsArimo() {
|
|
52
|
+
setFont(arimoFont);
|
|
53
|
+
}
|
|
54
|
+
/** Wires `@molecule/app-icons-molecule` to `@molecule/app-icons`. */
|
|
55
|
+
export function setupAppIconsMolecule() {
|
|
56
|
+
setIconSet(moleculeIconSet);
|
|
57
|
+
}
|
|
58
|
+
/** Wires `@molecule/app-routing-react-router` to `@molecule/app-routing`. */
|
|
59
|
+
export function setupAppRoutingReactRouter() {
|
|
60
|
+
setRouter(reactRouterProvider);
|
|
61
|
+
}
|
|
62
|
+
/** Wires `@molecule/app-storage-localstorage` to `@molecule/app-storage`. */
|
|
63
|
+
export function setupAppStorageLocalstorage() {
|
|
64
|
+
setStorage(localStorageProvider);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Wires `@molecule/app-styling-tailwind`: registers `tailwind-merge` as the
|
|
68
|
+
* class merger for `@molecule/app-styling`'s `cn()`, so conflicting Tailwind
|
|
69
|
+
* utilities resolve (last wins). Tailwind itself is configured via env vars +
|
|
70
|
+
* the Vite plugin; this is the one runtime hook the framework-agnostic styling
|
|
71
|
+
* core needs so it carries no Tailwind dependency of its own.
|
|
72
|
+
*/
|
|
73
|
+
export function setupAppStylingTailwind() {
|
|
74
|
+
registerTailwindClassMerger();
|
|
75
|
+
}
|
|
76
|
+
/** Wires the default light + dark CSS-variables theme provider to `@molecule/app-theme`. */
|
|
77
|
+
export function setupAppThemeCssVariables() {
|
|
78
|
+
setTheme(getDefaultThemeProvider());
|
|
79
|
+
}
|
|
80
|
+
/** Wires `@molecule/app-ui-tailwind` `classMap` to `@molecule/app-ui`. */
|
|
81
|
+
export function setupAppUiTailwind() {
|
|
82
|
+
setClassMap(classMap);
|
|
83
|
+
}
|
|
84
|
+
/** Wires `@molecule/app-realtime-socketio` to `@molecule/app-realtime`. */
|
|
85
|
+
export async function setupAppRealtimeSocketio() {
|
|
86
|
+
const [{ setProvider: setRealtime }, { provider }] = await Promise.all([
|
|
87
|
+
import('@molecule/app-realtime'),
|
|
88
|
+
import('@molecule/app-realtime-socketio'),
|
|
89
|
+
]);
|
|
90
|
+
setRealtime(provider);
|
|
91
|
+
}
|
|
92
|
+
/** Wires `@molecule/app-keyboard-shortcuts-hotkeys` to `@molecule/app-keyboard-shortcuts`. */
|
|
93
|
+
export async function setupAppKeyboardShortcutsHotkeys() {
|
|
94
|
+
const [{ setProvider: setKbd }, { provider }] = await Promise.all([
|
|
95
|
+
import('@molecule/app-keyboard-shortcuts'),
|
|
96
|
+
import('@molecule/app-keyboard-shortcuts-hotkeys'),
|
|
97
|
+
]);
|
|
98
|
+
setKbd(provider);
|
|
99
|
+
}
|
|
100
|
+
/** Wires `@molecule/app-command-palette-cmdk` to `@molecule/app-command-palette`. */
|
|
101
|
+
export async function setupAppCommandPaletteCmdk() {
|
|
102
|
+
const [{ setProvider: setPalette }, { provider }] = await Promise.all([
|
|
103
|
+
import('@molecule/app-command-palette'),
|
|
104
|
+
import('@molecule/app-command-palette-cmdk'),
|
|
105
|
+
]);
|
|
106
|
+
setPalette(provider);
|
|
107
|
+
}
|
|
108
|
+
/** Wires `@molecule/app-code-editor-monaco` to `@molecule/app-code-editor`. */
|
|
109
|
+
export async function setupAppCodeEditorMonaco() {
|
|
110
|
+
const [{ setProvider: setEditor }, { provider }] = await Promise.all([
|
|
111
|
+
import('@molecule/app-code-editor'),
|
|
112
|
+
import('@molecule/app-code-editor-monaco'),
|
|
113
|
+
]);
|
|
114
|
+
setEditor(provider);
|
|
115
|
+
}
|
|
116
|
+
/** Wires `@molecule/app-virtual-scroll-tanstack` to `@molecule/app-virtual-scroll`. */
|
|
117
|
+
export async function setupAppVirtualScrollTanstack() {
|
|
118
|
+
const [{ setProvider: setScroll }, { provider }] = await Promise.all([
|
|
119
|
+
import('@molecule/app-virtual-scroll'),
|
|
120
|
+
import('@molecule/app-virtual-scroll-tanstack'),
|
|
121
|
+
]);
|
|
122
|
+
setScroll(provider);
|
|
123
|
+
}
|
|
124
|
+
/** Wires `@molecule/app-drag-drop-dndkit` to `@molecule/app-drag-drop`. */
|
|
125
|
+
export async function setupAppDragDropDndkit() {
|
|
126
|
+
const [{ setProvider: setDnd }, { provider }] = await Promise.all([
|
|
127
|
+
import('@molecule/app-drag-drop'),
|
|
128
|
+
import('@molecule/app-drag-drop-dndkit'),
|
|
129
|
+
]);
|
|
130
|
+
setDnd(provider);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Wires `@molecule/app-charts-chartjs` (Chart.js) to `@molecule/app-charts` — real
|
|
134
|
+
* line/bar/pie/etc. charts instead of the core's placeholder panel.
|
|
135
|
+
*/
|
|
136
|
+
export async function setupAppChartsChartjs() {
|
|
137
|
+
const [{ setProvider: setCharts }, { provider }] = await Promise.all([
|
|
138
|
+
import('@molecule/app-charts'),
|
|
139
|
+
import('@molecule/app-charts-chartjs'),
|
|
140
|
+
]);
|
|
141
|
+
setCharts(provider);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Wires `@molecule/app-maps-leaflet` (Leaflet + OpenStreetMap, no API key) to
|
|
145
|
+
* `@molecule/app-maps` — a real slippy map instead of the core's grey placeholder.
|
|
146
|
+
* REQUIRES `import 'leaflet/dist/leaflet.css'` once in the app entry (the scaffolded
|
|
147
|
+
* `bonds/app-maps-leaflet.ts` does this); without it tiles + markers mis-position.
|
|
148
|
+
*/
|
|
149
|
+
export async function setupAppMapsLeaflet() {
|
|
150
|
+
const [{ setProvider: setMaps }, { provider }] = await Promise.all([
|
|
151
|
+
import('@molecule/app-maps'),
|
|
152
|
+
import('@molecule/app-maps-leaflet'),
|
|
153
|
+
]);
|
|
154
|
+
setMaps(provider);
|
|
155
|
+
}
|
|
156
|
+
/** Wires `@molecule/app-video-hls` (hls.js — HLS streaming everywhere) to `@molecule/app-video`. */
|
|
157
|
+
export async function setupAppVideoHls() {
|
|
158
|
+
const [{ setProvider: setVideo }, { provider }] = await Promise.all([
|
|
159
|
+
import('@molecule/app-video'),
|
|
160
|
+
import('@molecule/app-video-hls'),
|
|
161
|
+
]);
|
|
162
|
+
setVideo(provider);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Wires all 7 universal app-side bonds in one call — fonts, routing,
|
|
166
|
+
* storage, styling, theme, UI ClassMap, icons (in that order). Auth
|
|
167
|
+
* + i18n stay per-app because they need app-specific config.
|
|
168
|
+
*
|
|
169
|
+
* Replaces 9 individual setupX() calls in per-app `bonds/index.ts`.
|
|
170
|
+
*/
|
|
171
|
+
export function setupAllDefaultBonds() {
|
|
172
|
+
setupAppFontsArimo();
|
|
173
|
+
setupAppRoutingReactRouter();
|
|
174
|
+
setupAppStorageLocalstorage();
|
|
175
|
+
setupAppStylingTailwind();
|
|
176
|
+
setupAppThemeCssVariables();
|
|
177
|
+
setupAppUiTailwind();
|
|
178
|
+
setupAppIconsMolecule();
|
|
179
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@molecule/app-bonds-default-react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Default app-side bond wirings for React+Tailwind+react-router+localStorage+Arimo font+molecule icons. 5 setup functions consolidating 665 byte-identical per-app bond wiring files across the fleet.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"test": "vitest run",
|
|
11
|
+
"test:watch": "vitest"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"molecule",
|
|
24
|
+
"bonds",
|
|
25
|
+
"default",
|
|
26
|
+
"react"
|
|
27
|
+
],
|
|
28
|
+
"license": "Apache-2.0",
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@molecule/app-auth": "1.0.0",
|
|
31
|
+
"@molecule/app-charts-chartjs": "1.0.0",
|
|
32
|
+
"@molecule/app-code-editor": "1.0.0",
|
|
33
|
+
"@molecule/app-code-editor-monaco": "1.0.0",
|
|
34
|
+
"@molecule/app-command-palette": "1.0.0",
|
|
35
|
+
"@molecule/app-command-palette-cmdk": "1.0.0",
|
|
36
|
+
"@molecule/app-drag-drop": "1.0.0",
|
|
37
|
+
"@molecule/app-drag-drop-dndkit": "1.0.0",
|
|
38
|
+
"@molecule/app-fonts": "1.0.0",
|
|
39
|
+
"@molecule/app-fonts-arimo": "1.0.0",
|
|
40
|
+
"@molecule/app-http": "1.0.0",
|
|
41
|
+
"@molecule/app-icons": "1.0.0",
|
|
42
|
+
"@molecule/app-icons-molecule": "1.0.0",
|
|
43
|
+
"@molecule/app-keyboard-shortcuts": "1.0.0",
|
|
44
|
+
"@molecule/app-keyboard-shortcuts-hotkeys": "1.0.0",
|
|
45
|
+
"@molecule/app-maps-leaflet": "1.0.0",
|
|
46
|
+
"@molecule/app-realtime": "1.0.0",
|
|
47
|
+
"@molecule/app-realtime-socketio": "1.0.0",
|
|
48
|
+
"@molecule/app-routing": "1.0.0",
|
|
49
|
+
"@molecule/app-routing-react-router": "1.0.0",
|
|
50
|
+
"@molecule/app-storage": "1.0.0",
|
|
51
|
+
"@molecule/app-storage-localstorage": "1.0.0",
|
|
52
|
+
"@molecule/app-theme": "1.0.0",
|
|
53
|
+
"@molecule/app-theme-css-variables": "1.0.0",
|
|
54
|
+
"@molecule/app-ui": "1.0.0",
|
|
55
|
+
"@molecule/app-ui-tailwind": "1.0.0",
|
|
56
|
+
"@molecule/app-video-hls": "1.0.0",
|
|
57
|
+
"@molecule/app-virtual-scroll": "1.0.0",
|
|
58
|
+
"@molecule/app-virtual-scroll-tanstack": "1.0.0",
|
|
59
|
+
"@types/node": "26.1.2",
|
|
60
|
+
"@types/react": "19.2.17",
|
|
61
|
+
"@types/react-dom": "19.2.3",
|
|
62
|
+
"happy-dom": "20.11.1",
|
|
63
|
+
"react": "19.2.8",
|
|
64
|
+
"react-dom": "19.2.8",
|
|
65
|
+
"typescript": "6.0.3",
|
|
66
|
+
"vitest": "4.1.10"
|
|
67
|
+
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"@molecule/app-auth": "^1.0.0",
|
|
70
|
+
"@molecule/app-charts-chartjs": "1.0.0",
|
|
71
|
+
"@molecule/app-code-editor": "^1.0.0",
|
|
72
|
+
"@molecule/app-code-editor-monaco": "^1.0.0",
|
|
73
|
+
"@molecule/app-command-palette": "^1.0.0",
|
|
74
|
+
"@molecule/app-command-palette-cmdk": "^1.0.0",
|
|
75
|
+
"@molecule/app-drag-drop": "^1.0.0",
|
|
76
|
+
"@molecule/app-drag-drop-dndkit": "^1.0.0",
|
|
77
|
+
"@molecule/app-fonts": "^1.0.0",
|
|
78
|
+
"@molecule/app-fonts-arimo": "^1.0.0",
|
|
79
|
+
"@molecule/app-http": "^1.0.0",
|
|
80
|
+
"@molecule/app-icons": "^1.0.0",
|
|
81
|
+
"@molecule/app-icons-molecule": "^1.0.0",
|
|
82
|
+
"@molecule/app-keyboard-shortcuts": "^1.0.0",
|
|
83
|
+
"@molecule/app-keyboard-shortcuts-hotkeys": "^1.0.0",
|
|
84
|
+
"@molecule/app-maps-leaflet": "1.0.0",
|
|
85
|
+
"@molecule/app-realtime": "^1.0.0",
|
|
86
|
+
"@molecule/app-realtime-socketio": "^1.0.0",
|
|
87
|
+
"@molecule/app-routing": "^1.0.0",
|
|
88
|
+
"@molecule/app-routing-react-router": "^1.0.0",
|
|
89
|
+
"@molecule/app-storage": "^1.0.0",
|
|
90
|
+
"@molecule/app-storage-localstorage": "^1.0.0",
|
|
91
|
+
"@molecule/app-styling-tailwind": "^1.0.0",
|
|
92
|
+
"@molecule/app-theme": "^1.0.0",
|
|
93
|
+
"@molecule/app-theme-css-variables": "^1.0.0",
|
|
94
|
+
"@molecule/app-ui": "^1.0.0",
|
|
95
|
+
"@molecule/app-ui-tailwind": "^1.0.0",
|
|
96
|
+
"@molecule/app-video-hls": "1.0.0",
|
|
97
|
+
"@molecule/app-virtual-scroll": "^1.0.0",
|
|
98
|
+
"@molecule/app-virtual-scroll-tanstack": "^1.0.0",
|
|
99
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
100
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
101
|
+
},
|
|
102
|
+
"peerDependenciesMeta": {
|
|
103
|
+
"@molecule/app-charts-chartjs": {
|
|
104
|
+
"optional": true
|
|
105
|
+
},
|
|
106
|
+
"@molecule/app-code-editor": {
|
|
107
|
+
"optional": true
|
|
108
|
+
},
|
|
109
|
+
"@molecule/app-code-editor-monaco": {
|
|
110
|
+
"optional": true
|
|
111
|
+
},
|
|
112
|
+
"@molecule/app-command-palette": {
|
|
113
|
+
"optional": true
|
|
114
|
+
},
|
|
115
|
+
"@molecule/app-command-palette-cmdk": {
|
|
116
|
+
"optional": true
|
|
117
|
+
},
|
|
118
|
+
"@molecule/app-drag-drop": {
|
|
119
|
+
"optional": true
|
|
120
|
+
},
|
|
121
|
+
"@molecule/app-drag-drop-dndkit": {
|
|
122
|
+
"optional": true
|
|
123
|
+
},
|
|
124
|
+
"@molecule/app-keyboard-shortcuts": {
|
|
125
|
+
"optional": true
|
|
126
|
+
},
|
|
127
|
+
"@molecule/app-keyboard-shortcuts-hotkeys": {
|
|
128
|
+
"optional": true
|
|
129
|
+
},
|
|
130
|
+
"@molecule/app-maps-leaflet": {
|
|
131
|
+
"optional": true
|
|
132
|
+
},
|
|
133
|
+
"@molecule/app-realtime": {
|
|
134
|
+
"optional": true
|
|
135
|
+
},
|
|
136
|
+
"@molecule/app-realtime-socketio": {
|
|
137
|
+
"optional": true
|
|
138
|
+
},
|
|
139
|
+
"@molecule/app-video-hls": {
|
|
140
|
+
"optional": true
|
|
141
|
+
},
|
|
142
|
+
"@molecule/app-virtual-scroll": {
|
|
143
|
+
"optional": true
|
|
144
|
+
},
|
|
145
|
+
"@molecule/app-virtual-scroll-tanstack": {
|
|
146
|
+
"optional": true
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|