@hitch42/applet 0.1.1-beta.18 → 0.1.1-beta.20
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/applet.js +11 -11
- package/dist/{build-DkKTiIu7.js → build-D47vK5aa.js} +1 -1
- package/dist/build-JtbY8q2p.js +2 -0
- package/dist/{ci-B5-mH-YW.js → ci-BTFTCBgy.js} +6 -1
- package/dist/client/hitch/client.d.ts +1 -1
- package/dist/client/hitch.d.ts +1 -1
- package/dist/create-C2UrZYSK.d.ts +72 -0
- package/dist/{deploy-DODTE8ri.js → deploy-BbqyK5Ik.js} +2 -2
- package/dist/{generate-8yyxKRSz.js → generate-BLD0DoCk.js} +31 -7
- package/dist/generate-COCRy1Bs.js +2 -0
- package/dist/{hitch-client--qZVa2KM.d.ts → hitch-client-DtyTZzP5.d.ts} +5 -4
- package/dist/{init-DT0faD-q.js → init-BKUBf6i9.js} +3 -3
- package/dist/{load-config-BYrBjPlr.js → load-config-DGALUExv.js} +4 -1
- package/dist/{logs-CEIikWzV.js → logs-Cv5z1e2w.js} +1 -1
- package/dist/{project-CWVwic2C.js → project-CrxdZR0B.js} +13 -6
- package/dist/{schedules-B7xNl9oy.js → schedules-Dajgni_z.js} +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/{variables-DCbLJBr0.js → variables-B-CLu8cY.js} +1 -1
- package/dist/vite.js +7 -6
- package/package.json +1 -1
- package/scaffold/.agents/skills/hitch-applets/SKILL.md +1 -1
- package/scaffold/.agents/skills/hitch-applets/references/records.md +16 -1
- package/dist/batch-Qa4B4-Yp.d.ts +0 -30
- package/dist/build-DpkWOvd2.js +0 -2
- package/dist/generate-Df29-UJm.js +0 -2
package/dist/applet.js
CHANGED
|
@@ -99,23 +99,23 @@ async function main() {
|
|
|
99
99
|
const noLogFlags = values.run === void 0 && values.filter === void 0 && values.level === void 0 && values.limit === void 0 && values.live === void 0 && values.search === void 0 && values.since === void 0;
|
|
100
100
|
const noModeFlags = values["client-only"] === void 0 && values["server-only"] === void 0;
|
|
101
101
|
if (positionals.length === 1 && positionals[0] === "bootstrap" && noModeFlags && noGitFlags && noVariableFlags && noLogFlags) {
|
|
102
|
-
await (await import("./init-
|
|
102
|
+
await (await import("./init-BKUBf6i9.js")).runBootstrap({ install: values["no-install"] !== true });
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
105
|
if (positionals.length === 1 && positionals[0] === "generate" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noVariableFlags && noLogFlags) {
|
|
106
|
-
await (await import("./generate-
|
|
106
|
+
await (await import("./generate-COCRy1Bs.js")).runGenerate();
|
|
107
107
|
return;
|
|
108
108
|
}
|
|
109
109
|
if (positionals.length === 1 && positionals[0] === "build" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noVariableFlags && noLogFlags) {
|
|
110
|
-
await (await import("./build-
|
|
110
|
+
await (await import("./build-JtbY8q2p.js")).runBuild();
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
113
|
if (positionals.length === 1 && positionals[0] === "deploy" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noVariableFlags && noLogFlags) {
|
|
114
|
-
await (await import("./deploy-
|
|
114
|
+
await (await import("./deploy-BbqyK5Ik.js")).runDeploy({});
|
|
115
115
|
return;
|
|
116
116
|
}
|
|
117
117
|
if (positionals.length === 2 && positionals[0] === "init" && noModeFlags && noVariableFlags && noLogFlags) {
|
|
118
|
-
await (await import("./init-
|
|
118
|
+
await (await import("./init-BKUBf6i9.js")).runInit(positionals[1], {
|
|
119
119
|
commit: values["no-commit"] !== true,
|
|
120
120
|
git: values["no-git"] !== true,
|
|
121
121
|
install: values["no-install"] !== true
|
|
@@ -123,7 +123,7 @@ async function main() {
|
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
125
|
if (positionals.length === 2 && positionals[0] === "new" && noGitFlags && noVariableFlags && noLogFlags) {
|
|
126
|
-
await (await import("./init-
|
|
126
|
+
await (await import("./init-BKUBf6i9.js")).runNew({
|
|
127
127
|
code: positionals[1],
|
|
128
128
|
clientOnly: values["client-only"],
|
|
129
129
|
install: values["no-install"] !== true,
|
|
@@ -132,7 +132,7 @@ async function main() {
|
|
|
132
132
|
return;
|
|
133
133
|
}
|
|
134
134
|
if ((positionals.length === 1 || positionals.length === 2) && positionals[0] === "logs" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noVariableFlags) {
|
|
135
|
-
await (await import("./logs-
|
|
135
|
+
await (await import("./logs-Cv5z1e2w.js")).runLogs({
|
|
136
136
|
code: positionals[1],
|
|
137
137
|
filter: values.filter,
|
|
138
138
|
run: values.run,
|
|
@@ -145,14 +145,14 @@ async function main() {
|
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
147
|
if (positionals.length === 3 && positionals[0] === "schedules" && positionals[1] === "run" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noLogFlags && values.secret === void 0) {
|
|
148
|
-
await (await import("./schedules-
|
|
148
|
+
await (await import("./schedules-Dajgni_z.js")).runSchedule({
|
|
149
149
|
code: positionals[2],
|
|
150
150
|
yes: values.yes
|
|
151
151
|
});
|
|
152
152
|
return;
|
|
153
153
|
}
|
|
154
154
|
if ((positionals.length === 3 || positionals.length === 4) && positionals[0] === "variables" && positionals[1] === "set" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noLogFlags) {
|
|
155
|
-
await (await import("./variables-
|
|
155
|
+
await (await import("./variables-B-CLu8cY.js")).runVariablesSet({
|
|
156
156
|
key: positionals[2],
|
|
157
157
|
secret: values.secret,
|
|
158
158
|
value: positionals[3],
|
|
@@ -161,11 +161,11 @@ async function main() {
|
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
163
163
|
if (positionals.length === 2 && positionals[0] === "variables" && positionals[1] === "list" && values["no-install"] === void 0 && noModeFlags && noGitFlags && noVariableFlags && noLogFlags) {
|
|
164
|
-
await (await import("./variables-
|
|
164
|
+
await (await import("./variables-B-CLu8cY.js")).runVariablesList();
|
|
165
165
|
return;
|
|
166
166
|
}
|
|
167
167
|
if (positionals.length === 3 && positionals[0] === "variables" && positionals[1] === "delete" && values["no-install"] === void 0 && noModeFlags && noGitFlags && values.secret === void 0 && noLogFlags) {
|
|
168
|
-
await (await import("./variables-
|
|
168
|
+
await (await import("./variables-B-CLu8cY.js")).runVariablesDelete({
|
|
169
169
|
key: positionals[2],
|
|
170
170
|
yes: values.yes
|
|
171
171
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as prepareAppletProjects, r as prepareAppletProject } from "./project-
|
|
1
|
+
import { i as prepareAppletProjects, r as prepareAppletProject } from "./project-CrxdZR0B.js";
|
|
2
2
|
import { rm } from "node:fs/promises";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { c as resolveInstanceUrl } from "./store-B8N_8JIN.js";
|
|
2
|
+
import { a as userAgent } from "./project-CrxdZR0B.js";
|
|
2
3
|
//#region src/ci.ts
|
|
3
4
|
function githubActionsContext() {
|
|
4
5
|
const env = process.env;
|
|
@@ -38,9 +39,13 @@ async function fetchWithGitHubActions(context, request) {
|
|
|
38
39
|
async function loadGitHubActionsBuildInputs(context, requiresChangeset) {
|
|
39
40
|
const fetcher = globalThis.fetch;
|
|
40
41
|
const query = requiresChangeset === void 0 ? "" : `?changeset_id=${encodeURIComponent(requiresChangeset)}`;
|
|
42
|
+
const agent = await userAgent();
|
|
41
43
|
const response = await fetchWithGitHubActions(context, (instanceUrl, accessToken) => fetcher(`${instanceUrl}/api/ci/v1/build-inputs${query}`, {
|
|
42
44
|
method: "POST",
|
|
43
|
-
headers: {
|
|
45
|
+
headers: {
|
|
46
|
+
Authorization: `Bearer ${accessToken}`,
|
|
47
|
+
"User-Agent": agent
|
|
48
|
+
}
|
|
44
49
|
}));
|
|
45
50
|
if (!response.ok) throw await hitchResponseError(response, "Failed to load the CI build inputs");
|
|
46
51
|
const body = await response.json();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as hitch } from "../../hitch-client
|
|
1
|
+
import { t as hitch } from "../../hitch-client-DtyTZzP5.js";
|
|
2
2
|
export { hitch };
|
package/dist/client/hitch.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as hitch } from "../hitch-client
|
|
1
|
+
import { t as hitch } from "../hitch-client-DtyTZzP5.js";
|
|
2
2
|
import { i as createPhone, n as Phone, r as PhoneState, t as usePhone } from "../use-phone-M7c_HsB7.js";
|
|
3
3
|
export { type Phone, type PhoneState, createPhone, hitch, usePhone };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { AnyContractRouter } from "@orpc/contract";
|
|
2
|
+
import { ClientPromiseResult } from "@orpc/client";
|
|
3
|
+
//#region src/hitch/batch.d.ts
|
|
4
|
+
type BatchVerb = "create" | "update" | "delete" | "updateWhere";
|
|
5
|
+
type BatchTxRecords<Records> = { [Code in keyof Records]: { [Verb in keyof Records[Code] & BatchVerb]: Records[Code][Verb] extends ((...args: infer Args) => unknown) ? (input: Verb extends "create" ? Args[0] extends {
|
|
6
|
+
body: infer Body;
|
|
7
|
+
} ? Omit<Args[0], "body"> & {
|
|
8
|
+
body: Exclude<Body, readonly unknown[]>;
|
|
9
|
+
} : Args[0] : Args[0]) => void : never; }; };
|
|
10
|
+
type BatchTx<T> = T extends {
|
|
11
|
+
records: infer Records;
|
|
12
|
+
} ? BatchTxRecords<Records> : never;
|
|
13
|
+
type BatchRecorderOptions = {
|
|
14
|
+
dryRun?: boolean;
|
|
15
|
+
idempotencyKey?: string;
|
|
16
|
+
};
|
|
17
|
+
type BatchRecorderCall<T, Batch> = Batch extends ((...args: infer _Args) => infer Result) ? (record: (tx: BatchTx<T>) => void | Promise<void>, options?: BatchRecorderOptions) => Result : never;
|
|
18
|
+
type WithBatchRecorder<T> = T extends {
|
|
19
|
+
records: unknown;
|
|
20
|
+
batch: infer Batch;
|
|
21
|
+
} ? Omit<T, "batch"> & {
|
|
22
|
+
/**
|
|
23
|
+
* Record record writes inside `record` and send them as one atomic batch.
|
|
24
|
+
*
|
|
25
|
+
* The callback receives a `tx` whose `create` / `update` / `updateWhere` /
|
|
26
|
+
* `delete` calls are buffered, not sent immediately; the whole batch runs
|
|
27
|
+
* in a single transaction when the callback resolves.
|
|
28
|
+
*
|
|
29
|
+
* @remarks A batch may contain at most **100** requests. More than that is
|
|
30
|
+
* rejected with a `400` before any write runs.
|
|
31
|
+
*/
|
|
32
|
+
batch: BatchRecorderCall<T, Batch> & Batch;
|
|
33
|
+
} : T;
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/hitch/create.d.ts
|
|
36
|
+
type Many<T> = Extract<T, readonly unknown[]>;
|
|
37
|
+
type One<T> = Exclude<T, readonly unknown[]>;
|
|
38
|
+
type SplitCreate<F> = F extends ((input: infer Input extends {
|
|
39
|
+
body: unknown;
|
|
40
|
+
}, ...rest: infer Rest) => ClientPromiseResult<infer Output, infer TError>) ? [Many<Input["body"]>] extends [never] ? F : {
|
|
41
|
+
(input: Omit<Input, "body"> & {
|
|
42
|
+
body: Many<Input["body"]>;
|
|
43
|
+
}, ...rest: Rest): ClientPromiseResult<Many<Output>, TError>;
|
|
44
|
+
(input: Omit<Input, "body"> & {
|
|
45
|
+
body: One<Input["body"]>;
|
|
46
|
+
}, ...rest: Rest): ClientPromiseResult<One<Output>, TError>;
|
|
47
|
+
} : F extends {
|
|
48
|
+
call: infer Call;
|
|
49
|
+
} ? Omit<F, "call"> & {
|
|
50
|
+
call: SplitCreate<Call>;
|
|
51
|
+
} : F;
|
|
52
|
+
type WithRecordCreates<T> = T extends {
|
|
53
|
+
records: infer Records;
|
|
54
|
+
} ? Omit<T, "records"> & {
|
|
55
|
+
records: { [Code in keyof Records]: { [Verb in keyof Records[Code]]: Verb extends "create" ? SplitCreate<Records[Code][Verb]> : Records[Code][Verb]; }; };
|
|
56
|
+
} : T;
|
|
57
|
+
type WithSingleRecordCreates<T> = T extends {
|
|
58
|
+
records: infer Records;
|
|
59
|
+
} ? Omit<T, "records"> & {
|
|
60
|
+
records: { [Code in keyof Records]: { [Verb in keyof Records[Code]]: Verb extends "create" ? SplitCreate<Records[Code][Verb]> extends ((...args: infer Args) => infer Result) ? (...args: Args) => Result : Records[Code][Verb] : Records[Code][Verb]; }; };
|
|
61
|
+
} : T;
|
|
62
|
+
type WithRecordCreateCalls<Utils, Client> = Utils extends {
|
|
63
|
+
records: infer Records;
|
|
64
|
+
} ? Client extends {
|
|
65
|
+
records: infer Clients;
|
|
66
|
+
} ? Omit<Utils, "records"> & {
|
|
67
|
+
records: { [Code in keyof Records]: { [Verb in keyof Records[Code]]: Verb extends "create" ? Code extends keyof Clients ? Verb extends keyof Clients[Code] ? Omit<Records[Code][Verb], "call"> & {
|
|
68
|
+
call: SplitCreate<Clients[Code][Verb]>;
|
|
69
|
+
} : Records[Code][Verb] : Records[Code][Verb] : Records[Code][Verb]; }; };
|
|
70
|
+
} : Utils : Utils;
|
|
71
|
+
//#endregion
|
|
72
|
+
export { WithBatchRecorder as i, WithRecordCreates as n, WithSingleRecordCreates as r, WithRecordCreateCalls as t };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as readWorkspaceConfig } from "./workspace-8yqXsvce.js";
|
|
2
2
|
import { t as fetchWithOrgAuth } from "./auth-D3CrCtZq.js";
|
|
3
|
-
import { a as loadGitHubActionsSources, n as githubActionsContext, r as hitchResponseError, t as fetchWithGitHubActions } from "./ci-
|
|
4
|
-
import { n as buildPreparedApplet, r as prepareWorkspaceBuild, t as buildApplet } from "./build-
|
|
3
|
+
import { a as loadGitHubActionsSources, n as githubActionsContext, r as hitchResponseError, t as fetchWithGitHubActions } from "./ci-BTFTCBgy.js";
|
|
4
|
+
import { n as buildPreparedApplet, r as prepareWorkspaceBuild, t as buildApplet } from "./build-D47vK5aa.js";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
7
|
import { existsSync } from "node:fs";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { a as organizationInstanceUrl, c as resolveInstanceUrl } from "./store-B8N_8JIN.js";
|
|
2
2
|
import { t as fetchWithOrgAuth } from "./auth-D3CrCtZq.js";
|
|
3
|
-
import { t as loadAppletConfig } from "./load-config-
|
|
4
|
-
import {
|
|
5
|
-
import { r as
|
|
3
|
+
import { t as loadAppletConfig } from "./load-config-DGALUExv.js";
|
|
4
|
+
import { a as userAgent, r as prepareAppletProject } from "./project-CrxdZR0B.js";
|
|
5
|
+
import { i as loadGitHubActionsBuildInputs, n as githubActionsContext, r as hitchResponseError } from "./ci-BTFTCBgy.js";
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import { isContractProcedure, minifyContractRouter } from "@orpc/contract";
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
@@ -58,6 +58,20 @@ export default createWorkerEntry(server, { code: ${JSON.stringify(appletCode)} }
|
|
|
58
58
|
`);
|
|
59
59
|
}
|
|
60
60
|
//#endregion
|
|
61
|
+
//#region src/typegen/create-schema.ts
|
|
62
|
+
function isObject$3(value) {
|
|
63
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
64
|
+
}
|
|
65
|
+
function isComponentRef(value) {
|
|
66
|
+
return isObject$3(value) && typeof value.$ref === "string" && /^#\/components\/schemas\/[^/]+$/.test(value.$ref);
|
|
67
|
+
}
|
|
68
|
+
function singleCreateSchema(value) {
|
|
69
|
+
if (isComponentRef(value)) return value;
|
|
70
|
+
if (!isObject$3(value) || !Array.isArray(value.oneOf) || value.oneOf.length !== 2) return void 0;
|
|
71
|
+
const [single, array] = value.oneOf;
|
|
72
|
+
return isComponentRef(single) && isObject$3(array) && array.type === "array" && isComponentRef(array.items) && array.items.$ref === single.$ref ? single : void 0;
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
61
75
|
//#region src/typegen/operations.ts
|
|
62
76
|
const RECORD_ROUTE = /^\/v1\/([^/]+)(?:\/(\{id\}(?:\/history)?|query|update|aggregate))?$/;
|
|
63
77
|
const COMPONENT_REF_PREFIX$1 = "#/components/schemas/";
|
|
@@ -195,9 +209,15 @@ function prepareRecordSpec(spec, manifest) {
|
|
|
195
209
|
const content = isObject$2(response?.content) ? response.content : void 0;
|
|
196
210
|
const mediaType = isObject$2(content?.["application/json"]) ? content["application/json"] : void 0;
|
|
197
211
|
const schema = isObject$2(mediaType) ? mediaType.schema : void 0;
|
|
198
|
-
const ref = isObject$2(schema) ? schema.$ref : void 0;
|
|
212
|
+
const ref = record.verb === "create" ? singleCreateSchema(schema)?.$ref : isObject$2(schema) ? schema.$ref : void 0;
|
|
199
213
|
if (typeof ref !== "string" || !ref.startsWith(COMPONENT_REF_PREFIX$1) || ref.slice(21).length === 0 || ref.slice(21).includes("/")) throw new Error(`object "${record.objectCode}": paths.${path}.${method}.responses.${status}.content.application/json.schema expected a component schema $ref, found ${describeValue$1(schema, true)}`);
|
|
200
214
|
}
|
|
215
|
+
if (record.verb === "create") {
|
|
216
|
+
const request = isObject$2(operation.requestBody) ? operation.requestBody : void 0;
|
|
217
|
+
const content = isObject$2(request?.content) ? request.content : void 0;
|
|
218
|
+
const body = isObject$2(content?.["application/json"]) ? content["application/json"] : void 0;
|
|
219
|
+
if (singleCreateSchema(body?.schema) === void 0) throw new Error(`object "${record.objectCode}": paths.${path}.${method}.requestBody.content.application/json.schema expected a component schema $ref or single/array oneOf, found ${describeValue$1(body?.schema, true)}`);
|
|
220
|
+
}
|
|
201
221
|
const prepared = withRecordOperationId(path, method, operation);
|
|
202
222
|
return prepared ? [[method, prepared]] : [];
|
|
203
223
|
});
|
|
@@ -262,7 +282,7 @@ function describeValue(value, objectDescription = "an object") {
|
|
|
262
282
|
return `${typeof value} ${JSON.stringify(value)}`;
|
|
263
283
|
}
|
|
264
284
|
function componentName(value, path, objectCode) {
|
|
265
|
-
const ref =
|
|
285
|
+
const ref = singleCreateSchema(value)?.$ref;
|
|
266
286
|
if (typeof ref !== "string" || !ref.startsWith(COMPONENT_REF_PREFIX)) throw new Error(`object "${objectCode}": ${path} expected a component schema $ref, found ${describeValue(value, "an object without a $ref")}`);
|
|
267
287
|
const name = ref.slice(21);
|
|
268
288
|
if (name.length === 0 || name.includes("/")) throw new Error(`object "${objectCode}": ${path} expected a direct component schema $ref, found ${JSON.stringify(ref)}`);
|
|
@@ -427,8 +447,12 @@ async function responseJson(response) {
|
|
|
427
447
|
async function loadAuthenticatedSpec(manifest) {
|
|
428
448
|
const github = githubActionsContext();
|
|
429
449
|
if (github !== void 0) return (await loadGitHubActionsBuildInputs(github, manifest.requiresChangeset)).openapi;
|
|
430
|
-
const
|
|
431
|
-
|
|
450
|
+
const agent = await userAgent();
|
|
451
|
+
const response = await fetchWithOrgAuth(manifest.org, (instanceUrl, accessToken) => globalThis.fetch(`${instanceUrl}/api/v1/openapi.json${manifest.requiresChangeset === void 0 ? "" : `?changeset_id=${encodeURIComponent(manifest.requiresChangeset)}`}`, { headers: {
|
|
452
|
+
Authorization: `Bearer ${accessToken}`,
|
|
453
|
+
"User-Agent": agent
|
|
454
|
+
} }));
|
|
455
|
+
if (!response.ok) throw await hitchResponseError(response, "Failed to load the organization's OpenAPI spec");
|
|
432
456
|
return responseJson(response);
|
|
433
457
|
}
|
|
434
458
|
async function loadThemeStylesheet(orgCode) {
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { l as RegisteredContract, u as RegisteredManifest } from "./manifest-BBHD_EY9.js";
|
|
2
2
|
import { t as NarrowContract } from "./contract-CJv-n1l3.js";
|
|
3
|
-
import {
|
|
3
|
+
import { i as WithBatchRecorder, n as WithRecordCreates, r as WithSingleRecordCreates, t as WithRecordCreateCalls } from "./create-C2UrZYSK.js";
|
|
4
4
|
import { o as WithFilesUpload } from "./upload-D_kkmne_.js";
|
|
5
5
|
import { t as ExactRouterUtils } from "./query-utils-zz9pVjgp.js";
|
|
6
6
|
import { ContractRouterClient } from "@orpc/contract";
|
|
7
7
|
//#region src/author/hitch-client.d.ts
|
|
8
8
|
type AuthorContract = NarrowContract<RegisteredContract, RegisteredManifest>;
|
|
9
9
|
type BaseHitchClient = ContractRouterClient<AuthorContract>;
|
|
10
|
-
type AuthorHitchClient = WithBatchRecorder<BaseHitchClient
|
|
11
|
-
type BaseHitchUtils = ExactRouterUtils<BaseHitchClient
|
|
12
|
-
type AuthorHitchUtils =
|
|
10
|
+
type AuthorHitchClient = WithRecordCreates<WithBatchRecorder<BaseHitchClient>>;
|
|
11
|
+
type BaseHitchUtils = ExactRouterUtils<WithSingleRecordCreates<BaseHitchClient>>;
|
|
12
|
+
type AuthorHitchUtils = WithRecordCreateCalls<BatchHitchUtils, BaseHitchClient>;
|
|
13
|
+
type BatchHitchUtils = AuthorHitchClient extends {
|
|
13
14
|
batch: infer Batch;
|
|
14
15
|
} ? BaseHitchUtils extends {
|
|
15
16
|
batch: infer BatchUtils;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { c as resolveInstanceUrl, s as resolveAuthForOrg } from "./store-B8N_8JIN.js";
|
|
2
2
|
import { n as readWorkspaceConfig } from "./workspace-8yqXsvce.js";
|
|
3
|
-
import { r as runGenerate } from "./generate-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { r as runGenerate } from "./generate-BLD0DoCk.js";
|
|
4
|
+
import { c as ORG_CODE_PATTERN, n as loadAppletSourceDefinition, s as APPLET_CODE_PATTERN } from "./load-config-DGALUExv.js";
|
|
5
|
+
import { n as loadCliManifest, o as writeAppletSupport, s as writeWorkspaceSupport, t as assertWorkspaceCli } from "./project-CrxdZR0B.js";
|
|
6
6
|
import { access, cp, mkdir, readdir, writeFile } from "node:fs/promises";
|
|
7
7
|
import { relative, resolve } from "node:path";
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
@@ -135,6 +135,9 @@ z.strictObject({
|
|
|
135
135
|
variables: appletManifestShape.variables,
|
|
136
136
|
objects: appletManifestShape.objects
|
|
137
137
|
}).superRefine(checkDuplicateCodes).superRefine(checkPublicFields);
|
|
138
|
+
function appletMountPath({ code, public: isPublic }) {
|
|
139
|
+
return isPublic ? `pages/${code}` : code;
|
|
140
|
+
}
|
|
138
141
|
const packageVersionsSchema = z.record(z.string().min(1), z.string().min(1)).readonly();
|
|
139
142
|
const RESERVED_APPLET_PACKAGES = /* @__PURE__ */ new Set([
|
|
140
143
|
"@fontsource-variable/geist-mono",
|
|
@@ -247,4 +250,4 @@ async function loadAppletConfig(root) {
|
|
|
247
250
|
};
|
|
248
251
|
}
|
|
249
252
|
//#endregion
|
|
250
|
-
export {
|
|
253
|
+
export { appletMountPath as a, ORG_CODE_PATTERN as c, appletManifestSchema as i, loadAppletSourceDefinition as n, appletSourceDefinitionSchema as o, resolveWorkspaceOrg as r, APPLET_CODE_PATTERN as s, loadAppletConfig as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as readWorkspaceConfig } from "./workspace-8yqXsvce.js";
|
|
2
2
|
import { t as fetchWithOrgAuth } from "./auth-D3CrCtZq.js";
|
|
3
|
-
import {
|
|
3
|
+
import { r as resolveWorkspaceOrg, s as APPLET_CODE_PATTERN, t as loadAppletConfig } from "./load-config-DGALUExv.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
//#region src/logs.ts
|
|
6
6
|
const LOG_LEVELS = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as organizationInstanceUrl, n as DEFAULT_INSTANCE_URL } from "./store-B8N_8JIN.js";
|
|
2
2
|
import { n as readWorkspaceConfig } from "./workspace-8yqXsvce.js";
|
|
3
|
-
import { n as loadAppletSourceDefinition } from "./load-config-
|
|
3
|
+
import { a as appletMountPath, n as loadAppletSourceDefinition } from "./load-config-DGALUExv.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
6
|
import { cp, mkdir, readFile, readdir, rm, symlink, writeFile } from "node:fs/promises";
|
|
@@ -115,19 +115,26 @@ const cliManifestSchema = z.object({
|
|
|
115
115
|
typescript: cliManifestValueSchema
|
|
116
116
|
})
|
|
117
117
|
});
|
|
118
|
-
async function
|
|
118
|
+
async function loadPackageManifest() {
|
|
119
119
|
const result = cliManifestSchema.safeParse(JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8")));
|
|
120
120
|
if (!result.success) {
|
|
121
121
|
const issue = result.error.issues.at(0);
|
|
122
122
|
if (issue === void 0) throw new Error("Invalid CLI package manifest.");
|
|
123
123
|
throw new Error(`Invalid CLI package manifest field "${issue.path.join(".")}": ${issue.message}.`);
|
|
124
124
|
}
|
|
125
|
-
|
|
125
|
+
return result.data;
|
|
126
|
+
}
|
|
127
|
+
async function userAgent() {
|
|
128
|
+
return `hitch-applet-sdk/${(await loadPackageManifest()).version}`;
|
|
129
|
+
}
|
|
130
|
+
async function loadCliManifest(options) {
|
|
131
|
+
const cli = await loadPackageManifest();
|
|
132
|
+
const catalogEntry = [...Object.entries(cli.dependencies).map(([name, value]) => [`dependencies.${name}`, value]), ...Object.entries(cli.peerDependencies).map(([name, value]) => [`peerDependencies.${name}`, value])].find(([, value]) => value.startsWith("catalog:"));
|
|
126
133
|
if (catalogEntry !== void 0) {
|
|
127
134
|
if (options?.allowDevelopment === true) return void 0;
|
|
128
135
|
throw new Error(`Invalid CLI package manifest field "${catalogEntry[0]}": "catalog:" identifies an unpublished development build. Run the published @hitch42/applet CLI instead.`);
|
|
129
136
|
}
|
|
130
|
-
return
|
|
137
|
+
return cli;
|
|
131
138
|
}
|
|
132
139
|
function assertWorkspaceCli(config, cli) {
|
|
133
140
|
const runningCli = `${cli.name}@${cli.version}`;
|
|
@@ -497,7 +504,7 @@ export default defineConfig({
|
|
|
497
504
|
children: [{
|
|
498
505
|
type: "physical",
|
|
499
506
|
directory: ".",
|
|
500
|
-
pathPrefix: definition
|
|
507
|
+
pathPrefix: appletMountPath(definition)
|
|
501
508
|
}]
|
|
502
509
|
}
|
|
503
510
|
}, null, 2)}\n`) : rm(resolve(root, "tsr.config.json"), { force: true }),
|
|
@@ -562,4 +569,4 @@ async function prepareAppletProject(appletRoot = process.cwd()) {
|
|
|
562
569
|
return workspaceRoot;
|
|
563
570
|
}
|
|
564
571
|
//#endregion
|
|
565
|
-
export {
|
|
572
|
+
export { userAgent as a, prepareAppletProjects as i, loadCliManifest as n, writeAppletSupport as o, prepareAppletProject as r, writeWorkspaceSupport as s, assertWorkspaceCli as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as loadAppletConfig } from "./load-config-
|
|
1
|
+
import { t as loadAppletConfig } from "./load-config-DGALUExv.js";
|
|
2
2
|
import { t as question } from "./prompt-ChS-grYO.js";
|
|
3
3
|
import { RPCLink } from "@orpc/client/fetch";
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
package/dist/server.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as createWorkflow, i as WorkflowStep, n as WorkflowDefinition, r as WorkflowDuration } from "./workflow-DurM6Fwx.js";
|
|
2
2
|
import { l as RegisteredContract, m as RegisteredWorkflows, p as RegisteredVariables, u as RegisteredManifest } from "./manifest-BBHD_EY9.js";
|
|
3
3
|
import { t as NarrowContract } from "./contract-CJv-n1l3.js";
|
|
4
|
-
import {
|
|
4
|
+
import { i as WithBatchRecorder, n as WithRecordCreates } from "./create-C2UrZYSK.js";
|
|
5
5
|
import { o as WithFilesUpload } from "./upload-D_kkmne_.js";
|
|
6
6
|
import { ContractRouterClient } from "@orpc/contract";
|
|
7
7
|
//#region src/server/workflows-client.d.ts
|
|
@@ -43,7 +43,7 @@ declare const log: {
|
|
|
43
43
|
//#endregion
|
|
44
44
|
//#region src/author/server.d.ts
|
|
45
45
|
type AuthorContract = NarrowContract<RegisteredContract, RegisteredManifest>;
|
|
46
|
-
type AuthorHitchClient = WithBatchRecorder<ContractRouterClient<AuthorContract
|
|
46
|
+
type AuthorHitchClient = WithRecordCreates<WithBatchRecorder<ContractRouterClient<AuthorContract>>>;
|
|
47
47
|
type AuthorHitch = WithFilesUpload<AuthorHitchClient> & (RegisteredManifest extends {
|
|
48
48
|
public: true;
|
|
49
49
|
} ? {} : {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as fetchWithOrgAuth } from "./auth-D3CrCtZq.js";
|
|
2
|
-
import { t as loadAppletConfig } from "./load-config-
|
|
2
|
+
import { t as loadAppletConfig } from "./load-config-DGALUExv.js";
|
|
3
3
|
import { t as question } from "./prompt-ChS-grYO.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
//#region src/variables.ts
|
package/dist/vite.js
CHANGED
|
@@ -3,8 +3,8 @@ import { a as openQueryCacheDatabase } from "./query-cache-CXmAyLv3.js";
|
|
|
3
3
|
import { d as HITCH_SESSION_HEADER, f as HITCH_USER_HEADER } from "./headers-CeRX-Xji.js";
|
|
4
4
|
import { a as workflowOutcomeSchema, n as runWorkflowJournal } from "./workflow-engine-BOTzURKM.js";
|
|
5
5
|
import { a as organizationInstanceUrl, c as resolveInstanceUrl, o as rejectEnvironmentKey, r as bearerToken, s as resolveAuthForOrg } from "./store-B8N_8JIN.js";
|
|
6
|
-
import { a as writeRegisterDeclaration, c as writeAppletRoot, d as writeServerEntry, i as syncContract, l as writeClientEntry, n as routesModuleSource, u as writeManifestGen } from "./generate-
|
|
7
|
-
import { a as
|
|
6
|
+
import { a as writeRegisterDeclaration, c as writeAppletRoot, d as writeServerEntry, i as syncContract, l as writeClientEntry, n as routesModuleSource, u as writeManifestGen } from "./generate-BLD0DoCk.js";
|
|
7
|
+
import { a as appletMountPath, i as appletManifestSchema, o as appletSourceDefinitionSchema, r as resolveWorkspaceOrg, s as APPLET_CODE_PATTERN } from "./load-config-DGALUExv.js";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { randomUUID } from "node:crypto";
|
|
10
10
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
@@ -572,6 +572,7 @@ function applet(sourceDefinition) {
|
|
|
572
572
|
}
|
|
573
573
|
const { dependencies: _dependencies, devDependencies: _devDependencies, ...definition } = parsedSourceDefinition.data;
|
|
574
574
|
const parsedDefinition = { data: definition };
|
|
575
|
+
const mountPath = appletMountPath(definition);
|
|
575
576
|
let appletConfig;
|
|
576
577
|
let buildRootOutDir;
|
|
577
578
|
let clearedOutDir = false;
|
|
@@ -589,7 +590,7 @@ function applet(sourceDefinition) {
|
|
|
589
590
|
children: [{
|
|
590
591
|
type: "physical",
|
|
591
592
|
directory: ".",
|
|
592
|
-
pathPrefix:
|
|
593
|
+
pathPrefix: mountPath
|
|
593
594
|
}]
|
|
594
595
|
};
|
|
595
596
|
const resolveAppletConfig = (root) => {
|
|
@@ -738,7 +739,7 @@ function applet(sourceDefinition) {
|
|
|
738
739
|
if (colocated.length > 0) throw new Error(`Applet tests run only from the test folder. Move ${colocated.map((path) => `src/${path}`).join(", ")} to test/.`);
|
|
739
740
|
}
|
|
740
741
|
return {
|
|
741
|
-
base: `/${
|
|
742
|
+
base: `/${mountPath}/`,
|
|
742
743
|
test: { include: ["test/**/*.test.{ts,tsx}"] },
|
|
743
744
|
resolve: { alias: {
|
|
744
745
|
"clsx/lite": "cn/lite",
|
|
@@ -776,7 +777,7 @@ function applet(sourceDefinition) {
|
|
|
776
777
|
invoke: async (workflow, body) => {
|
|
777
778
|
const address = server.httpServer?.address();
|
|
778
779
|
if (address === null || address === void 0 || typeof address === "string") throw new Error("The dev server has no port.");
|
|
779
|
-
const response = await fetch(`http://localhost:${address.port}/${
|
|
780
|
+
const response = await fetch(`http://localhost:${address.port}/${mountPath}/api/__hitch/workflows/${encodeURIComponent(workflow)}`, {
|
|
780
781
|
method: "POST",
|
|
781
782
|
headers: { "content-type": "application/json" },
|
|
782
783
|
body: JSON.stringify(body)
|
|
@@ -818,7 +819,7 @@ function applet(sourceDefinition) {
|
|
|
818
819
|
process.off("exit", removeDevServerFile);
|
|
819
820
|
removeDevServerFile();
|
|
820
821
|
});
|
|
821
|
-
const mount = `/${
|
|
822
|
+
const mount = `/${mountPath}`;
|
|
822
823
|
const apiPrefix = `${mount}/api`;
|
|
823
824
|
server.middlewares.use((request, response, next) => {
|
|
824
825
|
if (request.url === mount || request.url?.startsWith(`${mount}?`)) request.url = `${mount}/${request.url.slice(mount.length)}`;
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ Treat each applet as an isolated microfrontend. Keep it separate from the data s
|
|
|
11
11
|
|
|
12
12
|
## Public applets
|
|
13
13
|
|
|
14
|
-
Set `public: true` for an applet that anonymous visitors can use. It runs as the applet identity. Its manifest grants cap its access.
|
|
14
|
+
Set `public: true` for an applet that anonymous visitors can use. It is served at `https://{org}.hitch42.app/pages/{code}`. It runs as the applet identity. Its manifest grants cap its access.
|
|
15
15
|
|
|
16
16
|
A public applet cannot use schedules, email, telephony, workflows, or `@hitch42/applet/client/hitch`. Client code calls its server procedures with `api` from `@hitch42/applet/client`.
|
|
17
17
|
|
|
@@ -14,7 +14,7 @@ Use the generated Hitch contract as the typed data plane.
|
|
|
14
14
|
## Use record verbs
|
|
15
15
|
|
|
16
16
|
- `list` sends `GET /v1/<objectCode>` and lists records with query parameters.
|
|
17
|
-
- `create` sends `POST /v1/<objectCode>` and creates one record.
|
|
17
|
+
- `create` sends `POST /v1/<objectCode>` and creates one record or an array of records.
|
|
18
18
|
- `get` sends `GET /v1/<objectCode>/{id}` and gets one record.
|
|
19
19
|
- `history` sends `GET /v1/<objectCode>/{id}/history` and gets record changes.
|
|
20
20
|
- `update` sends `PATCH /v1/<objectCode>/{id}` and updates one record.
|
|
@@ -74,6 +74,21 @@ const deal = await hitch.records.deals.get({
|
|
|
74
74
|
- Do not use `.queryOptions(...)` or `.mutationOptions(...)` on the server.
|
|
75
75
|
- Use the server SDK for imperative data access, secrets, or external services.
|
|
76
76
|
|
|
77
|
+
## Create records
|
|
78
|
+
|
|
79
|
+
Pass one object in `body` to create one record. The call returns one record.
|
|
80
|
+
Use server SDK `create(...)` or client `create.call(...)` with an array to create up to 1000 records. The call returns an array in the same order.
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const deals = await hitch.records.deals.create({
|
|
84
|
+
body: [{ name: "First deal" }, { name: "Second deal" }],
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The call creates all records or none. If one record fails, the error gives its index in `entry_index`.
|
|
89
|
+
The first record has index 0. An empty array returns an empty array and requires the create grant.
|
|
90
|
+
`mutationOptions` creates one record. Batch recorder calls accept one record per create call.
|
|
91
|
+
|
|
77
92
|
## Read history
|
|
78
93
|
|
|
79
94
|
```ts
|
package/dist/batch-Qa4B4-Yp.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { AnyContractRouter } from "@orpc/contract";
|
|
2
|
-
//#region src/hitch/batch.d.ts
|
|
3
|
-
type BatchVerb = "create" | "update" | "delete" | "updateWhere";
|
|
4
|
-
type BatchTxRecords<Records> = { [Code in keyof Records]: { [Verb in keyof Records[Code] & BatchVerb]: Records[Code][Verb] extends ((...args: infer Args) => unknown) ? (input: Args[0]) => void : never; }; };
|
|
5
|
-
type BatchTx<T> = T extends {
|
|
6
|
-
records: infer Records;
|
|
7
|
-
} ? BatchTxRecords<Records> : never;
|
|
8
|
-
type BatchRecorderOptions = {
|
|
9
|
-
dryRun?: boolean;
|
|
10
|
-
idempotencyKey?: string;
|
|
11
|
-
};
|
|
12
|
-
type BatchRecorderCall<T, Batch> = Batch extends ((...args: infer _Args) => infer Result) ? (record: (tx: BatchTx<T>) => void | Promise<void>, options?: BatchRecorderOptions) => Result : never;
|
|
13
|
-
type WithBatchRecorder<T> = T extends {
|
|
14
|
-
records: unknown;
|
|
15
|
-
batch: infer Batch;
|
|
16
|
-
} ? Omit<T, "batch"> & {
|
|
17
|
-
/**
|
|
18
|
-
* Record record writes inside `record` and send them as one atomic batch.
|
|
19
|
-
*
|
|
20
|
-
* The callback receives a `tx` whose `create` / `update` / `updateWhere` /
|
|
21
|
-
* `delete` calls are buffered, not sent immediately; the whole batch runs
|
|
22
|
-
* in a single transaction when the callback resolves.
|
|
23
|
-
*
|
|
24
|
-
* @remarks A batch may contain at most **100** requests. More than that is
|
|
25
|
-
* rejected with a `400` before any write runs.
|
|
26
|
-
*/
|
|
27
|
-
batch: BatchRecorderCall<T, Batch> & Batch;
|
|
28
|
-
} : T;
|
|
29
|
-
//#endregion
|
|
30
|
-
export { WithBatchRecorder as t };
|
package/dist/build-DpkWOvd2.js
DELETED