appflare 0.2.46 → 0.2.48
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/Documentation.md +898 -898
- package/cli/commands/index.ts +247 -247
- package/cli/generate.ts +360 -360
- package/cli/index.ts +120 -120
- package/cli/load-config.ts +184 -184
- package/cli/schema-compiler.ts +1366 -1366
- package/cli/templates/auth/README.md +156 -156
- package/cli/templates/auth/config.ts +61 -61
- package/cli/templates/auth/route-config.ts +1 -1
- package/cli/templates/auth/route-handler.ts +1 -1
- package/cli/templates/auth/route-request-utils.ts +5 -5
- package/cli/templates/auth/route.config.ts +18 -18
- package/cli/templates/auth/route.handler.ts +18 -18
- package/cli/templates/auth/route.request-utils.ts +55 -55
- package/cli/templates/auth/route.ts +14 -14
- package/cli/templates/core/README.md +266 -266
- package/cli/templates/core/app-creation.ts +19 -19
- package/cli/templates/core/client/appflare.ts +112 -112
- package/cli/templates/core/client/handlers/index.ts +763 -763
- package/cli/templates/core/client/handlers.ts +1 -1
- package/cli/templates/core/client/index.ts +7 -7
- package/cli/templates/core/client/storage.ts +195 -195
- package/cli/templates/core/client/types.ts +187 -187
- package/cli/templates/core/client-modules/appflare.ts +1 -1
- package/cli/templates/core/client-modules/handlers.ts +1 -1
- package/cli/templates/core/client-modules/index.ts +1 -1
- package/cli/templates/core/client-modules/storage.ts +1 -1
- package/cli/templates/core/client-modules/types.ts +1 -1
- package/cli/templates/core/client.artifacts.ts +39 -39
- package/cli/templates/core/client.ts +4 -4
- package/cli/templates/core/drizzle.ts +15 -15
- package/cli/templates/core/export.ts +14 -14
- package/cli/templates/core/handlers.route.ts +24 -24
- package/cli/templates/core/handlers.ts +1 -1
- package/cli/templates/core/imports.ts +9 -9
- package/cli/templates/core/server.ts +38 -38
- package/cli/templates/core/types.ts +6 -6
- package/cli/templates/core/wrangler.ts +109 -109
- package/cli/templates/dashboard/builders/functions/index.ts +17 -17
- package/cli/templates/dashboard/builders/functions/render-page/header.ts +20 -20
- package/cli/templates/dashboard/builders/functions/render-page/index.ts +33 -33
- package/cli/templates/dashboard/builders/functions/render-page/request-panel.ts +271 -271
- package/cli/templates/dashboard/builders/functions/render-page/result-panel.ts +85 -85
- package/cli/templates/dashboard/builders/functions/render-page/scripts.ts +703 -703
- package/cli/templates/dashboard/builders/functions/tree-builder.ts +47 -47
- package/cli/templates/dashboard/builders/navigation.ts +155 -155
- package/cli/templates/dashboard/builders/storage/index.ts +13 -13
- package/cli/templates/dashboard/builders/storage/routes/create-directory-route.ts +29 -29
- package/cli/templates/dashboard/builders/storage/routes/delete-route.ts +18 -18
- package/cli/templates/dashboard/builders/storage/routes/download-route.ts +23 -23
- package/cli/templates/dashboard/builders/storage/routes/index.ts +22 -22
- package/cli/templates/dashboard/builders/storage/routes/list-route.ts +25 -25
- package/cli/templates/dashboard/builders/storage/routes/preview-route.ts +21 -21
- package/cli/templates/dashboard/builders/storage/routes/upload-route.ts +21 -21
- package/cli/templates/dashboard/builders/storage/runtime/helpers.ts +72 -72
- package/cli/templates/dashboard/builders/storage/runtime/storage-page.ts +130 -130
- package/cli/templates/dashboard/builders/table-routes/common/drawer-panel.ts +27 -27
- package/cli/templates/dashboard/builders/table-routes/common/pagination.ts +30 -30
- package/cli/templates/dashboard/builders/table-routes/common/search-bar.ts +23 -23
- package/cli/templates/dashboard/builders/table-routes/fragments.ts +217 -217
- package/cli/templates/dashboard/builders/table-routes/helpers.ts +45 -45
- package/cli/templates/dashboard/builders/table-routes/index.ts +8 -8
- package/cli/templates/dashboard/builders/table-routes/table/actions-cell.ts +71 -71
- package/cli/templates/dashboard/builders/table-routes/table/get-route.ts +291 -291
- package/cli/templates/dashboard/builders/table-routes/table/index.ts +80 -80
- package/cli/templates/dashboard/builders/table-routes/table/post-routes.ts +163 -163
- package/cli/templates/dashboard/builders/table-routes/table-route.ts +7 -7
- package/cli/templates/dashboard/builders/table-routes/users/get-route.ts +69 -69
- package/cli/templates/dashboard/builders/table-routes/users/html/modals.ts +57 -57
- package/cli/templates/dashboard/builders/table-routes/users/html/page.ts +27 -27
- package/cli/templates/dashboard/builders/table-routes/users/html/table.ts +128 -128
- package/cli/templates/dashboard/builders/table-routes/users/index.ts +32 -32
- package/cli/templates/dashboard/builders/table-routes/users/post-routes.ts +150 -150
- package/cli/templates/dashboard/builders/table-routes/users/redirect.ts +14 -14
- package/cli/templates/dashboard/builders/table-routes/users-route.ts +10 -10
- package/cli/templates/dashboard/components/dashboard-home.ts +23 -23
- package/cli/templates/dashboard/components/layout.ts +420 -420
- package/cli/templates/dashboard/components/login-page.ts +65 -65
- package/cli/templates/dashboard/index.ts +61 -61
- package/cli/templates/dashboard/types.ts +9 -9
- package/cli/templates/handlers/README.md +353 -353
- package/cli/templates/handlers/auth.ts +37 -37
- package/cli/templates/handlers/execution.ts +42 -42
- package/cli/templates/handlers/generators/context/context-creation.ts +101 -101
- package/cli/templates/handlers/generators/context/error-helpers.ts +11 -11
- package/cli/templates/handlers/generators/context/scheduler.ts +24 -24
- package/cli/templates/handlers/generators/context/storage-api.ts +82 -82
- package/cli/templates/handlers/generators/context/storage-helpers.ts +59 -59
- package/cli/templates/handlers/generators/context/types.ts +40 -40
- package/cli/templates/handlers/generators/context.ts +43 -43
- package/cli/templates/handlers/generators/execution.ts +15 -15
- package/cli/templates/handlers/generators/handlers.ts +14 -14
- package/cli/templates/handlers/generators/registration/modules/cron.ts +35 -26
- package/cli/templates/handlers/generators/registration/modules/realtime/auth.ts +75 -75
- package/cli/templates/handlers/generators/registration/modules/realtime/durable-object.ts +144 -144
- package/cli/templates/handlers/generators/registration/modules/realtime/index.ts +14 -14
- package/cli/templates/handlers/generators/registration/modules/realtime/publisher.ts +102 -102
- package/cli/templates/handlers/generators/registration/modules/realtime/routes.ts +164 -164
- package/cli/templates/handlers/generators/registration/modules/realtime/types.ts +30 -30
- package/cli/templates/handlers/generators/registration/modules/realtime/utils.ts +510 -510
- package/cli/templates/handlers/generators/registration/modules/scheduler.ts +65 -56
- package/cli/templates/handlers/generators/registration/modules/storage.ts +199 -199
- package/cli/templates/handlers/generators/registration/sections.ts +210 -210
- package/cli/templates/handlers/generators/types/context.ts +121 -121
- package/cli/templates/handlers/generators/types/core.ts +108 -106
- package/cli/templates/handlers/generators/types/operations.ts +135 -135
- package/cli/templates/handlers/generators/types/query-definitions/filter-and-where-types.ts +291 -291
- package/cli/templates/handlers/generators/types/query-definitions/query-api-types.ts +135 -135
- package/cli/templates/handlers/generators/types/query-definitions/query-helper-functions.ts +1382 -1382
- package/cli/templates/handlers/generators/types/query-definitions/schema-and-table-types.ts +278 -278
- package/cli/templates/handlers/generators/types/query-definitions.ts +13 -13
- package/cli/templates/handlers/generators/types/query-runtime/handled-error.ts +13 -13
- package/cli/templates/handlers/generators/types/query-runtime/runtime-aggregate-and-footer.ts +174 -174
- package/cli/templates/handlers/generators/types/query-runtime/runtime-read.ts +158 -157
- package/cli/templates/handlers/generators/types/query-runtime/runtime-setup.ts +45 -45
- package/cli/templates/handlers/generators/types/query-runtime/runtime-write.ts +958 -958
- package/cli/templates/handlers/generators/types/query-runtime.ts +15 -15
- package/cli/templates/handlers/index.ts +47 -47
- package/cli/templates/handlers/operations.ts +116 -116
- package/cli/templates/handlers/registration.ts +91 -91
- package/cli/templates/handlers/types.ts +17 -17
- package/cli/templates/handlers/utils.ts +48 -48
- package/cli/types.ts +110 -110
- package/cli/utils/handler-discovery.ts +501 -501
- package/cli/utils/json-utils.ts +24 -24
- package/cli/utils/path-utils.ts +19 -19
- package/cli/utils/schema-discovery.ts +399 -399
- package/dist/cli/index.js +43 -23
- package/dist/cli/index.mjs +43 -23
- package/dist/react/index.js +1 -1
- package/dist/react/index.mjs +1 -1
- package/index.ts +18 -18
- package/package.json +58 -58
- package/react/index.ts +5 -5
- package/react/use-infinite-query.ts +255 -255
- package/react/use-mutation.ts +89 -89
- package/react/use-query.ts +210 -210
- package/schema.ts +641 -641
- package/test-better-auth-hash.ts +2 -2
- package/tsconfig.json +6 -6
- package/tsup.config.ts +82 -82
|
@@ -1,271 +1,271 @@
|
|
|
1
|
-
import { DiscoveredArgField, DiscoveredHandlerOperation } from "../../../../../utils/handler-discovery";
|
|
2
|
-
|
|
3
|
-
const fieldInputClass =
|
|
4
|
-
"input input-xs input-bordered font-mono flex-1 bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-lg border-base-200";
|
|
5
|
-
|
|
6
|
-
function renderObjectFieldInputs(fields: DiscoveredArgField[]): string {
|
|
7
|
-
return fields
|
|
8
|
-
.map((f) => {
|
|
9
|
-
const badge =
|
|
10
|
-
f.type !== "unknown"
|
|
11
|
-
? `<span class="badge badge-xs badge-ghost font-mono opacity-25 ml-1">${f.type}</span>`
|
|
12
|
-
: "";
|
|
13
|
-
|
|
14
|
-
if (f.type === "boolean") {
|
|
15
|
-
return `
|
|
16
|
-
<div class="flex items-center gap-2">
|
|
17
|
-
<input
|
|
18
|
-
type="checkbox"
|
|
19
|
-
data-obj-key="${f.name}"
|
|
20
|
-
data-obj-field-type="boolean"
|
|
21
|
-
class="checkbox checkbox-xs checkbox-primary shrink-0"
|
|
22
|
-
${f.defaultValue === "true" ? "checked" : ""}
|
|
23
|
-
/>
|
|
24
|
-
<span class="text-[10px] font-mono opacity-50">${f.name}${badge}</span>
|
|
25
|
-
</div>`;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const inputType =
|
|
29
|
-
f.type === "number" ? "number" : f.type === "date" ? "datetime-local" : "text";
|
|
30
|
-
|
|
31
|
-
return `
|
|
32
|
-
<div class="flex items-center gap-2">
|
|
33
|
-
<span class="text-[10px] font-mono opacity-50 w-20 shrink-0 truncate" title="${f.name}">${f.name}${badge}</span>
|
|
34
|
-
<input
|
|
35
|
-
type="${inputType}"
|
|
36
|
-
data-obj-key="${f.name}"
|
|
37
|
-
data-obj-field-type="${f.type}"
|
|
38
|
-
placeholder="${f.defaultValue ?? ""}"
|
|
39
|
-
value="${f.defaultValue ?? ""}"
|
|
40
|
-
class="${fieldInputClass}"
|
|
41
|
-
/>
|
|
42
|
-
</div>`;
|
|
43
|
-
})
|
|
44
|
-
.join("\n");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function renderArgRows(h: DiscoveredHandlerOperation): string {
|
|
48
|
-
const fields = h.args ?? [];
|
|
49
|
-
if (fields.length === 0) {
|
|
50
|
-
return `
|
|
51
|
-
<div class="text-[11px] opacity-30 italic py-2">No arguments defined for this ${h.kind}.</div>
|
|
52
|
-
`;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const inputClass =
|
|
56
|
-
"input input-sm input-bordered font-mono w-full bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-xl border-base-200";
|
|
57
|
-
|
|
58
|
-
return fields
|
|
59
|
-
.map((field) => {
|
|
60
|
-
const label = `${field.name}${field.optional ? "" : " *"}`;
|
|
61
|
-
const badge =
|
|
62
|
-
field.type !== "unknown"
|
|
63
|
-
? `<span class="badge badge-xs badge-ghost font-mono opacity-40 ml-1">${field.type}</span>`
|
|
64
|
-
: "";
|
|
65
|
-
const optionalAlt = field.optional
|
|
66
|
-
? '<span class="label-text-alt text-[10px] opacity-30 italic">optional</span>'
|
|
67
|
-
: "";
|
|
68
|
-
const labelRow = `
|
|
69
|
-
<label class="label py-0.5">
|
|
70
|
-
<span class="label-text text-[11px] font-mono font-semibold">${label}${badge}</span>
|
|
71
|
-
${optionalAlt}
|
|
72
|
-
</label>`;
|
|
73
|
-
|
|
74
|
-
if (field.type === "boolean") {
|
|
75
|
-
return `
|
|
76
|
-
<div class="flex items-center gap-3 py-1">
|
|
77
|
-
<input
|
|
78
|
-
type="checkbox"
|
|
79
|
-
data-arg-key="${field.name}"
|
|
80
|
-
data-arg-type="boolean"
|
|
81
|
-
class="checkbox checkbox-sm checkbox-primary"
|
|
82
|
-
${field.defaultValue === "true" ? "checked" : ""}
|
|
83
|
-
/>
|
|
84
|
-
<span class="text-sm font-mono opacity-70">${field.name}${badge}</span>
|
|
85
|
-
${field.optional ? '<span class="text-[10px] opacity-30 italic ml-auto">optional</span>' : ""}
|
|
86
|
-
</div>`;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (field.type === "object") {
|
|
90
|
-
if (field.fields && field.fields.length > 0) {
|
|
91
|
-
return `
|
|
92
|
-
<div class="form-control">
|
|
93
|
-
${labelRow}
|
|
94
|
-
<div
|
|
95
|
-
data-arg-key="${field.name}"
|
|
96
|
-
data-arg-type="object"
|
|
97
|
-
class="border border-base-200 rounded-xl p-3 bg-base-200/20 flex flex-col gap-2"
|
|
98
|
-
>
|
|
99
|
-
${renderObjectFieldInputs(field.fields)}
|
|
100
|
-
</div>
|
|
101
|
-
</div>`;
|
|
102
|
-
}
|
|
103
|
-
// Fallback when schema isn't statically known
|
|
104
|
-
return `
|
|
105
|
-
<div class="form-control">
|
|
106
|
-
${labelRow}
|
|
107
|
-
<textarea
|
|
108
|
-
data-arg-key="${field.name}"
|
|
109
|
-
data-arg-type="object"
|
|
110
|
-
placeholder="{}"
|
|
111
|
-
rows="4"
|
|
112
|
-
class="textarea textarea-sm textarea-bordered font-mono w-full bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-xl border-base-200 resize-y text-xs"
|
|
113
|
-
${!field.optional ? "required" : ""}
|
|
114
|
-
>${field.defaultValue ?? ""}</textarea>
|
|
115
|
-
</div>`;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (field.type === "array") {
|
|
119
|
-
const itemType = field.itemType ?? "string";
|
|
120
|
-
const itemFieldsJson = JSON.stringify(
|
|
121
|
-
(field.itemFields ?? []).map((f) => ({ name: f.name, type: f.type })),
|
|
122
|
-
);
|
|
123
|
-
return `
|
|
124
|
-
<div class="form-control">
|
|
125
|
-
${labelRow}
|
|
126
|
-
<div
|
|
127
|
-
data-arg-key="${field.name}"
|
|
128
|
-
data-arg-type="array"
|
|
129
|
-
data-item-type="${itemType}"
|
|
130
|
-
data-item-fields='${itemFieldsJson}'
|
|
131
|
-
class="flex flex-col gap-2"
|
|
132
|
-
></div>
|
|
133
|
-
<button
|
|
134
|
-
type="button"
|
|
135
|
-
onclick="addArrayItem('${field.name}')"
|
|
136
|
-
class="btn btn-xs btn-ghost gap-1 mt-1 self-start opacity-50 hover:opacity-100"
|
|
137
|
-
>
|
|
138
|
-
<iconify-icon icon="solar:add-circle-linear" width="12" height="12"></iconify-icon>
|
|
139
|
-
Add item
|
|
140
|
-
</button>
|
|
141
|
-
</div>`;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const inputType =
|
|
145
|
-
field.type === "number" ? "number" : field.type === "date" ? "datetime-local" : "text";
|
|
146
|
-
|
|
147
|
-
return `
|
|
148
|
-
<div class="form-control">
|
|
149
|
-
${labelRow}
|
|
150
|
-
<input
|
|
151
|
-
type="${inputType}"
|
|
152
|
-
placeholder="${field.defaultValue ?? ""}"
|
|
153
|
-
data-arg-key="${field.name}"
|
|
154
|
-
data-arg-type="${field.type}"
|
|
155
|
-
value="${field.defaultValue ?? ""}"
|
|
156
|
-
class="${inputClass}"
|
|
157
|
-
${!field.optional ? "required" : ""}
|
|
158
|
-
/>
|
|
159
|
-
</div>`;
|
|
160
|
-
})
|
|
161
|
-
.join("\n");
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function renderArgumentsSection(h: DiscoveredHandlerOperation): string {
|
|
165
|
-
return `
|
|
166
|
-
<div class="space-y-4">
|
|
167
|
-
<div class="flex items-center justify-between">
|
|
168
|
-
<div class="flex flex-col">
|
|
169
|
-
<span class="text-[11px] font-bold uppercase tracking-wider opacity-40">Arguments</span>
|
|
170
|
-
<span class="text-[10px] font-mono opacity-30">${h.kind}</span>
|
|
171
|
-
</div>
|
|
172
|
-
<label class="flex items-center gap-2 cursor-pointer select-none group" title="Enable realtime updates via WebSocket">
|
|
173
|
-
<span class="text-[10px] font-bold uppercase tracking-wider opacity-40 group-hover:opacity-70 transition-opacity">Realtime</span>
|
|
174
|
-
<input type="checkbox" id="realtime-toggle" class="toggle toggle-xs toggle-success" onchange="toggleRealtime(this.checked)" />
|
|
175
|
-
</label>
|
|
176
|
-
</div>
|
|
177
|
-
<div id="args-rows" class="flex flex-col gap-3">
|
|
178
|
-
${renderArgRows(h)}
|
|
179
|
-
</div>
|
|
180
|
-
<p class="text-[11px] opacity-30 mt-2 italic">Values are sent as ${h.kind === "query" ? "query string params" : "JSON request body"}.</p>
|
|
181
|
-
</div>
|
|
182
|
-
`;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function renderBearerTokenSection(): string {
|
|
186
|
-
return `
|
|
187
|
-
<div class="space-y-4">
|
|
188
|
-
<label class="text-[11px] font-bold uppercase tracking-wider opacity-40 block">Bearer Token <span class="font-normal normal-case">(optional)</span></label>
|
|
189
|
-
<div class="relative group">
|
|
190
|
-
<input
|
|
191
|
-
type="password"
|
|
192
|
-
name="token"
|
|
193
|
-
id="bearer-token-input"
|
|
194
|
-
class="input input-sm input-bordered font-mono text-sm w-full bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-xl border-base-200 pr-9"
|
|
195
|
-
placeholder="eyJhbGciOi..."
|
|
196
|
-
/>
|
|
197
|
-
<button type="button" onclick="toggleTokenVisibility()" class="absolute right-2.5 top-1/2 -translate-y-1/2 opacity-30 hover:opacity-70 transition-opacity">
|
|
198
|
-
<iconify-icon id="token-eye-icon" icon="solar:eye-linear" width="15" height="15"></iconify-icon>
|
|
199
|
-
</button>
|
|
200
|
-
</div>
|
|
201
|
-
<p class="text-[10px] opacity-30 italic">Token will be included in the Authorization header.</p>
|
|
202
|
-
</div>
|
|
203
|
-
`;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function renderCustomHeadersSection(): string {
|
|
207
|
-
return `
|
|
208
|
-
<div class="space-y-4">
|
|
209
|
-
<div class="flex items-center justify-between">
|
|
210
|
-
<span class="text-[11px] font-bold uppercase tracking-wider opacity-40">Custom Headers</span>
|
|
211
|
-
<button type="button" onclick="addHeaderRow()" class="btn btn-xs btn-ghost gap-1 opacity-50 hover:opacity-100">
|
|
212
|
-
<iconify-icon icon="solar:add-circle-linear" width="14" height="14"></iconify-icon>
|
|
213
|
-
Add
|
|
214
|
-
</button>
|
|
215
|
-
</div>
|
|
216
|
-
<div id="headers-rows" class="flex flex-col gap-2">
|
|
217
|
-
<!-- populated by addHeaderRow() -->
|
|
218
|
-
</div>
|
|
219
|
-
<p id="headers-error" class="text-[11px] text-error mt-1.5 hidden"></p>
|
|
220
|
-
</div>
|
|
221
|
-
`;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export function renderRequestPanel(h: DiscoveredHandlerOperation): string {
|
|
225
|
-
return `
|
|
226
|
-
<div class="card bg-base-100 border border-base-200 shadow-sm overflow-hidden flex flex-col h-full">
|
|
227
|
-
<div class="px-5 py-3 border-b border-base-200 bg-base-200/20 flex items-center justify-between flex-none">
|
|
228
|
-
<h3 class="text-xs font-bold uppercase tracking-widest opacity-40">Request</h3>
|
|
229
|
-
<iconify-icon icon="solar:settings-linear" width="16" height="16" class="opacity-30"></iconify-icon>
|
|
230
|
-
</div>
|
|
231
|
-
|
|
232
|
-
<div class="flex-1 overflow-hidden flex flex-col">
|
|
233
|
-
<form id="fn-form" onsubmit="return false" class="flex flex-col h-full">
|
|
234
|
-
<!-- Tabs Navigation -->
|
|
235
|
-
<div class="px-5 pt-4 flex-none">
|
|
236
|
-
<div role="tablist" class="tabs tabs-box bg-base-200/50 p-1 rounded-xl">
|
|
237
|
-
<a role="tab" id="req-tab-btn-args" class="tab tab-active !text-[10px] !font-bold uppercase tracking-wider h-8" onclick="switchRequestTab('args')">Args</a>
|
|
238
|
-
<a role="tab" id="req-tab-btn-auth" class="tab !text-[10px] !font-bold uppercase tracking-wider h-8" onclick="switchRequestTab('auth')">Auth</a>
|
|
239
|
-
<a role="tab" id="req-tab-btn-headers" class="tab !text-[10px] !font-bold uppercase tracking-wider h-8" onclick="switchRequestTab('headers')">Headers</a>
|
|
240
|
-
</div>
|
|
241
|
-
</div>
|
|
242
|
-
|
|
243
|
-
<!-- Tab Content -->
|
|
244
|
-
<div class="flex-1 overflow-y-auto">
|
|
245
|
-
<div id="request-tab-args" class="p-5">
|
|
246
|
-
${renderArgumentsSection(h)}
|
|
247
|
-
</div>
|
|
248
|
-
<div id="request-tab-auth" class="p-5 hidden">
|
|
249
|
-
${renderBearerTokenSection()}
|
|
250
|
-
</div>
|
|
251
|
-
<div id="request-tab-headers" class="p-5 hidden">
|
|
252
|
-
${renderCustomHeadersSection()}
|
|
253
|
-
</div>
|
|
254
|
-
</div>
|
|
255
|
-
|
|
256
|
-
<!-- Submit Button (Fixed at bottom) -->
|
|
257
|
-
<div class="p-5 border-t border-base-200 mt-auto bg-base-200/5">
|
|
258
|
-
<button
|
|
259
|
-
type="button"
|
|
260
|
-
onclick="executeFn()"
|
|
261
|
-
class="btn btn-primary w-full gap-2 rounded-xl shadow-lg shadow-primary/20 hover:shadow-xl hover:shadow-primary/30 transition-all font-semibold"
|
|
262
|
-
>
|
|
263
|
-
<iconify-icon icon="solar:play-bold" width="18" height="18"></iconify-icon>
|
|
264
|
-
Run ${h.kind}
|
|
265
|
-
</button>
|
|
266
|
-
</div>
|
|
267
|
-
</form>
|
|
268
|
-
</div>
|
|
269
|
-
</div>
|
|
270
|
-
`;
|
|
271
|
-
}
|
|
1
|
+
import { DiscoveredArgField, DiscoveredHandlerOperation } from "../../../../../utils/handler-discovery";
|
|
2
|
+
|
|
3
|
+
const fieldInputClass =
|
|
4
|
+
"input input-xs input-bordered font-mono flex-1 bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-lg border-base-200";
|
|
5
|
+
|
|
6
|
+
function renderObjectFieldInputs(fields: DiscoveredArgField[]): string {
|
|
7
|
+
return fields
|
|
8
|
+
.map((f) => {
|
|
9
|
+
const badge =
|
|
10
|
+
f.type !== "unknown"
|
|
11
|
+
? `<span class="badge badge-xs badge-ghost font-mono opacity-25 ml-1">${f.type}</span>`
|
|
12
|
+
: "";
|
|
13
|
+
|
|
14
|
+
if (f.type === "boolean") {
|
|
15
|
+
return `
|
|
16
|
+
<div class="flex items-center gap-2">
|
|
17
|
+
<input
|
|
18
|
+
type="checkbox"
|
|
19
|
+
data-obj-key="${f.name}"
|
|
20
|
+
data-obj-field-type="boolean"
|
|
21
|
+
class="checkbox checkbox-xs checkbox-primary shrink-0"
|
|
22
|
+
${f.defaultValue === "true" ? "checked" : ""}
|
|
23
|
+
/>
|
|
24
|
+
<span class="text-[10px] font-mono opacity-50">${f.name}${badge}</span>
|
|
25
|
+
</div>`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const inputType =
|
|
29
|
+
f.type === "number" ? "number" : f.type === "date" ? "datetime-local" : "text";
|
|
30
|
+
|
|
31
|
+
return `
|
|
32
|
+
<div class="flex items-center gap-2">
|
|
33
|
+
<span class="text-[10px] font-mono opacity-50 w-20 shrink-0 truncate" title="${f.name}">${f.name}${badge}</span>
|
|
34
|
+
<input
|
|
35
|
+
type="${inputType}"
|
|
36
|
+
data-obj-key="${f.name}"
|
|
37
|
+
data-obj-field-type="${f.type}"
|
|
38
|
+
placeholder="${f.defaultValue ?? ""}"
|
|
39
|
+
value="${f.defaultValue ?? ""}"
|
|
40
|
+
class="${fieldInputClass}"
|
|
41
|
+
/>
|
|
42
|
+
</div>`;
|
|
43
|
+
})
|
|
44
|
+
.join("\n");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function renderArgRows(h: DiscoveredHandlerOperation): string {
|
|
48
|
+
const fields = h.args ?? [];
|
|
49
|
+
if (fields.length === 0) {
|
|
50
|
+
return `
|
|
51
|
+
<div class="text-[11px] opacity-30 italic py-2">No arguments defined for this ${h.kind}.</div>
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const inputClass =
|
|
56
|
+
"input input-sm input-bordered font-mono w-full bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-xl border-base-200";
|
|
57
|
+
|
|
58
|
+
return fields
|
|
59
|
+
.map((field) => {
|
|
60
|
+
const label = `${field.name}${field.optional ? "" : " *"}`;
|
|
61
|
+
const badge =
|
|
62
|
+
field.type !== "unknown"
|
|
63
|
+
? `<span class="badge badge-xs badge-ghost font-mono opacity-40 ml-1">${field.type}</span>`
|
|
64
|
+
: "";
|
|
65
|
+
const optionalAlt = field.optional
|
|
66
|
+
? '<span class="label-text-alt text-[10px] opacity-30 italic">optional</span>'
|
|
67
|
+
: "";
|
|
68
|
+
const labelRow = `
|
|
69
|
+
<label class="label py-0.5">
|
|
70
|
+
<span class="label-text text-[11px] font-mono font-semibold">${label}${badge}</span>
|
|
71
|
+
${optionalAlt}
|
|
72
|
+
</label>`;
|
|
73
|
+
|
|
74
|
+
if (field.type === "boolean") {
|
|
75
|
+
return `
|
|
76
|
+
<div class="flex items-center gap-3 py-1">
|
|
77
|
+
<input
|
|
78
|
+
type="checkbox"
|
|
79
|
+
data-arg-key="${field.name}"
|
|
80
|
+
data-arg-type="boolean"
|
|
81
|
+
class="checkbox checkbox-sm checkbox-primary"
|
|
82
|
+
${field.defaultValue === "true" ? "checked" : ""}
|
|
83
|
+
/>
|
|
84
|
+
<span class="text-sm font-mono opacity-70">${field.name}${badge}</span>
|
|
85
|
+
${field.optional ? '<span class="text-[10px] opacity-30 italic ml-auto">optional</span>' : ""}
|
|
86
|
+
</div>`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (field.type === "object") {
|
|
90
|
+
if (field.fields && field.fields.length > 0) {
|
|
91
|
+
return `
|
|
92
|
+
<div class="form-control">
|
|
93
|
+
${labelRow}
|
|
94
|
+
<div
|
|
95
|
+
data-arg-key="${field.name}"
|
|
96
|
+
data-arg-type="object"
|
|
97
|
+
class="border border-base-200 rounded-xl p-3 bg-base-200/20 flex flex-col gap-2"
|
|
98
|
+
>
|
|
99
|
+
${renderObjectFieldInputs(field.fields)}
|
|
100
|
+
</div>
|
|
101
|
+
</div>`;
|
|
102
|
+
}
|
|
103
|
+
// Fallback when schema isn't statically known
|
|
104
|
+
return `
|
|
105
|
+
<div class="form-control">
|
|
106
|
+
${labelRow}
|
|
107
|
+
<textarea
|
|
108
|
+
data-arg-key="${field.name}"
|
|
109
|
+
data-arg-type="object"
|
|
110
|
+
placeholder="{}"
|
|
111
|
+
rows="4"
|
|
112
|
+
class="textarea textarea-sm textarea-bordered font-mono w-full bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-xl border-base-200 resize-y text-xs"
|
|
113
|
+
${!field.optional ? "required" : ""}
|
|
114
|
+
>${field.defaultValue ?? ""}</textarea>
|
|
115
|
+
</div>`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (field.type === "array") {
|
|
119
|
+
const itemType = field.itemType ?? "string";
|
|
120
|
+
const itemFieldsJson = JSON.stringify(
|
|
121
|
+
(field.itemFields ?? []).map((f) => ({ name: f.name, type: f.type })),
|
|
122
|
+
);
|
|
123
|
+
return `
|
|
124
|
+
<div class="form-control">
|
|
125
|
+
${labelRow}
|
|
126
|
+
<div
|
|
127
|
+
data-arg-key="${field.name}"
|
|
128
|
+
data-arg-type="array"
|
|
129
|
+
data-item-type="${itemType}"
|
|
130
|
+
data-item-fields='${itemFieldsJson}'
|
|
131
|
+
class="flex flex-col gap-2"
|
|
132
|
+
></div>
|
|
133
|
+
<button
|
|
134
|
+
type="button"
|
|
135
|
+
onclick="addArrayItem('${field.name}')"
|
|
136
|
+
class="btn btn-xs btn-ghost gap-1 mt-1 self-start opacity-50 hover:opacity-100"
|
|
137
|
+
>
|
|
138
|
+
<iconify-icon icon="solar:add-circle-linear" width="12" height="12"></iconify-icon>
|
|
139
|
+
Add item
|
|
140
|
+
</button>
|
|
141
|
+
</div>`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const inputType =
|
|
145
|
+
field.type === "number" ? "number" : field.type === "date" ? "datetime-local" : "text";
|
|
146
|
+
|
|
147
|
+
return `
|
|
148
|
+
<div class="form-control">
|
|
149
|
+
${labelRow}
|
|
150
|
+
<input
|
|
151
|
+
type="${inputType}"
|
|
152
|
+
placeholder="${field.defaultValue ?? ""}"
|
|
153
|
+
data-arg-key="${field.name}"
|
|
154
|
+
data-arg-type="${field.type}"
|
|
155
|
+
value="${field.defaultValue ?? ""}"
|
|
156
|
+
class="${inputClass}"
|
|
157
|
+
${!field.optional ? "required" : ""}
|
|
158
|
+
/>
|
|
159
|
+
</div>`;
|
|
160
|
+
})
|
|
161
|
+
.join("\n");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function renderArgumentsSection(h: DiscoveredHandlerOperation): string {
|
|
165
|
+
return `
|
|
166
|
+
<div class="space-y-4">
|
|
167
|
+
<div class="flex items-center justify-between">
|
|
168
|
+
<div class="flex flex-col">
|
|
169
|
+
<span class="text-[11px] font-bold uppercase tracking-wider opacity-40">Arguments</span>
|
|
170
|
+
<span class="text-[10px] font-mono opacity-30">${h.kind}</span>
|
|
171
|
+
</div>
|
|
172
|
+
<label class="flex items-center gap-2 cursor-pointer select-none group" title="Enable realtime updates via WebSocket">
|
|
173
|
+
<span class="text-[10px] font-bold uppercase tracking-wider opacity-40 group-hover:opacity-70 transition-opacity">Realtime</span>
|
|
174
|
+
<input type="checkbox" id="realtime-toggle" class="toggle toggle-xs toggle-success" onchange="toggleRealtime(this.checked)" />
|
|
175
|
+
</label>
|
|
176
|
+
</div>
|
|
177
|
+
<div id="args-rows" class="flex flex-col gap-3">
|
|
178
|
+
${renderArgRows(h)}
|
|
179
|
+
</div>
|
|
180
|
+
<p class="text-[11px] opacity-30 mt-2 italic">Values are sent as ${h.kind === "query" ? "query string params" : "JSON request body"}.</p>
|
|
181
|
+
</div>
|
|
182
|
+
`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function renderBearerTokenSection(): string {
|
|
186
|
+
return `
|
|
187
|
+
<div class="space-y-4">
|
|
188
|
+
<label class="text-[11px] font-bold uppercase tracking-wider opacity-40 block">Bearer Token <span class="font-normal normal-case">(optional)</span></label>
|
|
189
|
+
<div class="relative group">
|
|
190
|
+
<input
|
|
191
|
+
type="password"
|
|
192
|
+
name="token"
|
|
193
|
+
id="bearer-token-input"
|
|
194
|
+
class="input input-sm input-bordered font-mono text-sm w-full bg-base-200/30 focus:bg-base-100 focus:border-primary transition-all rounded-xl border-base-200 pr-9"
|
|
195
|
+
placeholder="eyJhbGciOi..."
|
|
196
|
+
/>
|
|
197
|
+
<button type="button" onclick="toggleTokenVisibility()" class="absolute right-2.5 top-1/2 -translate-y-1/2 opacity-30 hover:opacity-70 transition-opacity">
|
|
198
|
+
<iconify-icon id="token-eye-icon" icon="solar:eye-linear" width="15" height="15"></iconify-icon>
|
|
199
|
+
</button>
|
|
200
|
+
</div>
|
|
201
|
+
<p class="text-[10px] opacity-30 italic">Token will be included in the Authorization header.</p>
|
|
202
|
+
</div>
|
|
203
|
+
`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function renderCustomHeadersSection(): string {
|
|
207
|
+
return `
|
|
208
|
+
<div class="space-y-4">
|
|
209
|
+
<div class="flex items-center justify-between">
|
|
210
|
+
<span class="text-[11px] font-bold uppercase tracking-wider opacity-40">Custom Headers</span>
|
|
211
|
+
<button type="button" onclick="addHeaderRow()" class="btn btn-xs btn-ghost gap-1 opacity-50 hover:opacity-100">
|
|
212
|
+
<iconify-icon icon="solar:add-circle-linear" width="14" height="14"></iconify-icon>
|
|
213
|
+
Add
|
|
214
|
+
</button>
|
|
215
|
+
</div>
|
|
216
|
+
<div id="headers-rows" class="flex flex-col gap-2">
|
|
217
|
+
<!-- populated by addHeaderRow() -->
|
|
218
|
+
</div>
|
|
219
|
+
<p id="headers-error" class="text-[11px] text-error mt-1.5 hidden"></p>
|
|
220
|
+
</div>
|
|
221
|
+
`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function renderRequestPanel(h: DiscoveredHandlerOperation): string {
|
|
225
|
+
return `
|
|
226
|
+
<div class="card bg-base-100 border border-base-200 shadow-sm overflow-hidden flex flex-col h-full">
|
|
227
|
+
<div class="px-5 py-3 border-b border-base-200 bg-base-200/20 flex items-center justify-between flex-none">
|
|
228
|
+
<h3 class="text-xs font-bold uppercase tracking-widest opacity-40">Request</h3>
|
|
229
|
+
<iconify-icon icon="solar:settings-linear" width="16" height="16" class="opacity-30"></iconify-icon>
|
|
230
|
+
</div>
|
|
231
|
+
|
|
232
|
+
<div class="flex-1 overflow-hidden flex flex-col">
|
|
233
|
+
<form id="fn-form" onsubmit="return false" class="flex flex-col h-full">
|
|
234
|
+
<!-- Tabs Navigation -->
|
|
235
|
+
<div class="px-5 pt-4 flex-none">
|
|
236
|
+
<div role="tablist" class="tabs tabs-box bg-base-200/50 p-1 rounded-xl">
|
|
237
|
+
<a role="tab" id="req-tab-btn-args" class="tab tab-active !text-[10px] !font-bold uppercase tracking-wider h-8" onclick="switchRequestTab('args')">Args</a>
|
|
238
|
+
<a role="tab" id="req-tab-btn-auth" class="tab !text-[10px] !font-bold uppercase tracking-wider h-8" onclick="switchRequestTab('auth')">Auth</a>
|
|
239
|
+
<a role="tab" id="req-tab-btn-headers" class="tab !text-[10px] !font-bold uppercase tracking-wider h-8" onclick="switchRequestTab('headers')">Headers</a>
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
<!-- Tab Content -->
|
|
244
|
+
<div class="flex-1 overflow-y-auto">
|
|
245
|
+
<div id="request-tab-args" class="p-5">
|
|
246
|
+
${renderArgumentsSection(h)}
|
|
247
|
+
</div>
|
|
248
|
+
<div id="request-tab-auth" class="p-5 hidden">
|
|
249
|
+
${renderBearerTokenSection()}
|
|
250
|
+
</div>
|
|
251
|
+
<div id="request-tab-headers" class="p-5 hidden">
|
|
252
|
+
${renderCustomHeadersSection()}
|
|
253
|
+
</div>
|
|
254
|
+
</div>
|
|
255
|
+
|
|
256
|
+
<!-- Submit Button (Fixed at bottom) -->
|
|
257
|
+
<div class="p-5 border-t border-base-200 mt-auto bg-base-200/5">
|
|
258
|
+
<button
|
|
259
|
+
type="button"
|
|
260
|
+
onclick="executeFn()"
|
|
261
|
+
class="btn btn-primary w-full gap-2 rounded-xl shadow-lg shadow-primary/20 hover:shadow-xl hover:shadow-primary/30 transition-all font-semibold"
|
|
262
|
+
>
|
|
263
|
+
<iconify-icon icon="solar:play-bold" width="18" height="18"></iconify-icon>
|
|
264
|
+
Run ${h.kind}
|
|
265
|
+
</button>
|
|
266
|
+
</div>
|
|
267
|
+
</form>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
`;
|
|
271
|
+
}
|