@jini-ai/admin 0.1.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 +201 -0
- package/README.md +138 -0
- package/dist/browser/index.d.ts +8 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +8 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/navigation.d.ts +39 -0
- package/dist/browser/navigation.d.ts.map +1 -0
- package/dist/browser/navigation.js +113 -0
- package/dist/browser/navigation.js.map +1 -0
- package/dist/core/gated/types.d.ts +87 -0
- package/dist/core/gated/types.d.ts.map +1 -0
- package/dist/core/gated/types.js +37 -0
- package/dist/core/gated/types.js.map +1 -0
- package/dist/core/index.d.ts +20 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +15 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/manifest/rules.d.ts +84 -0
- package/dist/core/manifest/rules.d.ts.map +1 -0
- package/dist/core/manifest/rules.js +130 -0
- package/dist/core/manifest/rules.js.map +1 -0
- package/dist/core/manifest/types.d.ts +154 -0
- package/dist/core/manifest/types.d.ts.map +1 -0
- package/dist/core/manifest/types.js +31 -0
- package/dist/core/manifest/types.js.map +1 -0
- package/dist/core/permissions/rules.d.ts +32 -0
- package/dist/core/permissions/rules.d.ts.map +1 -0
- package/dist/core/permissions/rules.js +34 -0
- package/dist/core/permissions/rules.js.map +1 -0
- package/dist/core/ports/analytics.d.ts +35 -0
- package/dist/core/ports/analytics.d.ts.map +1 -0
- package/dist/core/ports/analytics.js +14 -0
- package/dist/core/ports/analytics.js.map +1 -0
- package/dist/core/ports/auth.d.ts +49 -0
- package/dist/core/ports/auth.d.ts.map +1 -0
- package/dist/core/ports/auth.js +19 -0
- package/dist/core/ports/auth.js.map +1 -0
- package/dist/core/ports/comments.d.ts +90 -0
- package/dist/core/ports/comments.d.ts.map +1 -0
- package/dist/core/ports/comments.js +24 -0
- package/dist/core/ports/comments.js.map +1 -0
- package/dist/core/ports/database.d.ts +101 -0
- package/dist/core/ports/database.d.ts.map +1 -0
- package/dist/core/ports/database.js +2 -0
- package/dist/core/ports/database.js.map +1 -0
- package/dist/core/ports/forms.d.ts +130 -0
- package/dist/core/ports/forms.d.ts.map +1 -0
- package/dist/core/ports/forms.js +62 -0
- package/dist/core/ports/forms.js.map +1 -0
- package/dist/core/ports/identity.d.ts +114 -0
- package/dist/core/ports/identity.d.ts.map +1 -0
- package/dist/core/ports/identity.js +28 -0
- package/dist/core/ports/identity.js.map +1 -0
- package/dist/core/ports/index.d.ts +21 -0
- package/dist/core/ports/index.d.ts.map +1 -0
- package/dist/core/ports/index.js +6 -0
- package/dist/core/ports/index.js.map +1 -0
- package/dist/core/ports/integrations.d.ts +81 -0
- package/dist/core/ports/integrations.d.ts.map +1 -0
- package/dist/core/ports/integrations.js +21 -0
- package/dist/core/ports/integrations.js.map +1 -0
- package/dist/core/ports/media.d.ts +74 -0
- package/dist/core/ports/media.d.ts.map +1 -0
- package/dist/core/ports/media.js +28 -0
- package/dist/core/ports/media.js.map +1 -0
- package/dist/core/ports/members.d.ts +50 -0
- package/dist/core/ports/members.d.ts.map +1 -0
- package/dist/core/ports/members.js +17 -0
- package/dist/core/ports/members.js.map +1 -0
- package/dist/core/ports/menus.d.ts +179 -0
- package/dist/core/ports/menus.d.ts.map +1 -0
- package/dist/core/ports/menus.js +70 -0
- package/dist/core/ports/menus.js.map +1 -0
- package/dist/core/ports/plugins.d.ts +68 -0
- package/dist/core/ports/plugins.d.ts.map +1 -0
- package/dist/core/ports/plugins.js +27 -0
- package/dist/core/ports/plugins.js.map +1 -0
- package/dist/core/ports/recovery.d.ts +171 -0
- package/dist/core/ports/recovery.d.ts.map +1 -0
- package/dist/core/ports/recovery.js +2 -0
- package/dist/core/ports/recovery.js.map +1 -0
- package/dist/core/ports/redirects.d.ts +139 -0
- package/dist/core/ports/redirects.d.ts.map +1 -0
- package/dist/core/ports/redirects.js +55 -0
- package/dist/core/ports/redirects.js.map +1 -0
- package/dist/core/ports/seo.d.ts +147 -0
- package/dist/core/ports/seo.d.ts.map +1 -0
- package/dist/core/ports/seo.js +39 -0
- package/dist/core/ports/seo.js.map +1 -0
- package/dist/core/ports/settings.d.ts +87 -0
- package/dist/core/ports/settings.d.ts.map +1 -0
- package/dist/core/ports/settings.js +23 -0
- package/dist/core/ports/settings.js.map +1 -0
- package/dist/core/ports/workspace.d.ts +44 -0
- package/dist/core/ports/workspace.d.ts.map +1 -0
- package/dist/core/ports/workspace.js +29 -0
- package/dist/core/ports/workspace.js.map +1 -0
- package/dist/core/routing/rules.d.ts +54 -0
- package/dist/core/routing/rules.d.ts.map +1 -0
- package/dist/core/routing/rules.js +113 -0
- package/dist/core/routing/rules.js.map +1 -0
- package/dist/core/routing/types.d.ts +36 -0
- package/dist/core/routing/types.d.ts.map +1 -0
- package/dist/core/routing/types.js +17 -0
- package/dist/core/routing/types.js.map +1 -0
- package/dist/core/transport/errors.d.ts +53 -0
- package/dist/core/transport/errors.d.ts.map +1 -0
- package/dist/core/transport/errors.js +63 -0
- package/dist/core/transport/errors.js.map +1 -0
- package/dist/core/transport/http.d.ts +63 -0
- package/dist/core/transport/http.d.ts.map +1 -0
- package/dist/core/transport/http.js +63 -0
- package/dist/core/transport/http.js.map +1 -0
- package/dist/core/transport/index.d.ts +5 -0
- package/dist/core/transport/index.d.ts.map +1 -0
- package/dist/core/transport/index.js +3 -0
- package/dist/core/transport/index.js.map +1 -0
- package/dist/core/transport/types.d.ts +81 -0
- package/dist/core/transport/types.d.ts.map +1 -0
- package/dist/core/transport/types.js +43 -0
- package/dist/core/transport/types.js.map +1 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.d.ts +40 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.d.ts.map +1 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts +22 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.hooks.d.ts.map +1 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js +59 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.hooks.js.map +1 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.js +40 -0
- package/dist/react/components/ConfirmButton/ConfirmButton.js.map +1 -0
- package/dist/react/components/ConfirmButton.d.ts +39 -0
- package/dist/react/components/ConfirmButton.d.ts.map +1 -0
- package/dist/react/components/ConfirmButton.js +79 -0
- package/dist/react/components/ConfirmButton.js.map +1 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts +90 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.d.ts.map +1 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts +49 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.d.ts.map +1 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js +81 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.hooks.js.map +1 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.js +92 -0
- package/dist/react/components/ConfirmDialog/ConfirmDialog.js.map +1 -0
- package/dist/react/components/ConfirmDialog.d.ts +57 -0
- package/dist/react/components/ConfirmDialog.d.ts.map +1 -0
- package/dist/react/components/ConfirmDialog.js +85 -0
- package/dist/react/components/ConfirmDialog.js.map +1 -0
- package/dist/react/components/DataTable.d.ts +97 -0
- package/dist/react/components/DataTable.d.ts.map +1 -0
- package/dist/react/components/DataTable.js +20 -0
- package/dist/react/components/DataTable.js.map +1 -0
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts +25 -0
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.d.ts.map +1 -0
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js +148 -0
- package/dist/react/components/InteractiveHtmlEditor/InteractiveHtmlEditor.js.map +1 -0
- package/dist/react/components/RowMenu/RowMenu.d.ts +77 -0
- package/dist/react/components/RowMenu/RowMenu.d.ts.map +1 -0
- package/dist/react/components/RowMenu/RowMenu.hooks.d.ts +30 -0
- package/dist/react/components/RowMenu/RowMenu.hooks.d.ts.map +1 -0
- package/dist/react/components/RowMenu/RowMenu.hooks.js +154 -0
- package/dist/react/components/RowMenu/RowMenu.hooks.js.map +1 -0
- package/dist/react/components/RowMenu/RowMenu.js +46 -0
- package/dist/react/components/RowMenu/RowMenu.js.map +1 -0
- package/dist/react/components/RowMenu.d.ts +44 -0
- package/dist/react/components/RowMenu.d.ts.map +1 -0
- package/dist/react/components/RowMenu.js +149 -0
- package/dist/react/components/RowMenu.js.map +1 -0
- package/dist/react/components/Sidebar.d.ts +128 -0
- package/dist/react/components/Sidebar.d.ts.map +1 -0
- package/dist/react/components/Sidebar.js +168 -0
- package/dist/react/components/Sidebar.js.map +1 -0
- package/dist/react/hooks/use-nav-sections.d.ts +50 -0
- package/dist/react/hooks/use-nav-sections.d.ts.map +1 -0
- package/dist/react/hooks/use-nav-sections.js +112 -0
- package/dist/react/hooks/use-nav-sections.js.map +1 -0
- package/dist/react/hooks/use-sidebar-rail.d.ts +39 -0
- package/dist/react/hooks/use-sidebar-rail.d.ts.map +1 -0
- package/dist/react/hooks/use-sidebar-rail.js +93 -0
- package/dist/react/hooks/use-sidebar-rail.js.map +1 -0
- package/dist/react/index.d.ts +53 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +53 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/types.d.ts +28 -0
- package/dist/react/types.d.ts.map +1 -0
- package/dist/react/types.js +23 -0
- package/dist/react/types.js.map +1 -0
- package/dist/server/composio/bounded-data.d.ts +36 -0
- package/dist/server/composio/bounded-data.d.ts.map +1 -0
- package/dist/server/composio/bounded-data.js +181 -0
- package/dist/server/composio/bounded-data.js.map +1 -0
- package/dist/server/composio/catalog.d.ts +147 -0
- package/dist/server/composio/catalog.d.ts.map +1 -0
- package/dist/server/composio/catalog.js +126 -0
- package/dist/server/composio/catalog.js.map +1 -0
- package/dist/server/composio/composio-config.d.ts +42 -0
- package/dist/server/composio/composio-config.d.ts.map +1 -0
- package/dist/server/composio/composio-config.js +145 -0
- package/dist/server/composio/composio-config.js.map +1 -0
- package/dist/server/composio/composio-descriptions.d.ts +16 -0
- package/dist/server/composio/composio-descriptions.d.ts.map +1 -0
- package/dist/server/composio/composio-descriptions.js +766 -0
- package/dist/server/composio/composio-descriptions.js.map +1 -0
- package/dist/server/composio/composio.d.ts +364 -0
- package/dist/server/composio/composio.d.ts.map +1 -0
- package/dist/server/composio/composio.js +1902 -0
- package/dist/server/composio/composio.js.map +1 -0
- package/dist/server/composio/errors.d.ts +15 -0
- package/dist/server/composio/errors.d.ts.map +1 -0
- package/dist/server/composio/errors.js +16 -0
- package/dist/server/composio/errors.js.map +1 -0
- package/dist/server/composio/file-lock.d.ts +13 -0
- package/dist/server/composio/file-lock.d.ts.map +1 -0
- package/dist/server/composio/file-lock.js +92 -0
- package/dist/server/composio/file-lock.js.map +1 -0
- package/dist/server/composio/index.d.ts +18 -0
- package/dist/server/composio/index.d.ts.map +1 -0
- package/dist/server/composio/index.js +7 -0
- package/dist/server/composio/index.js.map +1 -0
- package/dist/server/composio/json-schema.d.ts +93 -0
- package/dist/server/composio/json-schema.d.ts.map +1 -0
- package/dist/server/composio/json-schema.js +498 -0
- package/dist/server/composio/json-schema.js.map +1 -0
- package/dist/server/composio/output-protection.d.ts +32 -0
- package/dist/server/composio/output-protection.d.ts.map +1 -0
- package/dist/server/composio/output-protection.js +105 -0
- package/dist/server/composio/output-protection.js.map +1 -0
- package/dist/server/composio/service.d.ts +181 -0
- package/dist/server/composio/service.d.ts.map +1 -0
- package/dist/server/composio/service.js +758 -0
- package/dist/server/composio/service.js.map +1 -0
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +15 -0
- package/dist/server/index.js.map +1 -0
- package/package.json +92 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
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
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for describing the origin of the Work and
|
|
141
|
+
reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Support. While redistributing the Work or
|
|
166
|
+
Derivative Works thereof, You may choose to offer, and charge a
|
|
167
|
+
fee for, acceptance of support, warranty, indemnity, or other
|
|
168
|
+
liability obligations and/or rights consistent with this License.
|
|
169
|
+
However, in accepting such obligations, You may act only on Your
|
|
170
|
+
own behalf and on Your sole responsibility, not on behalf of any
|
|
171
|
+
other Contributor, and only if You agree to indemnify, defend,
|
|
172
|
+
and hold each Contributor harmless for any liability incurred by,
|
|
173
|
+
or claims asserted against, such Contributor by reason of your
|
|
174
|
+
accepting any such warranty or support.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2026 Open Design contributors
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# `@jini-ai/admin`
|
|
2
|
+
|
|
3
|
+
A composable admin surface for Jini-hosted products. A host picks the panels it wants, wires the
|
|
4
|
+
ports those panels need, and gets a working admin — sidebar, routing, and agent-navigation
|
|
5
|
+
allowlist all derived from one declaration.
|
|
6
|
+
|
|
7
|
+
Extracted from the reference implementation's admin SPA, which had grown a 1,548-line API client
|
|
8
|
+
with 134 methods in a single object and defined every section across three files that had to be
|
|
9
|
+
kept in sync by hand.
|
|
10
|
+
|
|
11
|
+
## Layers
|
|
12
|
+
|
|
13
|
+
Import only what you need. `sideEffects: false` plus per-layer subpaths means an unused layer is
|
|
14
|
+
not in your bundle.
|
|
15
|
+
|
|
16
|
+
| Subpath | Contains | Needs |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| `@jini-ai/admin/core` | contracts, panel registry, route matching, transport, ports | nothing |
|
|
19
|
+
| `@jini-ai/admin/browser` | `window`-bound navigation, link interception | a DOM |
|
|
20
|
+
| `@jini-ai/admin/server` | Composio integration: catalog, OAuth, tool execution | Node.js |
|
|
21
|
+
| `@jini-ai/admin/react` *(not built yet)* | `<AdminShell>`, primitives, panels | React (optional peer) |
|
|
22
|
+
|
|
23
|
+
`/core` is the layer a panel author codes against: no React, no DOM, no I/O. That boundary is
|
|
24
|
+
enforced at runtime — this package's vitest config runs `src/core/**` without a jsdom environment,
|
|
25
|
+
so a `window` reference in core fails loudly instead of passing quietly.
|
|
26
|
+
|
|
27
|
+
React and react-dom are **optional** peer dependencies (`peerDependenciesMeta`), so a consumer
|
|
28
|
+
importing only `/core` is not asked to install them.
|
|
29
|
+
|
|
30
|
+
## A panel
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import type { AdminPanel } from '@jini-ai/admin/core';
|
|
34
|
+
|
|
35
|
+
export const usersPanel: AdminPanel<() => ReactNode> = {
|
|
36
|
+
id: 'users',
|
|
37
|
+
render: () => <Users />,
|
|
38
|
+
nav: { label: 'Users', group: 'People', order: 1 },
|
|
39
|
+
requires: ['identity'], // dropped entirely if no identity port is wired
|
|
40
|
+
permissions: ['users.read'], // affordance only — never the authz boundary
|
|
41
|
+
agentReachable: true, // explicit opt-in; defaults to false
|
|
42
|
+
routes: [{ pattern: '/:userId', view: 'user-detail' }],
|
|
43
|
+
};
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Three properties carry decisions worth not re-deriving:
|
|
47
|
+
|
|
48
|
+
- **`nav` is optional.** A panel can be routable without a sidebar row (the reference
|
|
49
|
+
implementation's `appearance` and `settings-raw` panels both rely on this).
|
|
50
|
+
- **`agentReachable` defaults to `false` and must stay an explicit opt-in.** It is the allowlist
|
|
51
|
+
behind `page.navigate`-style capabilities. Deriving it from panel registration would make every
|
|
52
|
+
new screen agent-reachable as a side effect of existing, which inverts the point of an
|
|
53
|
+
allowlist. An AI generating a panel manifest cannot make itself reachable by omission.
|
|
54
|
+
- **`requires` is how a host composes.** You do not ship or omit panel *code*; you supply or
|
|
55
|
+
withhold the *ports* a panel names, and unmet panels vanish — no dead nav row, no route that
|
|
56
|
+
renders an error.
|
|
57
|
+
|
|
58
|
+
## Assembling a shell
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { resolvePanels, buildNav, buildAgentPageMap, matchRoute } from '@jini-ai/admin/core';
|
|
62
|
+
|
|
63
|
+
const mounted = resolvePanels(ALL_PANELS, { capabilities: wiredPorts, permissions: me.permissions });
|
|
64
|
+
const nav = buildNav(mounted);
|
|
65
|
+
const agentPages = buildAgentPageMap(mounted); // pass the RESOLVED set, never the raw one
|
|
66
|
+
const route = matchRoute('/users/u1', mounted);
|
|
67
|
+
// -> { panelId: 'users', view: 'user-detail', params: { userId: 'u1' }, query }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Route matching is registry-driven: a panel declares its own detail routes and the matcher is
|
|
71
|
+
generic. Unregistered paths return `panelId: null` so the shell can fall through to the dashboard,
|
|
72
|
+
matching the ported behaviour — a typo should look like a bad URL, not an empty screen.
|
|
73
|
+
|
|
74
|
+
## Adding your own routes alongside the shipped ones
|
|
75
|
+
|
|
76
|
+
Every route group is `(transport) => port`. Jini's and yours are the same shape, so they compose
|
|
77
|
+
into one client with one auth policy, one error class, and one place to add retries or tracing:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { createAdminClient, createHttpTransport } from '@jini-ai/admin/core';
|
|
81
|
+
|
|
82
|
+
const transport = createHttpTransport({ baseUrl: '/api/admin/v1' });
|
|
83
|
+
|
|
84
|
+
const client = createAdminClient(transport, {
|
|
85
|
+
identity: createIdentityRoutes, // shipped by @jini-ai/admin
|
|
86
|
+
media: createMediaRoutes, // shipped by @jini-ai/admin
|
|
87
|
+
posts: createHostPostRoutes, // yours, same signature
|
|
88
|
+
widgets: createHostWidgetRoutes, // yours
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
await client.identity.listUsers();
|
|
92
|
+
await client.posts.list();
|
|
93
|
+
await client.transport.request('/one-off'); // escape hatch for un-wrapped routes
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`AdminTransport` is an interface rather than a bare function so a host can supply a non-HTTP
|
|
97
|
+
implementation — an in-process direct dispatch for a multi-instance runner, or a fixture-returning
|
|
98
|
+
fake in tests — without any route group knowing.
|
|
99
|
+
|
|
100
|
+
## Errors
|
|
101
|
+
|
|
102
|
+
Route groups throw `AdminApiError` (`status`, `code`, raw `body`). There is deliberately **no**
|
|
103
|
+
shared code-to-message table: the same `code` means genuinely different things in different
|
|
104
|
+
domains, and a shared table could only pick one. `describeApiError` is the base case only; panels
|
|
105
|
+
layer their own per-code copy on top and fall through to it.
|
|
106
|
+
|
|
107
|
+
## Not a security boundary
|
|
108
|
+
|
|
109
|
+
`hasPermission` and a panel's `permissions` decide whether a control renders. They never run on
|
|
110
|
+
the server. A bug here can only show or hide a control; it cannot grant or block the underlying
|
|
111
|
+
operation, because every mutation must be independently re-checked server-side. Do not import
|
|
112
|
+
these into server code.
|
|
113
|
+
|
|
114
|
+
## Composio integration has moved
|
|
115
|
+
|
|
116
|
+
`@jini-ai/admin/server` no longer exists. Composio started as its own standalone package
|
|
117
|
+
(`@jini-ai/composio`), was folded into this package as `./server` on 2026-08-01, and has since
|
|
118
|
+
moved back out — now `@jini-ai/integrations/composio`, one of two subpaths (alongside
|
|
119
|
+
`@jini-ai/integrations/media-providers`) under the single `@jini-ai/integrations` package
|
|
120
|
+
(`packages/integrations/`). See that package's own `README.md` and `src/composio/source-map.md`
|
|
121
|
+
for full provenance. Import it directly rather than through `@jini-ai/admin`.
|
|
122
|
+
|
|
123
|
+
## Before writing a panel: check `@jini-ai/ui-core` first
|
|
124
|
+
|
|
125
|
+
`@jini-ai/ui-core` already models several domains an admin panel would otherwise re-derive —
|
|
126
|
+
`execution`, `integrations`, `connectors`, `media-providers`, `notifications`, `appearance`. Reuse
|
|
127
|
+
its ports and rules rather than defining a second (or third) version. See that package's README
|
|
128
|
+
for the full map and for the `DetectedAgent` drift that motivated this rule.
|
|
129
|
+
|
|
130
|
+
Panels that reuse `ui-core` take the dependency in `/react/panels/*`. **`/core` stays
|
|
131
|
+
zero-dependency** — otherwise every consumer of the contracts layer pulls in 6,000+ lines of
|
|
132
|
+
unrelated domain features to get a type.
|
|
133
|
+
|
|
134
|
+
## Status
|
|
135
|
+
|
|
136
|
+
Slice 1: `/core` and `/browser`, 76 tests. `/server` (Composio, folded in 2026-08-01, moved back out
|
|
137
|
+
to `@jini-ai/integrations/composio`) no longer exists in this package. `/react` is not built yet,
|
|
138
|
+
and of the twelve planned ports only `AdminIdentityPort` is specified.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file `@jini-ai/admin/browser` — DOM-bound helpers. No React.
|
|
3
|
+
*
|
|
4
|
+
* Split from `/core` so the universal half stays testable and reusable without a DOM. See
|
|
5
|
+
* `navigation.ts`'s header.
|
|
6
|
+
*/
|
|
7
|
+
export { NAVIGATION_EVENT, installInternalLinkInterceptor, navigate, readRoutePath, subscribeToRoute, } from './navigation.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,gBAAgB,EAChB,8BAA8B,EAC9B,QAAQ,EACR,aAAa,EACb,gBAAgB,GACjB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file `@jini-ai/admin/browser` — DOM-bound helpers. No React.
|
|
3
|
+
*
|
|
4
|
+
* Split from `/core` so the universal half stays testable and reusable without a DOM. See
|
|
5
|
+
* `navigation.ts`'s header.
|
|
6
|
+
*/
|
|
7
|
+
export { NAVIGATION_EVENT, installInternalLinkInterceptor, navigate, readRoutePath, subscribeToRoute, } from './navigation.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,gBAAgB,EAChB,8BAA8B,EAC9B,QAAQ,EACR,aAAa,EACb,gBAAgB,GACjB,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file `window`-bound navigation. DOM, but no React.
|
|
3
|
+
*
|
|
4
|
+
* Ported from the reference implementation's `lib/router.ts`. Separated from `core/routing` because that module must stay
|
|
5
|
+
* universal — a Vue consumer, an SSR pass, or a test asserting route rules should not need a DOM.
|
|
6
|
+
* Everything here genuinely touches `window`; everything that does not stayed in core.
|
|
7
|
+
*
|
|
8
|
+
* This is not a fourth architectural layer so much as an honest home for four functions. It
|
|
9
|
+
* follows the `src/browser/` split `@jini-ai/ui` already uses.
|
|
10
|
+
*/
|
|
11
|
+
/** Fires on `navigate()`. `pushState` does not emit `popstate`, so subscribers need this too. */
|
|
12
|
+
export declare const NAVIGATION_EVENT = "jini:admin-navigate";
|
|
13
|
+
/** The current route path, read from the address bar. */
|
|
14
|
+
export declare function readRoutePath(base?: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Navigates without a page load.
|
|
17
|
+
*
|
|
18
|
+
* Takes a *route path*, not a URL — passing `/admin/settings` here would produce
|
|
19
|
+
* `/admin/admin/settings`, which is exactly the class of mistake `adminHref` prevents.
|
|
20
|
+
*/
|
|
21
|
+
export declare function navigate(routePath: string, options?: {
|
|
22
|
+
readonly replace?: boolean;
|
|
23
|
+
readonly base?: string;
|
|
24
|
+
}): void;
|
|
25
|
+
/**
|
|
26
|
+
* Turns clicks on internal `<a href="/admin/...">` links into SPA navigations.
|
|
27
|
+
*
|
|
28
|
+
* A document-level listener rather than a `<Link>` component, and deliberately so: panel markup
|
|
29
|
+
* should stay plain anchors, because they are real URLs that middle-click, cmd-click and "copy
|
|
30
|
+
* link address" should all treat normally. Intercepting only the plain-left-click case preserves
|
|
31
|
+
* every one of those behaviours for free, where a `<Link>` component would have to re-implement
|
|
32
|
+
* them.
|
|
33
|
+
*
|
|
34
|
+
* @returns a teardown function.
|
|
35
|
+
*/
|
|
36
|
+
export declare function installInternalLinkInterceptor(base?: string): () => void;
|
|
37
|
+
/** Subscribes to route changes from both `popstate` and programmatic `navigate()`. */
|
|
38
|
+
export declare function subscribeToRoute(onChange: () => void): () => void;
|
|
39
|
+
//# sourceMappingURL=navigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../src/browser/navigation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,iGAAiG;AACjG,eAAO,MAAM,gBAAgB,wBAAwB,CAAC;AAEtD,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,IAAI,GAAE,MAA2B,GAAG,MAAM,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GACnE,IAAI,CA8BN;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,GAAE,MAA2B,GAAG,MAAM,IAAI,CAiC5F;AAED,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAOjE"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file `window`-bound navigation. DOM, but no React.
|
|
3
|
+
*
|
|
4
|
+
* Ported from the reference implementation's `lib/router.ts`. Separated from `core/routing` because that module must stay
|
|
5
|
+
* universal — a Vue consumer, an SSR pass, or a test asserting route rules should not need a DOM.
|
|
6
|
+
* Everything here genuinely touches `window`; everything that does not stayed in core.
|
|
7
|
+
*
|
|
8
|
+
* This is not a fourth architectural layer so much as an honest home for four functions. It
|
|
9
|
+
* follows the `src/browser/` split `@jini-ai/ui` already uses.
|
|
10
|
+
*/
|
|
11
|
+
import { DEFAULT_ADMIN_BASE, adminHref, currentRoutePath, stripTrailingSlash } from '../core/routing/rules.js';
|
|
12
|
+
/** Fires on `navigate()`. `pushState` does not emit `popstate`, so subscribers need this too. */
|
|
13
|
+
export const NAVIGATION_EVENT = 'jini:admin-navigate';
|
|
14
|
+
/** The current route path, read from the address bar. */
|
|
15
|
+
export function readRoutePath(base = DEFAULT_ADMIN_BASE) {
|
|
16
|
+
return currentRoutePath(window.location.pathname, base);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Navigates without a page load.
|
|
20
|
+
*
|
|
21
|
+
* Takes a *route path*, not a URL — passing `/admin/settings` here would produce
|
|
22
|
+
* `/admin/admin/settings`, which is exactly the class of mistake `adminHref` prevents.
|
|
23
|
+
*/
|
|
24
|
+
export function navigate(routePath, options = {}) {
|
|
25
|
+
const base = options.base ?? DEFAULT_ADMIN_BASE;
|
|
26
|
+
const url = adminHref(routePath, base);
|
|
27
|
+
/*
|
|
28
|
+
* Navigating to where you already are is a no-op, not a history entry. Without this, clicking
|
|
29
|
+
* the already-active sidebar link five times pushes five identical entries and Back appears
|
|
30
|
+
* stuck on the same screen.
|
|
31
|
+
*
|
|
32
|
+
* Both sides go through `URL` before comparing rather than string-matching. `pushState` stores a
|
|
33
|
+
* *normalized* URL, so a path containing anything the browser percent-encodes (a space, any
|
|
34
|
+
* non-ASCII character) comes back out of `location.pathname` in a different spelling than
|
|
35
|
+
* `adminHref` produced — `/admin/collections/my recipe` vs `/admin/collections/my%20recipe`.
|
|
36
|
+
* Comparing raw strings there silently fails to match and pushes the duplicate anyway, which is
|
|
37
|
+
* the exact bug this guard exists to prevent.
|
|
38
|
+
*
|
|
39
|
+
* Trailing slash is normalized away because the matcher drops empty segments, so `/settings/`
|
|
40
|
+
* and `/settings` are the same screen. Query and hash are compared in full: a
|
|
41
|
+
* same-path/different-query navigation is a real one.
|
|
42
|
+
*/
|
|
43
|
+
const target = new URL(url, window.location.href);
|
|
44
|
+
const isCurrent = stripTrailingSlash(target.pathname) === stripTrailingSlash(window.location.pathname) &&
|
|
45
|
+
target.search === window.location.search &&
|
|
46
|
+
target.hash === window.location.hash;
|
|
47
|
+
if (isCurrent)
|
|
48
|
+
return;
|
|
49
|
+
if (options.replace)
|
|
50
|
+
window.history.replaceState(null, '', url);
|
|
51
|
+
else
|
|
52
|
+
window.history.pushState(null, '', url);
|
|
53
|
+
window.dispatchEvent(new Event(NAVIGATION_EVENT));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Turns clicks on internal `<a href="/admin/...">` links into SPA navigations.
|
|
57
|
+
*
|
|
58
|
+
* A document-level listener rather than a `<Link>` component, and deliberately so: panel markup
|
|
59
|
+
* should stay plain anchors, because they are real URLs that middle-click, cmd-click and "copy
|
|
60
|
+
* link address" should all treat normally. Intercepting only the plain-left-click case preserves
|
|
61
|
+
* every one of those behaviours for free, where a `<Link>` component would have to re-implement
|
|
62
|
+
* them.
|
|
63
|
+
*
|
|
64
|
+
* @returns a teardown function.
|
|
65
|
+
*/
|
|
66
|
+
export function installInternalLinkInterceptor(base = DEFAULT_ADMIN_BASE) {
|
|
67
|
+
const onClick = (event) => {
|
|
68
|
+
// Anything but an unmodified primary click is the browser's to handle: cmd/ctrl-click opens a
|
|
69
|
+
// tab, shift-click a window, alt-click downloads.
|
|
70
|
+
if (event.defaultPrevented)
|
|
71
|
+
return;
|
|
72
|
+
if (event.button !== 0)
|
|
73
|
+
return;
|
|
74
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
|
|
75
|
+
return;
|
|
76
|
+
const anchor = event.target?.closest?.('a');
|
|
77
|
+
if (!anchor)
|
|
78
|
+
return;
|
|
79
|
+
if (anchor.hasAttribute('download'))
|
|
80
|
+
return;
|
|
81
|
+
// An explicit target (`_blank`, a frame name) is an explicit request not to navigate in place.
|
|
82
|
+
const target = anchor.getAttribute('target');
|
|
83
|
+
if (target && target !== '_self')
|
|
84
|
+
return;
|
|
85
|
+
const href = anchor.getAttribute('href');
|
|
86
|
+
if (!href || href.startsWith('#'))
|
|
87
|
+
return;
|
|
88
|
+
// `anchor.href` is the resolved absolute form, which is what makes relative hrefs and
|
|
89
|
+
// cross-origin links both fall out correctly.
|
|
90
|
+
const url = new URL(anchor.href, window.location.href);
|
|
91
|
+
if (url.origin !== window.location.origin)
|
|
92
|
+
return;
|
|
93
|
+
if (url.pathname !== base && !url.pathname.startsWith(`${base}/`))
|
|
94
|
+
return;
|
|
95
|
+
event.preventDefault();
|
|
96
|
+
// `url.hash` is carried through: an in-page fragment (`/admin/settings#seo-defaults`) is not a
|
|
97
|
+
// routing concern, but dropping it silently loses the anchor. It never reaches the matcher —
|
|
98
|
+
// the route snapshot is path + query only — so preserving it cannot affect routing.
|
|
99
|
+
navigate(`${currentRoutePath(url.pathname, base)}${url.search}${url.hash}`, { base });
|
|
100
|
+
};
|
|
101
|
+
document.addEventListener('click', onClick);
|
|
102
|
+
return () => document.removeEventListener('click', onClick);
|
|
103
|
+
}
|
|
104
|
+
/** Subscribes to route changes from both `popstate` and programmatic `navigate()`. */
|
|
105
|
+
export function subscribeToRoute(onChange) {
|
|
106
|
+
window.addEventListener('popstate', onChange);
|
|
107
|
+
window.addEventListener(NAVIGATION_EVENT, onChange);
|
|
108
|
+
return () => {
|
|
109
|
+
window.removeEventListener('popstate', onChange);
|
|
110
|
+
window.removeEventListener(NAVIGATION_EVENT, onChange);
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=navigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/browser/navigation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The plan -> confirm -> execute protocol for destructive operations.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this is in core rather than in the panels that use it
|
|
5
|
+
*
|
|
6
|
+
* The reference implementation independently grew this same three-step shape in three unrelated places — database
|
|
7
|
+
* forward-migration (`planMigrateForward`/`confirmMigrateForward`/`executeMigrateForward`),
|
|
8
|
+
* point-in-time restore (`planRestore`/`confirmRestore`/`executeRestore`), and taxonomy term
|
|
9
|
+
* merge (`planMergeTerm`/`confirmMergeTerm`/`executeMergeTerm`) — sharing `GatedPlanResult<T>`
|
|
10
|
+
* and `GatedConfirmResult` types. Three independent arrivals at one shape is the signal that it
|
|
11
|
+
* is a protocol, not a coincidence, and any product doing irreversible operator actions will
|
|
12
|
+
* need it.
|
|
13
|
+
*
|
|
14
|
+
* ## What the three steps are for
|
|
15
|
+
*
|
|
16
|
+
* - **plan** is read-only and idempotent. It computes what *would* happen and returns a token.
|
|
17
|
+
* Safe to call on render; safe to call twice.
|
|
18
|
+
* - **confirm** records that the operator saw the plan. Separate from execute so the UI can show
|
|
19
|
+
* consequences the operator has to acknowledge, and so a stale plan (the world changed between
|
|
20
|
+
* plan and execute) can be rejected here rather than half-applied.
|
|
21
|
+
* - **execute** does the thing. Requires the token from confirm.
|
|
22
|
+
*
|
|
23
|
+
* The token is what makes this more than a confirmation dialog: it binds the execute call to a
|
|
24
|
+
* specific computed plan, so an operator cannot approve a small change and have a large one run.
|
|
25
|
+
*
|
|
26
|
+
* ## Warning: this protocol promises reversibility it cannot itself deliver
|
|
27
|
+
*
|
|
28
|
+
* A hard-won rule from the reference implementation's admin UX audit: **never promise an undo the
|
|
29
|
+
* product cannot deliver.** A `reversible: true` plan means the *backend* claims a revert path
|
|
30
|
+
* exists — it does not mean the admin has a reachable UI for it. The reference implementation's
|
|
31
|
+
* post/page delete is a genuine server-side
|
|
32
|
+
* soft delete with no restore path reachable from the admin. A panel rendering "you can undo
|
|
33
|
+
* this" off this flag alone would be lying to the operator. Check that the revert is reachable,
|
|
34
|
+
* not merely that it exists.
|
|
35
|
+
*/
|
|
36
|
+
/** What `plan` returns: the computed consequences, plus the token that binds them to `execute`. */
|
|
37
|
+
export interface GatedPlanResult<TDetails = unknown> {
|
|
38
|
+
/** Opaque; pass back to `confirm`. Panels must not parse or construct these. */
|
|
39
|
+
readonly token: string;
|
|
40
|
+
/** Operation-specific description of what would happen — row counts, affected ids, warnings. */
|
|
41
|
+
readonly details: TDetails;
|
|
42
|
+
/** Whether the backend has a revert path. **Not** a claim that the admin exposes one — see the
|
|
43
|
+
* file header. */
|
|
44
|
+
readonly reversible?: boolean;
|
|
45
|
+
/** Operator-facing consequences to display before confirming. Rendered as-is; the backend owns
|
|
46
|
+
* the wording because it is the only side that knows the actual scope. */
|
|
47
|
+
readonly warnings?: readonly string[];
|
|
48
|
+
}
|
|
49
|
+
/** What `confirm` returns: the token `execute` requires. */
|
|
50
|
+
export interface GatedConfirmResult {
|
|
51
|
+
/** Distinct from the plan token. A backend may return the same value, but panels must pass
|
|
52
|
+
* through whatever they were given rather than reusing the plan's. */
|
|
53
|
+
readonly confirmToken: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* A gated operation, as a panel sees it.
|
|
57
|
+
*
|
|
58
|
+
* Route groups implementing this get a consistent three-call shape, which is what lets a shared
|
|
59
|
+
* confirmation component drive any of them without knowing the operation.
|
|
60
|
+
*
|
|
61
|
+
* ## Why `confirm`/`execute` take a type parameter rather than a bare token
|
|
62
|
+
*
|
|
63
|
+
* The first draft of this interface declared `confirm(token: string)` and
|
|
64
|
+
* `execute(confirmToken: string)`, inferred from method names alone. Reading the actual reference
|
|
65
|
+
* signatures showed that only one of the three real triads fits that shape:
|
|
66
|
+
*
|
|
67
|
+
* - **migrate-forward** — confirm and execute each take only the token. Fits.
|
|
68
|
+
* - **restore** — `confirm` needs `{planId, planHash, disclosureAcknowledged}` and `execute` needs
|
|
69
|
+
* `{confirmationToken, restorePointId}`. Does not fit.
|
|
70
|
+
*
|
|
71
|
+
* The instructive one is restore's `disclosureAcknowledged`. It says this protocol is not merely a
|
|
72
|
+
* two-step token handshake, it is *recorded informed consent* — the operator was shown what would
|
|
73
|
+
* be lost and said yes. That is the most destructive operation in the product, so an interface that
|
|
74
|
+
* excludes it is describing the easy case and abandoning the one that matters. Widened rather than
|
|
75
|
+
* documented around.
|
|
76
|
+
*
|
|
77
|
+
* The extra parameters default to `string`, so the simple case still reads
|
|
78
|
+
* `GatedOperation<PlanInput, Details, Result>` with no change.
|
|
79
|
+
*/
|
|
80
|
+
export interface GatedOperation<TPlanInput, TDetails, TResult, TConfirmInput = string, TExecuteInput = string> {
|
|
81
|
+
plan(input: TPlanInput): Promise<GatedPlanResult<TDetails>>;
|
|
82
|
+
/** Takes the plan's `token`, either bare or as one field of an operation-specific object. */
|
|
83
|
+
confirm(input: TConfirmInput): Promise<GatedConfirmResult>;
|
|
84
|
+
/** Takes the confirm step's `confirmToken`, bare or within an operation-specific object. */
|
|
85
|
+
execute(input: TExecuteInput): Promise<TResult>;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/gated/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,mGAAmG;AACnG,MAAM,WAAW,eAAe,CAAC,QAAQ,GAAG,OAAO;IACjD,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC3B;uBACmB;IACnB,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B;+EAC2E;IAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC;2EACuE;IACvE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,cAAc,CAC7B,UAAU,EACV,QAAQ,EACR,OAAO,EACP,aAAa,GAAG,MAAM,EACtB,aAAa,GAAG,MAAM;IAEtB,IAAI,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5D,6FAA6F;IAC7F,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC3D,4FAA4F;IAC5F,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACjD"}
|