lazyconvex 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +926 -0
- package/dist/components/index.mjs +937 -0
- package/dist/error-D4GuI0ot.mjs +71 -0
- package/dist/file-field-BqVgy8xY.mjs +205 -0
- package/dist/form-BXJK_j10.d.mts +99 -0
- package/dist/index.d.mts +433 -0
- package/dist/index.mjs +1 -0
- package/dist/index2.d.mts +5 -0
- package/dist/index3.d.mts +35 -0
- package/dist/index4.d.mts +101 -0
- package/dist/index5.d.mts +842 -0
- package/dist/next/index.mjs +151 -0
- package/dist/org-CmJBb8z-.d.mts +56 -0
- package/dist/react/index.mjs +158 -0
- package/dist/retry.d.mts +12 -0
- package/dist/retry.mjs +35 -0
- package/dist/schema.d.mts +23 -0
- package/dist/schema.mjs +15 -0
- package/dist/server/index.mjs +2572 -0
- package/dist/types-DWBVRtit.d.mts +322 -0
- package/dist/use-online-status-CMr73Jlk.mjs +155 -0
- package/dist/use-upload-DtELytQi.mjs +95 -0
- package/dist/zod.d.mts +18 -0
- package/dist/zod.mjs +87 -0
- package/package.json +40 -0
- package/src/components/editors-section.tsx +86 -0
- package/src/components/fields.tsx +884 -0
- package/src/components/file-field.tsx +234 -0
- package/src/components/form.tsx +191 -0
- package/src/components/index.ts +11 -0
- package/src/components/offline-indicator.tsx +15 -0
- package/src/components/org-avatar.tsx +13 -0
- package/src/components/permission-guard.tsx +36 -0
- package/src/components/role-badge.tsx +14 -0
- package/src/components/suspense-wrap.tsx +8 -0
- package/src/index.ts +40 -0
- package/src/next/active-org.ts +33 -0
- package/src/next/auth.ts +9 -0
- package/src/next/image.ts +134 -0
- package/src/next/index.ts +3 -0
- package/src/react/form-meta.ts +53 -0
- package/src/react/form.ts +201 -0
- package/src/react/index.ts +8 -0
- package/src/react/org.tsx +96 -0
- package/src/react/use-active-org.ts +48 -0
- package/src/react/use-bulk-selection.ts +47 -0
- package/src/react/use-online-status.ts +21 -0
- package/src/react/use-optimistic.ts +54 -0
- package/src/react/use-upload.ts +101 -0
- package/src/retry.ts +47 -0
- package/src/schema.ts +30 -0
- package/src/server/cache-crud.ts +175 -0
- package/src/server/check-schema.ts +29 -0
- package/src/server/child.ts +98 -0
- package/src/server/crud.ts +384 -0
- package/src/server/db.ts +7 -0
- package/src/server/error.ts +39 -0
- package/src/server/file.ts +372 -0
- package/src/server/helpers.ts +214 -0
- package/src/server/index.ts +12 -0
- package/src/server/org-crud.ts +307 -0
- package/src/server/org-helpers.ts +54 -0
- package/src/server/org.ts +572 -0
- package/src/server/schema-helpers.ts +107 -0
- package/src/server/setup.ts +138 -0
- package/src/server/test-crud.ts +211 -0
- package/src/server/test.ts +554 -0
- package/src/server/types.ts +392 -0
- package/src/server/unique.ts +28 -0
- package/src/zod.ts +141 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { fetchQuery } from "convex/nextjs";
|
|
2
|
+
import { cookies } from "next/headers";
|
|
3
|
+
import { convexAuthNextjsToken } from "@convex-dev/auth/nextjs/server";
|
|
4
|
+
import { ConvexHttpClient } from "convex/browser";
|
|
5
|
+
import { NextResponse } from "next/server";
|
|
6
|
+
import sharp from "sharp";
|
|
7
|
+
|
|
8
|
+
//#region src/next/active-org.ts
|
|
9
|
+
const setActiveOrgCookie = async ({ orgId, slug }) => {
|
|
10
|
+
const cookieStore = await cookies(), opts = {
|
|
11
|
+
httpOnly: false,
|
|
12
|
+
maxAge: 3600 * 24 * 365,
|
|
13
|
+
path: "/"
|
|
14
|
+
};
|
|
15
|
+
cookieStore.set("activeOrgId", orgId, opts);
|
|
16
|
+
cookieStore.set("activeOrgSlug", slug, opts);
|
|
17
|
+
}, clearActiveOrgCookie = async () => {
|
|
18
|
+
const cookieStore = await cookies();
|
|
19
|
+
cookieStore.delete("activeOrgId");
|
|
20
|
+
cookieStore.delete("activeOrgSlug");
|
|
21
|
+
}, getActiveOrg = async ({ query, token }) => {
|
|
22
|
+
if (!token) return null;
|
|
23
|
+
const cookieStore = await cookies(), orgId = cookieStore.get("activeOrgId")?.value;
|
|
24
|
+
if (!orgId) return null;
|
|
25
|
+
try {
|
|
26
|
+
return await fetchQuery(query, { orgId }, { token });
|
|
27
|
+
} catch {
|
|
28
|
+
cookieStore.delete("activeOrgId");
|
|
29
|
+
cookieStore.delete("activeOrgSlug");
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/next/auth.ts
|
|
36
|
+
const isTest = Boolean(process.env.PLAYWRIGHT || process.env.TEST_MODE), getToken = async () => isTest ? void 0 : convexAuthNextjsToken(), isAuthenticated = async () => isTest || Boolean(await convexAuthNextjsToken());
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/next/image.ts
|
|
40
|
+
const IMAGE_TYPES = new Set([
|
|
41
|
+
"image/gif",
|
|
42
|
+
"image/jpeg",
|
|
43
|
+
"image/png",
|
|
44
|
+
"image/svg+xml",
|
|
45
|
+
"image/webp"
|
|
46
|
+
]), isImageType = (contentType) => IMAGE_TYPES.has(contentType), formatToMime = {
|
|
47
|
+
jpeg: "image/jpeg",
|
|
48
|
+
png: "image/png",
|
|
49
|
+
webp: "image/webp"
|
|
50
|
+
}, applyFormat = ({ contentType, format, pipeline, quality }) => {
|
|
51
|
+
if (format === "jpeg") return pipeline.jpeg({ quality });
|
|
52
|
+
if (format === "png") return pipeline.png({ quality });
|
|
53
|
+
if (format === "webp") return pipeline.webp({ quality });
|
|
54
|
+
const [, ext] = contentType.split("/");
|
|
55
|
+
if (ext === "jpeg" || ext === "jpg") return pipeline.jpeg({ quality });
|
|
56
|
+
if (ext === "png") return pipeline.png({ quality });
|
|
57
|
+
if (ext === "webp") return pipeline.webp({ quality });
|
|
58
|
+
return pipeline;
|
|
59
|
+
}, applyTransforms = ({ contentType, options, pipeline, thumbnail }) => {
|
|
60
|
+
const quality = options?.compress?.quality ?? 80;
|
|
61
|
+
if (thumbnail) return pipeline.resize({
|
|
62
|
+
fit: "cover",
|
|
63
|
+
height: 200,
|
|
64
|
+
width: 200
|
|
65
|
+
}).webp({ quality: 80 });
|
|
66
|
+
let result = pipeline;
|
|
67
|
+
if (options?.resize) result = result.resize({
|
|
68
|
+
fit: options.resize.fit ?? "cover",
|
|
69
|
+
height: options.resize.height,
|
|
70
|
+
width: options.resize.width
|
|
71
|
+
});
|
|
72
|
+
if (options?.format || options?.compress) result = applyFormat({
|
|
73
|
+
contentType,
|
|
74
|
+
format: options.format,
|
|
75
|
+
pipeline: result,
|
|
76
|
+
quality
|
|
77
|
+
});
|
|
78
|
+
return result;
|
|
79
|
+
}, fetchImage = async ({ client, queryRef, storageId }) => {
|
|
80
|
+
const url = (await client.query(queryRef, { id: storageId }))?.url;
|
|
81
|
+
if (!url) return {
|
|
82
|
+
error: "File not found",
|
|
83
|
+
status: 404
|
|
84
|
+
};
|
|
85
|
+
const response = await fetch(url);
|
|
86
|
+
if (!response.ok) return {
|
|
87
|
+
error: "Failed to fetch image",
|
|
88
|
+
status: 500
|
|
89
|
+
};
|
|
90
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
91
|
+
if (!isImageType(contentType)) return {
|
|
92
|
+
error: "Not an image file",
|
|
93
|
+
status: 400
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
buffer: Buffer.from(await response.arrayBuffer()),
|
|
97
|
+
contentType
|
|
98
|
+
};
|
|
99
|
+
}, makeGet = ({ getClient, queryRef }) => async (req) => {
|
|
100
|
+
try {
|
|
101
|
+
const storageId = req.nextUrl.searchParams.get("id");
|
|
102
|
+
if (!storageId) return NextResponse.json({ error: "id is required" }, { status: 400 });
|
|
103
|
+
const result = await fetchImage({
|
|
104
|
+
client: getClient(),
|
|
105
|
+
queryRef,
|
|
106
|
+
storageId
|
|
107
|
+
});
|
|
108
|
+
if ("error" in result) return NextResponse.json({ error: result.error }, { status: result.status });
|
|
109
|
+
return new NextResponse(new Uint8Array(result.buffer), { headers: {
|
|
110
|
+
"Cache-Control": "public, max-age=31536000, immutable",
|
|
111
|
+
"Content-Type": result.contentType
|
|
112
|
+
} });
|
|
113
|
+
} catch (error) {
|
|
114
|
+
return NextResponse.json({ error: error instanceof Error ? error.message : "Failed to fetch image" }, { status: 500 });
|
|
115
|
+
}
|
|
116
|
+
}, makePost = ({ getClient, queryRef }) => async (req) => {
|
|
117
|
+
try {
|
|
118
|
+
const { options, storageId, thumbnail } = await req.json();
|
|
119
|
+
if (!storageId) return NextResponse.json({ error: "storageId is required" }, { status: 400 });
|
|
120
|
+
const result = await fetchImage({
|
|
121
|
+
client: getClient(),
|
|
122
|
+
queryRef,
|
|
123
|
+
storageId
|
|
124
|
+
});
|
|
125
|
+
if ("error" in result) return NextResponse.json({ error: result.error }, { status: result.status });
|
|
126
|
+
const { buffer, contentType } = result, outputBuffer = await applyTransforms({
|
|
127
|
+
contentType,
|
|
128
|
+
options,
|
|
129
|
+
pipeline: sharp(buffer),
|
|
130
|
+
thumbnail: thumbnail ?? false
|
|
131
|
+
}).toBuffer(), outputMime = thumbnail ? "image/webp" : options?.format ? formatToMime[options.format] : contentType;
|
|
132
|
+
return new NextResponse(new Uint8Array(outputBuffer), { headers: {
|
|
133
|
+
"Cache-Control": "public, max-age=31536000, immutable",
|
|
134
|
+
"Content-Type": outputMime
|
|
135
|
+
} });
|
|
136
|
+
} catch (error) {
|
|
137
|
+
return NextResponse.json({ error: error instanceof Error ? error.message : "Processing failed" }, { status: 500 });
|
|
138
|
+
}
|
|
139
|
+
}, makeImageRoute = async ({ convexUrl, fileInfoQuery = "file:info" }) => {
|
|
140
|
+
const getClient = () => new ConvexHttpClient(convexUrl), opts = {
|
|
141
|
+
getClient,
|
|
142
|
+
queryRef: fileInfoQuery
|
|
143
|
+
};
|
|
144
|
+
return {
|
|
145
|
+
GET: makeGet(opts),
|
|
146
|
+
POST: makePost(opts)
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
//#endregion
|
|
151
|
+
export { clearActiveOrgCookie, getActiveOrg, getToken, isAuthenticated, makeImageRoute, setActiveOrgCookie };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { w as OrgRole } from "./types-DWBVRtit.mjs";
|
|
2
|
+
import { FunctionReference } from "convex/server";
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/react/org.d.ts
|
|
7
|
+
interface OrgContextValue<O extends OrgDoc = OrgDoc, M = unknown> {
|
|
8
|
+
canDeleteOrg: boolean;
|
|
9
|
+
canManageAdmins: boolean;
|
|
10
|
+
canManageMembers: boolean;
|
|
11
|
+
isAdmin: boolean;
|
|
12
|
+
isMember: boolean;
|
|
13
|
+
isOwner: boolean;
|
|
14
|
+
membership: M | null;
|
|
15
|
+
org: O;
|
|
16
|
+
orgId: string;
|
|
17
|
+
role: OrgRole;
|
|
18
|
+
}
|
|
19
|
+
interface OrgDoc {
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
_id: string;
|
|
22
|
+
}
|
|
23
|
+
interface OrgProviderProps<O extends OrgDoc, M> {
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
membership: M | null;
|
|
26
|
+
org: O;
|
|
27
|
+
role: OrgRole;
|
|
28
|
+
}
|
|
29
|
+
declare const OrgProvider: <O extends OrgDoc, M>({
|
|
30
|
+
children,
|
|
31
|
+
membership,
|
|
32
|
+
org,
|
|
33
|
+
role
|
|
34
|
+
}: OrgProviderProps<O, M>) => react_jsx_runtime0.JSX.Element, useOrg: <O extends OrgDoc = OrgDoc, M = unknown>() => OrgContextValue<O, M>, useOrgQuery: <F extends FunctionReference<"query">>(query: F, args?: "skip" | Omit<F["_args"], "orgId">) => F["_returnType"] | undefined, useOrgMutation: <F extends FunctionReference<"mutation">>(mutation: F) => (args?: Omit<F["_args"], "orgId">) => Promise<F["_returnType"]>, canEditResource: ({
|
|
35
|
+
editorsList,
|
|
36
|
+
isAdmin,
|
|
37
|
+
resource,
|
|
38
|
+
userId
|
|
39
|
+
}: {
|
|
40
|
+
editorsList: {
|
|
41
|
+
userId: string;
|
|
42
|
+
}[];
|
|
43
|
+
isAdmin: boolean;
|
|
44
|
+
resource: {
|
|
45
|
+
userId: string;
|
|
46
|
+
};
|
|
47
|
+
userId: string;
|
|
48
|
+
}) => boolean, useMyOrgs: <O extends OrgDoc>(myOrgsQuery: FunctionReference<"query">) => {
|
|
49
|
+
isLoading: boolean;
|
|
50
|
+
orgs: {
|
|
51
|
+
org: O;
|
|
52
|
+
role: OrgRole;
|
|
53
|
+
}[];
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
export { canEditResource as a, useOrgMutation as c, OrgProviderProps as i, useOrgQuery as l, OrgDoc as n, useMyOrgs as o, OrgProvider as r, useOrg as s, OrgContextValue as t };
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import "../error-D4GuI0ot.mjs";
|
|
2
|
+
import { a as getMeta, i as buildMeta, n as useForm, r as useFormMutation, t as useOnlineStatus } from "../use-online-status-CMr73Jlk.mjs";
|
|
3
|
+
import { t as useUpload } from "../use-upload-DtELytQi.mjs";
|
|
4
|
+
import { useMutation, useQuery } from "convex/react";
|
|
5
|
+
import { createContext, use, useCallback, useMemo, useRef, useState } from "react";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
|
|
8
|
+
//#region src/react/org.tsx
|
|
9
|
+
const OrgContext = createContext(null);
|
|
10
|
+
const OrgProvider = ({ children, membership, org, role }) => {
|
|
11
|
+
return /* @__PURE__ */ jsx(OrgContext, {
|
|
12
|
+
value: useMemo(() => {
|
|
13
|
+
const isOwner = role === "owner", isAdmin = role === "owner" || role === "admin";
|
|
14
|
+
return {
|
|
15
|
+
canDeleteOrg: isOwner,
|
|
16
|
+
canManageAdmins: isOwner,
|
|
17
|
+
canManageMembers: isAdmin,
|
|
18
|
+
isAdmin,
|
|
19
|
+
isMember: true,
|
|
20
|
+
isOwner,
|
|
21
|
+
membership,
|
|
22
|
+
org,
|
|
23
|
+
orgId: org._id,
|
|
24
|
+
role
|
|
25
|
+
};
|
|
26
|
+
}, [
|
|
27
|
+
membership,
|
|
28
|
+
org,
|
|
29
|
+
role
|
|
30
|
+
]),
|
|
31
|
+
children
|
|
32
|
+
});
|
|
33
|
+
}, useOrg = () => {
|
|
34
|
+
const ctx = use(OrgContext);
|
|
35
|
+
if (!ctx) throw new Error("useOrg must be used inside OrgProvider");
|
|
36
|
+
return ctx;
|
|
37
|
+
}, useOrgQuery = (query, args) => {
|
|
38
|
+
const { orgId } = useOrg();
|
|
39
|
+
return useQuery(query, args === "skip" ? "skip" : {
|
|
40
|
+
...args,
|
|
41
|
+
orgId
|
|
42
|
+
});
|
|
43
|
+
}, useOrgMutation = (mutation) => {
|
|
44
|
+
const { orgId } = useOrg(), mutate = useMutation(mutation);
|
|
45
|
+
return useCallback(async (args) => mutate({
|
|
46
|
+
...args,
|
|
47
|
+
orgId
|
|
48
|
+
}), [mutate, orgId]);
|
|
49
|
+
}, canEditResource = ({ editorsList, isAdmin, resource, userId }) => isAdmin || resource.userId === userId || editorsList.some((e) => e.userId === userId), useMyOrgs = (myOrgsQuery) => {
|
|
50
|
+
const data = useQuery(myOrgsQuery);
|
|
51
|
+
return {
|
|
52
|
+
isLoading: data === void 0,
|
|
53
|
+
orgs: data ?? []
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/react/use-active-org.ts
|
|
59
|
+
const ACTIVE_ORG_REGEX = /activeOrgId=(?<id>[^;]+)/u, getActiveOrgIdFromCookie = () => {
|
|
60
|
+
if (typeof document === "undefined") return null;
|
|
61
|
+
return ACTIVE_ORG_REGEX.exec(document.cookie)?.groups?.id ?? null;
|
|
62
|
+
}, setActiveOrgCookieClient = ({ orgId, slug }) => {
|
|
63
|
+
const maxAge = 3600 * 24 * 365;
|
|
64
|
+
document.cookie = `activeOrgId=${orgId}; path=/; max-age=${maxAge}`;
|
|
65
|
+
document.cookie = `activeOrgSlug=${slug}; path=/; max-age=${maxAge}`;
|
|
66
|
+
}, useActiveOrg = (orgGetQuery) => {
|
|
67
|
+
const [activeOrgId, setActiveOrgId] = useState(getActiveOrgIdFromCookie), activeOrg = useQuery(orgGetQuery, activeOrgId ? { orgId: activeOrgId } : "skip"), setActiveOrg = useCallback((org) => {
|
|
68
|
+
setActiveOrgCookieClient({
|
|
69
|
+
orgId: org._id,
|
|
70
|
+
slug: org.slug
|
|
71
|
+
});
|
|
72
|
+
setActiveOrgId(org._id);
|
|
73
|
+
}, []), clearActiveOrg = useCallback(() => {
|
|
74
|
+
document.cookie = "activeOrgId=; path=/; max-age=0";
|
|
75
|
+
document.cookie = "activeOrgSlug=; path=/; max-age=0";
|
|
76
|
+
setActiveOrgId(null);
|
|
77
|
+
}, []);
|
|
78
|
+
return {
|
|
79
|
+
activeOrg: activeOrg ?? null,
|
|
80
|
+
activeOrgId,
|
|
81
|
+
clearActiveOrg,
|
|
82
|
+
isLoading: activeOrgId ? activeOrg === void 0 : false,
|
|
83
|
+
setActiveOrg
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/react/use-bulk-selection.ts
|
|
89
|
+
const useBulkSelection = ({ bulkRm, items, onError, onSuccess, orgId }) => {
|
|
90
|
+
const [selected, setSelected] = useState(/* @__PURE__ */ new Set()), clear = () => {
|
|
91
|
+
setSelected(/* @__PURE__ */ new Set());
|
|
92
|
+
}, toggleSelect = (id) => {
|
|
93
|
+
setSelected((prev) => {
|
|
94
|
+
const next = new Set(prev);
|
|
95
|
+
if (next.has(id)) next.delete(id);
|
|
96
|
+
else next.add(id);
|
|
97
|
+
return next;
|
|
98
|
+
});
|
|
99
|
+
}, toggleSelectAll = () => {
|
|
100
|
+
if (selected.size === items.length) setSelected(/* @__PURE__ */ new Set());
|
|
101
|
+
else setSelected(new Set(items.map((i) => i._id)));
|
|
102
|
+
}, handleBulkDelete = () => {
|
|
103
|
+
if (selected.size === 0) return;
|
|
104
|
+
const count = selected.size;
|
|
105
|
+
bulkRm({
|
|
106
|
+
ids: [...selected],
|
|
107
|
+
orgId
|
|
108
|
+
}).then(() => {
|
|
109
|
+
onSuccess?.(count);
|
|
110
|
+
setSelected(/* @__PURE__ */ new Set());
|
|
111
|
+
return null;
|
|
112
|
+
}).catch((bulkError) => onError?.(bulkError));
|
|
113
|
+
};
|
|
114
|
+
return {
|
|
115
|
+
clear,
|
|
116
|
+
handleBulkDelete,
|
|
117
|
+
selected,
|
|
118
|
+
toggleSelect,
|
|
119
|
+
toggleSelectAll
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/react/use-optimistic.ts
|
|
125
|
+
const useOptimisticMutation = ({ mutation, onOptimistic, onRollback, onSuccess }) => {
|
|
126
|
+
const mutate = useMutation(mutation), [isPending, setIsPending] = useState(false), [mutationError, setMutationError] = useState(null), pendingCount = useRef(0);
|
|
127
|
+
return {
|
|
128
|
+
error: mutationError,
|
|
129
|
+
execute: useCallback(async (args) => {
|
|
130
|
+
pendingCount.current += 1;
|
|
131
|
+
setIsPending(true);
|
|
132
|
+
setMutationError(null);
|
|
133
|
+
onOptimistic?.(args);
|
|
134
|
+
try {
|
|
135
|
+
const result = await mutate(args);
|
|
136
|
+
onSuccess?.(result, args);
|
|
137
|
+
return result;
|
|
138
|
+
} catch (error) {
|
|
139
|
+
const err = error instanceof Error ? error : /* @__PURE__ */ new Error("Mutation failed");
|
|
140
|
+
setMutationError(err);
|
|
141
|
+
onRollback?.(args, err);
|
|
142
|
+
return null;
|
|
143
|
+
} finally {
|
|
144
|
+
pendingCount.current -= 1;
|
|
145
|
+
if (pendingCount.current === 0) setIsPending(false);
|
|
146
|
+
}
|
|
147
|
+
}, [
|
|
148
|
+
mutate,
|
|
149
|
+
onOptimistic,
|
|
150
|
+
onRollback,
|
|
151
|
+
onSuccess
|
|
152
|
+
]),
|
|
153
|
+
isPending
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
//#endregion
|
|
158
|
+
export { OrgProvider, buildMeta, canEditResource, getMeta, setActiveOrgCookieClient, useActiveOrg, useBulkSelection, useForm, useFormMutation, useMyOrgs, useOnlineStatus, useOptimisticMutation, useOrg, useOrgMutation, useOrgQuery, useUpload };
|
package/dist/retry.d.mts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/retry.d.ts
|
|
2
|
+
interface RetryOptions {
|
|
3
|
+
base?: number;
|
|
4
|
+
initialDelayMs?: number;
|
|
5
|
+
maxAttempts?: number;
|
|
6
|
+
maxDelayMs?: number;
|
|
7
|
+
}
|
|
8
|
+
declare const withRetry: <T>(fn: () => Promise<T>, options?: RetryOptions) => Promise<T>, fetchWithRetry: (url: string, options?: RequestInit & {
|
|
9
|
+
retry?: RetryOptions;
|
|
10
|
+
}) => Promise<Response>;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { fetchWithRetry, withRetry };
|
package/dist/retry.mjs
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/retry.ts
|
|
2
|
+
const DEFAULT_OPTIONS = {
|
|
3
|
+
base: 2,
|
|
4
|
+
initialDelayMs: 500,
|
|
5
|
+
maxAttempts: 3,
|
|
6
|
+
maxDelayMs: 1e4
|
|
7
|
+
}, sleep = async (ms) => new Promise((resolve) => {
|
|
8
|
+
setTimeout(resolve, ms);
|
|
9
|
+
}), calculateDelay = (attempt, opts) => {
|
|
10
|
+
const jitter = Math.random() * .3 + .85;
|
|
11
|
+
return Math.min(opts.initialDelayMs * opts.base ** attempt * jitter, opts.maxDelayMs);
|
|
12
|
+
}, withRetry = async (fn, options = {}) => {
|
|
13
|
+
const opts = {
|
|
14
|
+
...DEFAULT_OPTIONS,
|
|
15
|
+
...options
|
|
16
|
+
};
|
|
17
|
+
let lastError = /* @__PURE__ */ new Error("Retry failed");
|
|
18
|
+
for (let attempt = 0; attempt < opts.maxAttempts; attempt += 1) try {
|
|
19
|
+
return await fn();
|
|
20
|
+
} catch (error) {
|
|
21
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
22
|
+
if (attempt < opts.maxAttempts - 1) await sleep(calculateDelay(attempt, opts));
|
|
23
|
+
}
|
|
24
|
+
throw lastError;
|
|
25
|
+
}, fetchWithRetry = async (url, options) => {
|
|
26
|
+
const { retry, ...fetchOptions } = options ?? {};
|
|
27
|
+
return withRetry(async () => {
|
|
28
|
+
const response = await fetch(url, fetchOptions);
|
|
29
|
+
if (!response.ok && response.status >= 500) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
30
|
+
return response;
|
|
31
|
+
}, retry);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
//#endregion
|
|
35
|
+
export { fetchWithRetry, withRetry };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as zod_v40 from "zod/v4";
|
|
2
|
+
import { ZodObject, ZodRawShape } from "zod/v4";
|
|
3
|
+
import * as convex_helpers_server_zod40 from "convex-helpers/server/zod4";
|
|
4
|
+
import * as zod_v4_core0 from "zod/v4/core";
|
|
5
|
+
|
|
6
|
+
//#region src/schema.d.ts
|
|
7
|
+
declare const cvFile: () => convex_helpers_server_zod40.Zid<"_storage">, cvFiles: () => zod_v40.ZodArray<convex_helpers_server_zod40.Zid<"_storage">>, child: <const P extends string, const S extends ZodRawShape, const FK extends keyof S & string>(config: {
|
|
8
|
+
foreignKey: FK;
|
|
9
|
+
index?: string;
|
|
10
|
+
parent: P;
|
|
11
|
+
schema: ZodObject<S>;
|
|
12
|
+
}) => {
|
|
13
|
+
foreignKey: FK;
|
|
14
|
+
index: string;
|
|
15
|
+
parent: P;
|
|
16
|
+
schema: ZodObject<S>;
|
|
17
|
+
}, orgSchema: ZodObject<{
|
|
18
|
+
avatarId: zod_v40.ZodOptional<zod_v40.ZodNullable<convex_helpers_server_zod40.Zid<"_storage">>>;
|
|
19
|
+
name: zod_v40.ZodString;
|
|
20
|
+
slug: zod_v40.ZodString;
|
|
21
|
+
}, zod_v4_core0.$strip>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { child, cvFile, cvFiles, orgSchema };
|
package/dist/schema.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { array, object, string } from "zod/v4";
|
|
2
|
+
import { zid } from "convex-helpers/server/zod4";
|
|
3
|
+
|
|
4
|
+
//#region src/schema.ts
|
|
5
|
+
const cvFile = () => zid("_storage").meta({ cv: "file" }), cvFiles = () => array(cvFile()).meta({ cv: "files" }), child = (config) => ({
|
|
6
|
+
...config,
|
|
7
|
+
index: config.index ?? `by_${config.parent}`
|
|
8
|
+
}), orgSchema = object({
|
|
9
|
+
avatarId: zid("_storage").nullable().optional(),
|
|
10
|
+
name: string().min(1),
|
|
11
|
+
slug: string().min(1).regex(/^[a-z0-9-]+$/u)
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { child, cvFile, cvFiles, orgSchema };
|