@hitch42/applet 0.1.0-beta.9 → 0.1.1-beta.10
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/dist/_internal/client.js +120 -11
- package/dist/_internal/log-context.d.ts +34 -0
- package/dist/_internal/log-context.js +2 -0
- package/dist/_internal/server.js +112 -57
- package/dist/applet.js +12 -12
- package/dist/build-Bh_S5BUv.js +2 -0
- package/dist/{build-CAb26kMY.js → build-CEfFoIZZ.js} +1 -1
- package/dist/{ci-5qWl7lT3.js → ci-BKw14X2h.js} +14 -13
- package/dist/client.d.ts +2 -2
- package/dist/{contract-rP_eV9PK.d.ts → contract-CsUpTBe0.d.ts} +1 -1
- package/dist/{deploy-D_OFJ6-Q.js → deploy-wGYjwXrx.js} +139 -88
- package/dist/{generate-CBPnHoqX.js → generate-BEIYs17x.js} +54 -22
- package/dist/generate-Dox-OYt6.js +2 -0
- package/dist/headers-DkNr9MLJ.js +17 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/{init-tfzwuYnk.js → init-6oGPM46R.js} +10 -15
- package/dist/{load-config-BYSxDVAl.js → load-config-xEdTXs0y.js} +2 -2
- package/dist/log-context-zu8U9Sjm.js +73 -0
- package/dist/{login-C7RKmmTe.js → login-CUx3TmFQ.js} +1 -1
- package/dist/{logs-DgjgAxj2.js → logs-DSjuEN0Q.js} +20 -22
- package/dist/{manifest-DD_SGkS6.d.ts → manifest-C6_F4bL8.d.ts} +5 -1
- package/dist/{manifest-Bp87Uz0a.js → manifest-CJSL9GuC.js} +20 -4
- package/dist/{project-D6XHllmC.js → project-BRZGd6xq.js} +197 -16
- package/dist/query-cache-CXmAyLv3.js +82 -0
- package/dist/react.d.ts +2 -1
- package/dist/react.js +59 -39
- package/dist/{schedules-dhU1yyFr.js → schedules-C8_Svr4h.js} +1 -1
- package/dist/server.d.ts +8 -3
- package/dist/server.js +29 -8
- package/dist/telephony.d.ts +24 -4
- package/dist/telephony.js +135 -16
- package/dist/{variables-Bwnr7oxf.js → variables-DT5RyHdH.js} +13 -13
- package/dist/vite.d.ts +3 -60
- package/dist/vite.js +50 -15
- package/dist/{workflow-engine-MogejNfF.js → workflow-engine-BOTzURKM.js} +1 -7
- package/dist/{workspace-XVtM12ZC.js → workspace-D0dnnlxL.js} +33 -38
- package/package.json +13 -6
- package/scaffold/.agents/skills/hitch-applets/SKILL.md +29 -3
- package/scaffold/.agents/skills/hitch-applets/references/manifest.md +8 -0
- package/scaffold/.agents/skills/hitch-applets/references/markdown.md +2 -0
- package/scaffold/.agents/skills/hitch-applets/references/records.md +2 -0
- package/scaffold/.agents/skills/hitch-data/SKILL.md +2 -1
- package/scaffold/.agents/skills/hitch-data/references/attributes.md +7 -1
- package/scaffold/.agents/skills/hitch-data/references/limits.md +13 -13
- package/scaffold/.agents/skills/hitch-theory/SKILL.md +3 -2
- package/scaffold/.agents/skills/react-best-practices/SKILL.md +127 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-effect-event-deps.md +50 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-init-once.md +42 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-defer-await.md +82 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-dependencies.md +48 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-parallel.md +24 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-analyzable-paths.md +42 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-barrel-imports.md +39 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-conditional.md +35 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-defer-third-party.md +46 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-dynamic-imports.md +38 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-preload.md +40 -0
- package/scaffold/.agents/skills/react-best-practices/rules/client-event-listeners.md +78 -0
- package/scaffold/.agents/skills/react-best-practices/rules/client-localstorage-schema.md +74 -0
- package/scaffold/.agents/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-batch-dom-css.md +110 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-cache-function-results.md +58 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-cache-storage.md +56 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-flatmap-filter.md +51 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-length-check-first.md +50 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-request-idle-callback.md +104 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +38 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-conditional-render.md +32 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-hoist-jsx.md +36 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-resource-hints.md +81 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-script-defer-async.md +36 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-usetransition-loading.md +43 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-functional-setstate.md +77 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-lazy-state-init.md +56 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo-with-default-value.md +36 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-no-inline-components.md +75 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/scaffold/.agents/skills/tanstack-query/SKILL.md +136 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/automatic-invalidation-after-mutations.md +124 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/broadcast-realtime-and-multi-tab-synchronization.md +150 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/compose-query-with-tanstack-router-and-start.md +248 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/enforce-query-best-practices-with-eslint.md +167 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/persist-offline-and-restore-caches.md +181 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/query-data-and-forms.md +156 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/build-query-abstractions.md +130 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/cancel-queries-and-consume-abort-signals.md +176 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/concurrent-optimistic-updates.md +135 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/coordinate-query-execution.md +188 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/design-query-keys-and-options.md +182 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/fetch-and-observe-queries.md +193 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/implement-optimistic-updates-and-cache-writes.md +168 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/paginate-and-build-infinite-queries.md +188 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/seed-placeholder-select-and-transform-data.md +188 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/selectors-and-derived-state.md +145 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/tune-defaults-freshness-retries-and-refetching.md +172 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/understand-query-internals-and-observers.md +104 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/write-mutations-and-invalidate-related-queries.md +183 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/debug-with-devtools.md +169 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/handle-status-and-errors.md +119 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/shape-data-and-render-efficiently.md +184 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/use-framework-adapter-reactivity.md +185 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/use-suspense-and-error-boundaries.md +208 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/migrate-major-versions-and-codemods.md +169 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/prefetch-and-remove-request-waterfalls.md +228 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/setup-query-client-and-providers.md +161 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/ssr-hydration-and-streaming.md +209 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/test-query-code.md +160 -0
- package/scaffold/.agents/skills/tanstack-router/SKILL.md +134 -0
- package/scaffold/.agents/skills/tanstack-router/references/compositions/router-query.md +412 -0
- package/scaffold/.agents/skills/tanstack-router/references/react-router.md +495 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/auth-and-guards.md +495 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/code-splitting.md +318 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/data-loading.md +490 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/index.md +158 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/navigation.md +433 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/not-found-and-errors.md +436 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/path-params.md +383 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/search-params.md +343 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/ssr.md +462 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/type-safety.md +493 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-plugin.md +250 -0
- package/scaffold/.agents/skills/tanstack-router/references/virtual-file-routes.md +215 -0
- package/scaffold/.agents/skills/web-design-guidelines/SKILL.md +184 -0
- package/scaffold/.github/workflows/hitch.yml +1 -1
- package/scaffold/AGENTS.md +2 -2
- package/scaffold/applet/src/client/components/ui/alert.tsx +1 -1
- package/scaffold/applet/src/client/components/ui/button.tsx +1 -1
- package/scaffold/applet/src/client/components/ui/checkbox.tsx +1 -1
- package/scaffold/applet/src/client/components/ui/dialog.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/dropdown-menu.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/input-group.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/select.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/sheet.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/spinner.tsx +2 -1
- package/scaffold/applet/src/client/components/ui/tabs.tsx +1 -1
- package/scaffold/applet/src/client/lib/utils.ts +1 -6
- package/scaffold/applet/src/client/styles/globals.css +2 -0
- package/dist/build-BfbTbt_r.js +0 -2
- package/dist/generate-BgepN4-b.js +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { i as APPLET_CODE_PATTERN } from "./manifest-
|
|
2
|
-
import { i as readWorkspaceConfig, n as fetchWithOrgAuth, t as resolveWorkspaceOrg } from "./workspace-
|
|
3
|
-
import { t as loadAppletConfig } from "./load-config-
|
|
1
|
+
import { i as APPLET_CODE_PATTERN } from "./manifest-CJSL9GuC.js";
|
|
2
|
+
import { i as readWorkspaceConfig, n as fetchWithOrgAuth, t as resolveWorkspaceOrg } from "./workspace-D0dnnlxL.js";
|
|
3
|
+
import { t as loadAppletConfig } from "./load-config-xEdTXs0y.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
//#region src/logs.ts
|
|
6
6
|
const LOG_LEVELS = [
|
|
@@ -19,6 +19,16 @@ const logSchema = z.object({
|
|
|
19
19
|
timestamp: z.number(),
|
|
20
20
|
level: z.string(),
|
|
21
21
|
message: z.string(),
|
|
22
|
+
context: z.record(z.string(), z.unknown()).optional(),
|
|
23
|
+
error: z.object({
|
|
24
|
+
name: z.string(),
|
|
25
|
+
message: z.string(),
|
|
26
|
+
stack: z.string().optional(),
|
|
27
|
+
cause: z.object({
|
|
28
|
+
name: z.string(),
|
|
29
|
+
message: z.string()
|
|
30
|
+
}).optional()
|
|
31
|
+
}).optional(),
|
|
22
32
|
releaseId: z.string(),
|
|
23
33
|
type: z.string().optional(),
|
|
24
34
|
runId: z.string().optional(),
|
|
@@ -93,20 +103,6 @@ async function readErrorDetails(response) {
|
|
|
93
103
|
}
|
|
94
104
|
return "";
|
|
95
105
|
}
|
|
96
|
-
function waitForPoll(signal) {
|
|
97
|
-
if (signal?.aborted === true) return Promise.resolve(false);
|
|
98
|
-
return new Promise((resolve) => {
|
|
99
|
-
const timeout = setTimeout(() => {
|
|
100
|
-
signal?.removeEventListener("abort", onAbort);
|
|
101
|
-
resolve(true);
|
|
102
|
-
}, POLL_INTERVAL_MS);
|
|
103
|
-
const onAbort = () => {
|
|
104
|
-
clearTimeout(timeout);
|
|
105
|
-
resolve(false);
|
|
106
|
-
};
|
|
107
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
106
|
function printLog(log) {
|
|
111
107
|
const details = log.type === "invocation" ? [
|
|
112
108
|
log.statusCode === void 0 ? void 0 : `status=${log.statusCode}`,
|
|
@@ -114,7 +110,9 @@ function printLog(log) {
|
|
|
114
110
|
log.wallTimeMs === void 0 ? void 0 : `wall=${log.wallTimeMs}ms`,
|
|
115
111
|
log.cpuTimeMs === void 0 ? void 0 : `cpu=${log.cpuTimeMs}ms`
|
|
116
112
|
].filter((value) => value !== void 0) : [];
|
|
117
|
-
console.log(`${new Date(log.timestamp).toISOString()} ${log.level.toUpperCase().padEnd(5)} ${log.type === "workflow" ? `[${log.workflow} ${log.runId?.slice(0, 8)}#${log.invocation}] ` : ""}${log.message}${details.length === 0 ? "" : ` [${details.join(" ")}]`}`);
|
|
113
|
+
console.log(`${new Date(log.timestamp).toISOString()} ${log.level.toUpperCase().padEnd(5)} ${log.type === "workflow" ? `[${log.workflow} ${log.runId?.slice(0, 8)}#${log.invocation}] ` : ""}${log.message}${details.length === 0 ? "" : ` [${details.join(" ")}]`}${log.context === void 0 ? "" : ` ${JSON.stringify(log.context)}`}`);
|
|
114
|
+
if (log.error) console.log(log.error.stack ?? `${log.error.name}: ${log.error.message}`);
|
|
115
|
+
if (log.error?.cause) console.log(`Caused by ${log.error.cause.name}: ${log.error.cause.message}`);
|
|
118
116
|
}
|
|
119
117
|
async function runLogs(options) {
|
|
120
118
|
const [{ code, org }, since, limit, level, userFilter, search] = await Promise.all([
|
|
@@ -127,13 +125,12 @@ async function runLogs(options) {
|
|
|
127
125
|
]);
|
|
128
126
|
const runFilter = options.run === void 0 ? void 0 : { runId: { $eq: options.run } };
|
|
129
127
|
const filter = runFilter === void 0 ? userFilter : userFilter === void 0 ? runFilter : { $and: [runFilter, userFilter] };
|
|
130
|
-
const fetcher = options.fetch ?? globalThis.fetch;
|
|
131
128
|
const startedAt = Date.now();
|
|
132
129
|
const requestLogs = async (from, to) => {
|
|
133
|
-
const response = await fetchWithOrgAuth(org,
|
|
130
|
+
const response = await fetchWithOrgAuth(org, (instanceUrl, accessToken) => {
|
|
134
131
|
const url = new URL(`/api/v1/applets/${encodeURIComponent(code)}/logs/query`, `${instanceUrl}/`);
|
|
135
132
|
const levelFilter = level === void 0 ? void 0 : { level: { $in: LOG_LEVELS.slice(LOG_LEVELS.indexOf(level)) } };
|
|
136
|
-
return
|
|
133
|
+
return fetch(url, {
|
|
137
134
|
method: "POST",
|
|
138
135
|
headers: {
|
|
139
136
|
Authorization: `Bearer ${accessToken}`,
|
|
@@ -172,7 +169,8 @@ async function runLogs(options) {
|
|
|
172
169
|
return;
|
|
173
170
|
}
|
|
174
171
|
let lastTimestamp = initialLogs.at(-1)?.timestamp ?? startedAt;
|
|
175
|
-
|
|
172
|
+
for (;;) {
|
|
173
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
176
174
|
const to = Date.now();
|
|
177
175
|
const logs = await requestLogs(Math.max(startedAt - since, lastTimestamp - LIVE_OVERLAP_MS), to);
|
|
178
176
|
printNewLogs(logs);
|
|
@@ -35,7 +35,9 @@ interface AppletManifest {
|
|
|
35
35
|
/** This code needs the schema as of this changeset. */
|
|
36
36
|
requiresChangeset?: string;
|
|
37
37
|
telephony?: {
|
|
38
|
-
|
|
38
|
+
read?: boolean;
|
|
39
|
+
send?: boolean;
|
|
40
|
+
events?: readonly "message.received"[];
|
|
39
41
|
};
|
|
40
42
|
schedules?: readonly {
|
|
41
43
|
code: string;
|
|
@@ -53,6 +55,8 @@ interface AppletManifest {
|
|
|
53
55
|
canDelete: boolean;
|
|
54
56
|
readOnly: readonly string[];
|
|
55
57
|
readWrite: readonly string[];
|
|
58
|
+
optional?: boolean;
|
|
59
|
+
optionalAttributes?: readonly string[];
|
|
56
60
|
}[];
|
|
57
61
|
}
|
|
58
62
|
type AppletDefinition = Omit<AppletManifest, "org">;
|
|
@@ -31,13 +31,22 @@ const appletManifestObjectSchema = z.strictObject({
|
|
|
31
31
|
canCreate: z.boolean(),
|
|
32
32
|
canDelete: z.boolean(),
|
|
33
33
|
readOnly: attributeCodesSchema,
|
|
34
|
-
readWrite: attributeCodesSchema
|
|
34
|
+
readWrite: attributeCodesSchema,
|
|
35
|
+
optional: z.boolean().optional(),
|
|
36
|
+
optionalAttributes: attributeCodesSchema.optional()
|
|
35
37
|
}).superRefine((object, context) => {
|
|
36
38
|
const overlap = object.readOnly.find((code) => object.readWrite.includes(code));
|
|
37
39
|
if (overlap !== void 0) context.addIssue({
|
|
38
40
|
code: "custom",
|
|
39
41
|
message: `readOnly and readWrite both contain "${overlap}".`
|
|
40
42
|
});
|
|
43
|
+
object.optionalAttributes?.forEach((code, index) => {
|
|
44
|
+
if (!object.readOnly.includes(code) && !object.readWrite.includes(code)) context.addIssue({
|
|
45
|
+
code: "custom",
|
|
46
|
+
message: `optionalAttributes contains undeclared attribute code "${code}".`,
|
|
47
|
+
path: ["optionalAttributes", index]
|
|
48
|
+
});
|
|
49
|
+
});
|
|
41
50
|
});
|
|
42
51
|
const appletManifestObjectsSchema = z.array(appletManifestObjectSchema).readonly();
|
|
43
52
|
const appletManifestSchedulesSchema = z.array(z.strictObject({
|
|
@@ -64,7 +73,11 @@ const appletManifestShape = {
|
|
|
64
73
|
name: nameSchema,
|
|
65
74
|
code: codeSchema,
|
|
66
75
|
requiresChangeset: z.uuid().optional(),
|
|
67
|
-
telephony: z.strictObject({
|
|
76
|
+
telephony: z.strictObject({
|
|
77
|
+
read: z.boolean().optional(),
|
|
78
|
+
send: z.boolean().optional(),
|
|
79
|
+
events: z.array(z.literal("message.received")).min(1).refine((events) => new Set(events).size === events.length).readonly().optional()
|
|
80
|
+
}).refine((telephony) => telephony.events === void 0 || telephony.read === true, "telephony.events needs telephony.read").optional(),
|
|
68
81
|
schedules: appletManifestSchedulesSchema.optional(),
|
|
69
82
|
variables: appletManifestVariablesSchema.optional(),
|
|
70
83
|
objects: appletManifestObjectsSchema
|
|
@@ -104,6 +117,7 @@ const appletDefinitionSchema = z.strictObject({
|
|
|
104
117
|
}).superRefine(checkDuplicateCodes);
|
|
105
118
|
const packageVersionsSchema = z.record(z.string().min(1), z.string().min(1)).readonly();
|
|
106
119
|
const RESERVED_APPLET_PACKAGES = /* @__PURE__ */ new Set([
|
|
120
|
+
"@fontsource-variable/geist-mono",
|
|
107
121
|
"@fontsource-variable/inter",
|
|
108
122
|
"@hitch42/applet",
|
|
109
123
|
"@orpc/contract",
|
|
@@ -123,14 +137,16 @@ const RESERVED_APPLET_PACKAGES = /* @__PURE__ */ new Set([
|
|
|
123
137
|
"@types/react",
|
|
124
138
|
"@types/react-dom",
|
|
125
139
|
"class-variance-authority",
|
|
126
|
-
"
|
|
140
|
+
"cn",
|
|
127
141
|
"lucide-react",
|
|
142
|
+
"oxfmt",
|
|
143
|
+
"oxlint",
|
|
144
|
+
"oxlint-tsgolint",
|
|
128
145
|
"react",
|
|
129
146
|
"react-aria-components",
|
|
130
147
|
"react-dom",
|
|
131
148
|
"shadcn",
|
|
132
149
|
"streamdown",
|
|
133
|
-
"tailwind-merge",
|
|
134
150
|
"tailwindcss",
|
|
135
151
|
"tw-animate-css",
|
|
136
152
|
"typescript",
|
|
@@ -1,9 +1,72 @@
|
|
|
1
|
-
import { i as readWorkspaceConfig } from "./workspace-
|
|
2
|
-
import { n as loadAppletSourceDefinition } from "./load-config-
|
|
1
|
+
import { i as readWorkspaceConfig, l as organizationInstanceUrl, s as DEFAULT_INSTANCE_URL } from "./workspace-D0dnnlxL.js";
|
|
2
|
+
import { n as loadAppletSourceDefinition } from "./load-config-xEdTXs0y.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
|
-
import { cp, mkdir, readFile, rm, symlink, writeFile } from "node:fs/promises";
|
|
5
|
+
import { cp, mkdir, readFile, readdir, rm, symlink, writeFile } from "node:fs/promises";
|
|
6
6
|
import { dirname, relative, resolve } from "node:path";
|
|
7
|
+
import { TomlError, parse, stringify } from "smol-toml";
|
|
8
|
+
//#region src/agent-support.ts
|
|
9
|
+
var AgentConfigError = class extends Error {};
|
|
10
|
+
async function ensureAgentConfigs(root, org) {
|
|
11
|
+
const servers = {
|
|
12
|
+
hitch: {
|
|
13
|
+
type: "http",
|
|
14
|
+
url: `${organizationInstanceUrl(DEFAULT_INSTANCE_URL, org)}/mcp`
|
|
15
|
+
},
|
|
16
|
+
"chrome-devtools": {
|
|
17
|
+
type: "stdio",
|
|
18
|
+
command: "pnpx",
|
|
19
|
+
args: ["chrome-devtools-mcp@latest", "--headless"]
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const configs = await Promise.all([{
|
|
23
|
+
path: resolve(root, ".mcp.json"),
|
|
24
|
+
format: "json",
|
|
25
|
+
key: "mcpServers"
|
|
26
|
+
}, {
|
|
27
|
+
path: resolve(root, ".codex/config.toml"),
|
|
28
|
+
format: "toml",
|
|
29
|
+
key: "mcp_servers"
|
|
30
|
+
}].map(async ({ path, format, key }) => {
|
|
31
|
+
const current = existsSync(path) ? await readFile(path, "utf8") : void 0;
|
|
32
|
+
let config;
|
|
33
|
+
let additions;
|
|
34
|
+
try {
|
|
35
|
+
config = z.record(z.string(), z.unknown()).parse(current === void 0 ? {} : format === "json" ? JSON.parse(current) : parse(current, { integersAsBigInt: true }));
|
|
36
|
+
const existing = config[key] === void 0 ? {} : z.record(z.string(), z.unknown()).parse(config[key]);
|
|
37
|
+
const missing = Object.entries(servers).filter(([name]) => !Object.hasOwn(existing, name));
|
|
38
|
+
if (current !== void 0 && missing.length === 0) return void 0;
|
|
39
|
+
additions = Object.fromEntries(missing.map(([name, server]) => [name, format === "json" ? server : Object.fromEntries(Object.entries(server).filter(([field]) => field !== "type"))]));
|
|
40
|
+
config[key] = {
|
|
41
|
+
...existing,
|
|
42
|
+
...additions
|
|
43
|
+
};
|
|
44
|
+
} catch (cause) {
|
|
45
|
+
throw new AgentConfigError(`Invalid agent configuration in ${path}.`, { cause });
|
|
46
|
+
}
|
|
47
|
+
if (format === "json") return {
|
|
48
|
+
path,
|
|
49
|
+
contents: `${JSON.stringify(config, null, 2)}\n`
|
|
50
|
+
};
|
|
51
|
+
const contents = `${current ?? ""}${current ? "\n" : ""}${stringify({ [key]: additions })}`;
|
|
52
|
+
try {
|
|
53
|
+
parse(contents, { integersAsBigInt: true });
|
|
54
|
+
return {
|
|
55
|
+
path,
|
|
56
|
+
contents
|
|
57
|
+
};
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (!(error instanceof TomlError)) throw error;
|
|
60
|
+
return {
|
|
61
|
+
path,
|
|
62
|
+
contents: stringify(config, { numbersAsFloat: true })
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}));
|
|
66
|
+
await mkdir(resolve(root, ".codex"), { recursive: true });
|
|
67
|
+
await Promise.all(configs.filter((config) => config !== void 0).map(({ path, contents }) => writeFile(path, contents)));
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
7
70
|
//#region src/project.ts
|
|
8
71
|
const PACKAGE_MANAGER = "pnpm@11.18.0+sha512.33d83c77da82f49fba836925c6f1b841181ec3132b670639bd012f7075f5c7cf634c5f870147c19aae7478fac01df09d8892e880454896edd23ee9b33757563c";
|
|
9
72
|
const cliManifestValueSchema = z.string().min(1, "must be a non-empty string");
|
|
@@ -11,6 +74,7 @@ const cliManifestSchema = z.object({
|
|
|
11
74
|
name: cliManifestValueSchema,
|
|
12
75
|
version: cliManifestValueSchema,
|
|
13
76
|
dependencies: z.object({
|
|
77
|
+
"@fontsource-variable/geist-mono": cliManifestValueSchema,
|
|
14
78
|
"@fontsource-variable/inter": cliManifestValueSchema,
|
|
15
79
|
"@orpc/contract": cliManifestValueSchema,
|
|
16
80
|
"@tiptap/core": cliManifestValueSchema,
|
|
@@ -24,12 +88,14 @@ const cliManifestSchema = z.object({
|
|
|
24
88
|
"@tailwindcss/vite": cliManifestValueSchema,
|
|
25
89
|
"@tanstack/router-cli": cliManifestValueSchema,
|
|
26
90
|
"class-variance-authority": cliManifestValueSchema,
|
|
27
|
-
|
|
91
|
+
cn: cliManifestValueSchema,
|
|
28
92
|
"lucide-react": cliManifestValueSchema,
|
|
93
|
+
oxfmt: cliManifestValueSchema,
|
|
94
|
+
oxlint: cliManifestValueSchema,
|
|
95
|
+
"oxlint-tsgolint": cliManifestValueSchema,
|
|
29
96
|
"react-aria-components": cliManifestValueSchema,
|
|
30
97
|
shadcn: cliManifestValueSchema,
|
|
31
98
|
streamdown: cliManifestValueSchema,
|
|
32
|
-
"tailwind-merge": cliManifestValueSchema,
|
|
33
99
|
tailwindcss: cliManifestValueSchema,
|
|
34
100
|
"tw-animate-css": cliManifestValueSchema,
|
|
35
101
|
vite: cliManifestValueSchema,
|
|
@@ -71,8 +137,16 @@ function workspacePackage(org) {
|
|
|
71
137
|
name: `${org.replaceAll("_", "-")}-applets`,
|
|
72
138
|
private: true,
|
|
73
139
|
type: "module",
|
|
140
|
+
scripts: {
|
|
141
|
+
lint: "oxlint",
|
|
142
|
+
fmt: "oxfmt",
|
|
143
|
+
check: "oxfmt --check && oxlint"
|
|
144
|
+
},
|
|
74
145
|
devDependencies: {
|
|
75
146
|
"@hitch42/applet": "catalog:",
|
|
147
|
+
oxfmt: "catalog:",
|
|
148
|
+
oxlint: "catalog:",
|
|
149
|
+
"oxlint-tsgolint": "catalog:",
|
|
76
150
|
typescript: "catalog:",
|
|
77
151
|
vite: "catalog:",
|
|
78
152
|
vitest: "catalog:"
|
|
@@ -85,6 +159,7 @@ function workspaceFile(cli) {
|
|
|
85
159
|
- applets/*
|
|
86
160
|
catalog:
|
|
87
161
|
"@hitch42/applet": npm:${cli.name}@${cli.version}
|
|
162
|
+
"@fontsource-variable/geist-mono": "${cli.dependencies["@fontsource-variable/geist-mono"]}"
|
|
88
163
|
"@fontsource-variable/inter": "${cli.dependencies["@fontsource-variable/inter"]}"
|
|
89
164
|
"@orpc/contract": "${cli.dependencies["@orpc/contract"]}"
|
|
90
165
|
"@orpc/server": "${cli.peerDependencies["@orpc/server"]}"
|
|
@@ -104,14 +179,16 @@ catalog:
|
|
|
104
179
|
"@types/react-dom": "${cli.peerDependencies["@types/react-dom"]}"
|
|
105
180
|
"@tailwindcss/vite": "${cli.dependencies["@tailwindcss/vite"]}"
|
|
106
181
|
class-variance-authority: "${cli.dependencies["class-variance-authority"]}"
|
|
107
|
-
|
|
182
|
+
cn: "${cli.dependencies.cn}"
|
|
108
183
|
lucide-react: "${cli.dependencies["lucide-react"]}"
|
|
184
|
+
oxfmt: "${cli.dependencies.oxfmt}"
|
|
185
|
+
oxlint: "${cli.dependencies.oxlint}"
|
|
186
|
+
oxlint-tsgolint: "${cli.dependencies["oxlint-tsgolint"]}"
|
|
109
187
|
react: "${cli.peerDependencies.react}"
|
|
110
188
|
react-aria-components: "${cli.dependencies["react-aria-components"]}"
|
|
111
189
|
react-dom: "${cli.peerDependencies["react-dom"]}"
|
|
112
190
|
shadcn: "${cli.dependencies.shadcn}"
|
|
113
191
|
streamdown: "${cli.dependencies.streamdown}"
|
|
114
|
-
tailwind-merge: "${cli.dependencies["tailwind-merge"]}"
|
|
115
192
|
tailwindcss: "${cli.dependencies.tailwindcss}"
|
|
116
193
|
tw-animate-css: "${cli.dependencies["tw-animate-css"]}"
|
|
117
194
|
typescript: "${cli.peerDependencies.typescript}"
|
|
@@ -126,17 +203,91 @@ minimumReleaseAgeExclude:
|
|
|
126
203
|
- "@hitch42/*"
|
|
127
204
|
`;
|
|
128
205
|
}
|
|
206
|
+
const OXLINT_CONFIG = `{
|
|
207
|
+
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
208
|
+
"plugins": ["eslint", "typescript", "unicorn", "import", "node"],
|
|
209
|
+
"options": { "typeAware": true, "typeCheck": true },
|
|
210
|
+
"env": { "node": true },
|
|
211
|
+
"overrides": [
|
|
212
|
+
{
|
|
213
|
+
"files": ["applets/*/src/client/**"],
|
|
214
|
+
"plugins": ["eslint", "typescript", "unicorn", "import", "react", "react-perf"],
|
|
215
|
+
"env": { "node": false, "browser": true },
|
|
216
|
+
"rules": {
|
|
217
|
+
"react/capitalized-calls": "error",
|
|
218
|
+
"react/error-boundaries": "error",
|
|
219
|
+
"react/exhaustive-effect-dependencies": "error",
|
|
220
|
+
"react/globals": "error",
|
|
221
|
+
"react/hooks": "error",
|
|
222
|
+
"react/immutability": "error",
|
|
223
|
+
"react/incompatible-library": "error",
|
|
224
|
+
"react/invariant": "error",
|
|
225
|
+
"react/memo-dependencies": "error",
|
|
226
|
+
"react/no-deriving-state-in-effects": "error",
|
|
227
|
+
"react/preserve-manual-memoization": "error",
|
|
228
|
+
"react/purity": "error",
|
|
229
|
+
"react/refs": "error",
|
|
230
|
+
"react/rule-suppression": "error",
|
|
231
|
+
"react/set-state-in-effect": "error",
|
|
232
|
+
"react/set-state-in-render": "error",
|
|
233
|
+
"react/static-components": "error",
|
|
234
|
+
"react/syntax": "error",
|
|
235
|
+
"react/todo": "error",
|
|
236
|
+
"react/unsupported-syntax": "error",
|
|
237
|
+
"react/use-memo": "error",
|
|
238
|
+
"react/void-use-memo": "error"
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"files": ["applets/*/test/**"],
|
|
243
|
+
"plugins": ["eslint", "typescript", "unicorn", "import", "vitest"],
|
|
244
|
+
"rules": {
|
|
245
|
+
"vitest/expect-expect": [
|
|
246
|
+
"warn",
|
|
247
|
+
{ "assertFunctionNames": ["expect", "expect*", "assert", "assert.*", "assert*"] }
|
|
248
|
+
]
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
`;
|
|
254
|
+
async function oxfmtConfig(root) {
|
|
255
|
+
const appletsRoot = resolve(root, "applets");
|
|
256
|
+
const overrides = (existsSync(appletsRoot) ? await readdir(appletsRoot) : []).filter((code) => existsSync(resolve(appletsRoot, code, "src/client/styles/globals.css"))).sort().map((code) => `
|
|
257
|
+
{
|
|
258
|
+
"files": ["applets/${code}/**"],
|
|
259
|
+
"options": {
|
|
260
|
+
"sortTailwindcss": {
|
|
261
|
+
"stylesheet": "applets/${code}/src/client/styles/globals.css",
|
|
262
|
+
"functions": ["cn", "cva"]
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}`);
|
|
266
|
+
return `{
|
|
267
|
+
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
|
268
|
+
"sortImports": true,
|
|
269
|
+
"overrides": [${overrides.join(",")}${overrides.length > 0 ? "\n " : ""}]
|
|
270
|
+
}
|
|
271
|
+
`;
|
|
272
|
+
}
|
|
129
273
|
const GITIGNORE_START = "# BEGIN Hitch generated files";
|
|
130
274
|
const GITIGNORE_END = "# END Hitch generated files";
|
|
131
275
|
const SKILLS = [
|
|
132
276
|
"hitch-applets",
|
|
133
277
|
"hitch-cli",
|
|
134
278
|
"hitch-data",
|
|
135
|
-
"hitch-theory"
|
|
279
|
+
"hitch-theory",
|
|
280
|
+
"react-best-practices",
|
|
281
|
+
"tanstack-query",
|
|
282
|
+
"tanstack-router",
|
|
283
|
+
"web-design-guidelines"
|
|
136
284
|
];
|
|
137
285
|
const GITIGNORE = `${GITIGNORE_START}
|
|
138
286
|
${SKILLS.map((skill) => `/.agents/skills/${skill}/`).join("\n")}
|
|
287
|
+
${SKILLS.map((skill) => `/.claude/skills/${skill}`).join("\n")}
|
|
139
288
|
/.node-version
|
|
289
|
+
/.oxfmtrc.json
|
|
290
|
+
/.oxlintrc.json
|
|
140
291
|
/AGENTS.md
|
|
141
292
|
/CLAUDE.md
|
|
142
293
|
/package.json
|
|
@@ -176,10 +327,12 @@ async function writeWorkspaceSupport(root, config, cli) {
|
|
|
176
327
|
const resolvedCli = cli ?? await loadCliManifest();
|
|
177
328
|
if (resolvedCli === void 0) throw new Error("The CLI package manifest is not published.");
|
|
178
329
|
assertWorkspaceCli(config, resolvedCli);
|
|
330
|
+
await ensureAgentConfigs(root, config.org);
|
|
179
331
|
const deployWorkflowTarget = resolve(root, ".github/workflows/hitch.yml");
|
|
180
332
|
const agents = await readFile(new URL("../scaffold/AGENTS.md", import.meta.url), "utf8");
|
|
181
333
|
await Promise.all([
|
|
182
334
|
mkdir(resolve(root, ".agents/skills"), { recursive: true }),
|
|
335
|
+
mkdir(resolve(root, ".claude/skills"), { recursive: true }),
|
|
183
336
|
config.githubWorkflow === false ? void 0 : mkdir(resolve(root, ".github/workflows"), { recursive: true }),
|
|
184
337
|
...SKILLS.map((skill) => rm(resolve(root, ".agents/skills", skill), {
|
|
185
338
|
force: true,
|
|
@@ -192,11 +345,21 @@ async function writeWorkspaceSupport(root, config, cli) {
|
|
|
192
345
|
writeFile(resolve(root, "pnpm-workspace.yaml"), workspaceFile(resolvedCli)),
|
|
193
346
|
config.githubWorkflow === false || existsSync(deployWorkflowTarget) ? void 0 : cp(new URL("../scaffold/.github/workflows/hitch.yml", import.meta.url), deployWorkflowTarget),
|
|
194
347
|
writeFile(resolve(root, ".node-version"), "24\n"),
|
|
348
|
+
writeFile(resolve(root, ".oxlintrc.json"), OXLINT_CONFIG),
|
|
349
|
+
oxfmtConfig(root).then((config) => writeFile(resolve(root, ".oxfmtrc.json"), config)),
|
|
195
350
|
writeGitignore(root),
|
|
196
351
|
writeFile(resolve(root, "AGENTS.md"), agents)
|
|
197
352
|
]);
|
|
198
353
|
await rm(resolve(root, "CLAUDE.md"), { force: true });
|
|
199
354
|
await symlink("AGENTS.md", resolve(root, "CLAUDE.md"));
|
|
355
|
+
await Promise.all(SKILLS.map(async (skill) => {
|
|
356
|
+
const target = resolve(root, ".claude/skills", skill);
|
|
357
|
+
await rm(target, { force: true });
|
|
358
|
+
await symlink(`../../.agents/skills/${skill}`, target, "dir");
|
|
359
|
+
}));
|
|
360
|
+
}
|
|
361
|
+
function sortedByName(packages) {
|
|
362
|
+
return Object.fromEntries(Object.entries(packages).sort(([a], [b]) => a < b ? -1 : 1));
|
|
200
363
|
}
|
|
201
364
|
function appletPackage(definition, options) {
|
|
202
365
|
return {
|
|
@@ -209,14 +372,18 @@ function appletPackage(definition, options) {
|
|
|
209
372
|
generate: "applet generate",
|
|
210
373
|
deploy: "applet deploy",
|
|
211
374
|
test: "vitest run",
|
|
212
|
-
typecheck: "tsc --noEmit"
|
|
375
|
+
typecheck: "tsc --noEmit",
|
|
376
|
+
lint: "oxlint",
|
|
377
|
+
fmt: "oxfmt",
|
|
378
|
+
check: "oxfmt --check && oxlint"
|
|
213
379
|
},
|
|
214
|
-
dependencies: {
|
|
380
|
+
dependencies: sortedByName({
|
|
215
381
|
"@hitch42/applet": "catalog:",
|
|
216
382
|
"@orpc/contract": "catalog:",
|
|
217
383
|
zod: "catalog:",
|
|
218
384
|
...options.hasServer ? { "@orpc/server": "catalog:" } : {},
|
|
219
385
|
...options.hasClient ? {
|
|
386
|
+
"@fontsource-variable/geist-mono": "catalog:",
|
|
220
387
|
"@fontsource-variable/inter": "catalog:",
|
|
221
388
|
"@tanstack/react-query": "catalog:",
|
|
222
389
|
"@tanstack/react-router": "catalog:",
|
|
@@ -229,19 +396,18 @@ function appletPackage(definition, options) {
|
|
|
229
396
|
"@tiptap/react": "catalog:",
|
|
230
397
|
"@tiptap/starter-kit": "catalog:",
|
|
231
398
|
"class-variance-authority": "catalog:",
|
|
232
|
-
|
|
399
|
+
cn: "catalog:",
|
|
233
400
|
"lucide-react": "catalog:",
|
|
234
401
|
react: "catalog:",
|
|
235
402
|
"react-aria-components": "catalog:",
|
|
236
403
|
"react-dom": "catalog:",
|
|
237
404
|
shadcn: "catalog:",
|
|
238
405
|
streamdown: "catalog:",
|
|
239
|
-
"tailwind-merge": "catalog:",
|
|
240
406
|
"tw-animate-css": "catalog:"
|
|
241
407
|
} : {},
|
|
242
408
|
...definition.dependencies
|
|
243
|
-
},
|
|
244
|
-
devDependencies: {
|
|
409
|
+
}),
|
|
410
|
+
devDependencies: sortedByName({
|
|
245
411
|
"@types/node": "catalog:",
|
|
246
412
|
typescript: "catalog:",
|
|
247
413
|
vite: "catalog:",
|
|
@@ -253,9 +419,21 @@ function appletPackage(definition, options) {
|
|
|
253
419
|
tailwindcss: "catalog:"
|
|
254
420
|
} : {},
|
|
255
421
|
...definition.devDependencies
|
|
256
|
-
}
|
|
422
|
+
})
|
|
257
423
|
};
|
|
258
424
|
}
|
|
425
|
+
const LEGACY_CN_HELPER = `import { clsx, type ClassValue } from "clsx";
|
|
426
|
+
import { twMerge } from "tailwind-merge";
|
|
427
|
+
|
|
428
|
+
export function cn(...inputs: ClassValue[]) {
|
|
429
|
+
return twMerge(clsx(inputs));
|
|
430
|
+
}
|
|
431
|
+
`;
|
|
432
|
+
async function replaceLegacyCnHelper(root) {
|
|
433
|
+
const path = resolve(root, "src/client/lib/utils.ts");
|
|
434
|
+
if (!existsSync(path) || await readFile(path, "utf8") !== LEGACY_CN_HELPER) return;
|
|
435
|
+
await cp(new URL("../scaffold/applet/src/client/lib/utils.ts", import.meta.url), path);
|
|
436
|
+
}
|
|
259
437
|
async function writeAppletSupport(root, definition) {
|
|
260
438
|
const hasClient = existsSync(resolve(root, "src/client/routes"));
|
|
261
439
|
const hasAuthorRoot = existsSync(resolve(root, "src/client/routes/__root.tsx"));
|
|
@@ -264,6 +442,7 @@ async function writeAppletSupport(root, definition) {
|
|
|
264
442
|
if (!hasServer && (definition.schedules?.length ?? 0) > 0) throw new Error("An applet with schedules must have src/server/main.ts.");
|
|
265
443
|
await Promise.all(hasClient ? [] : [rm(resolve(root, "index.html"), { force: true }), rm(resolve(root, "components.json"), { force: true })]);
|
|
266
444
|
await Promise.all([
|
|
445
|
+
replaceLegacyCnHelper(root),
|
|
267
446
|
writeFile(resolve(root, "package.json"), `${JSON.stringify(appletPackage(definition, {
|
|
268
447
|
hasClient,
|
|
269
448
|
hasServer
|
|
@@ -335,7 +514,9 @@ export default defineConfig({
|
|
|
335
514
|
"./.hitch/*.ts",
|
|
336
515
|
"./.hitch/*.tsx",
|
|
337
516
|
"./src/**/*.ts",
|
|
338
|
-
"./src/**/*.tsx"
|
|
517
|
+
"./src/**/*.tsx",
|
|
518
|
+
"./test/**/*.ts",
|
|
519
|
+
"./test/**/*.tsx"
|
|
339
520
|
]
|
|
340
521
|
}
|
|
341
522
|
`),
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//#region src/internal/query-cache.ts
|
|
2
|
+
const STORE = "clients";
|
|
3
|
+
const TIMESTAMP_INDEX = "timestamp";
|
|
4
|
+
const TAB_KEY = "hitch:query-tab";
|
|
5
|
+
const SAVE_INTERVAL = 1e3;
|
|
6
|
+
function openQueryCacheDatabase() {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const open = indexedDB.open("hitch-query-cache", 1);
|
|
9
|
+
open.onupgradeneeded = () => {
|
|
10
|
+
open.result.createObjectStore("clients").createIndex("timestamp", "timestamp");
|
|
11
|
+
};
|
|
12
|
+
open.onblocked = () => reject(/* @__PURE__ */ new Error("The query cache is open in an older tab."));
|
|
13
|
+
open.onsuccess = () => {
|
|
14
|
+
open.result.onversionchange = () => open.result.close();
|
|
15
|
+
resolve(open.result);
|
|
16
|
+
};
|
|
17
|
+
open.onerror = () => reject(open.error);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
let database;
|
|
21
|
+
function openCacheDatabase() {
|
|
22
|
+
database ??= window.__hitchCacheDatabase ?? openQueryCacheDatabase();
|
|
23
|
+
return database;
|
|
24
|
+
}
|
|
25
|
+
async function inStore(mode, run) {
|
|
26
|
+
const transaction = (await openCacheDatabase()).transaction(STORE, mode);
|
|
27
|
+
const request = run(transaction.objectStore(STORE));
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
transaction.oncomplete = () => resolve(request.result);
|
|
30
|
+
transaction.onabort = () => reject(transaction.error ?? request.error);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function cacheTabId() {
|
|
34
|
+
const existing = sessionStorage.getItem(TAB_KEY);
|
|
35
|
+
if (existing) return existing;
|
|
36
|
+
const id = crypto.randomUUID();
|
|
37
|
+
sessionStorage.setItem(TAB_KEY, id);
|
|
38
|
+
return id;
|
|
39
|
+
}
|
|
40
|
+
function indexedDbPersister(key) {
|
|
41
|
+
let pending;
|
|
42
|
+
let throttled = false;
|
|
43
|
+
const save = (client) => inStore("readwrite", (store) => store.put(client, key)).then(() => void 0, (error) => console.error("Could not persist the applet query cache.", error));
|
|
44
|
+
const release = () => {
|
|
45
|
+
if (!pending) {
|
|
46
|
+
throttled = false;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
save(pending);
|
|
50
|
+
pending = void 0;
|
|
51
|
+
setTimeout(release, SAVE_INTERVAL);
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
persistClient: (client) => {
|
|
55
|
+
if (throttled) {
|
|
56
|
+
pending = client;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
throttled = true;
|
|
60
|
+
setTimeout(release, SAVE_INTERVAL);
|
|
61
|
+
return save(client);
|
|
62
|
+
},
|
|
63
|
+
restoreClient: () => inStore("readonly", (store) => store.get(key)),
|
|
64
|
+
removeClient: () => inStore("readwrite", (store) => store.delete(key))
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function sweepExpiredQueryCaches(maxAge) {
|
|
68
|
+
return inStore("readwrite", (store) => {
|
|
69
|
+
const cursor = store.index(TIMESTAMP_INDEX).openKeyCursor(IDBKeyRange.upperBound(Date.now() - maxAge));
|
|
70
|
+
cursor.onsuccess = () => {
|
|
71
|
+
if (!cursor.result) return;
|
|
72
|
+
store.delete(cursor.result.primaryKey);
|
|
73
|
+
cursor.result.continue();
|
|
74
|
+
};
|
|
75
|
+
return cursor;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function clearAppletQueryCaches(appletCode) {
|
|
79
|
+
return inStore("readwrite", (store) => store.delete(IDBKeyRange.bound(`${appletCode}:`, `${appletCode}:\uffff`)));
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
export { openQueryCacheDatabase as a, openCacheDatabase as i, clearAppletQueryCaches as n, sweepExpiredQueryCaches as o, indexedDbPersister as r, cacheTabId as t };
|
package/dist/react.d.ts
CHANGED
|
@@ -29,9 +29,10 @@ type MarkdownEditorProps = {
|
|
|
29
29
|
minLength?: number;
|
|
30
30
|
maxLength?: number;
|
|
31
31
|
disabled?: boolean;
|
|
32
|
+
autoFocus?: boolean;
|
|
32
33
|
className?: string;
|
|
33
34
|
onUploadError?: (error: unknown, file: File) => void;
|
|
34
35
|
};
|
|
35
|
-
declare function MarkdownEditor({ value, onChange, files, id, placeholder, required, minLength, maxLength, disabled, className, onUploadError }: MarkdownEditorProps): ReactElement;
|
|
36
|
+
declare function MarkdownEditor({ value, onChange, files, id, placeholder, required, minLength, maxLength, disabled, autoFocus, className, onUploadError }: MarkdownEditorProps): ReactElement;
|
|
36
37
|
//#endregion
|
|
37
38
|
export { Markdown, MarkdownEditor, type MarkdownEditorFiles, type MarkdownEditorProps, type MarkdownFiles, type MarkdownProps };
|