mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-10-23 03:27:27 +09:00
refactor: Centralize Builder ID generation (#6323)
## Outcome Builder-owned code now routes standard ID generation through `@webstudio-is/sdk/createId` while preserving existing NanoID and UUID formats. Closes #6322 ## Technical choices - Use `createId("nano")` for Builder records, assets, transaction IDs, and other existing NanoID-backed values. - Use `createId()` for UUID-backed database records and browser-side client IDs. - Keep `BuilderRuntimeContext.createId` as an injectable dependency. Runtime operations, copy/paste, and deterministic tests rely on that injection. - Keep Node's `randomUUID` in CLI paths that explicitly support running without the Web Crypto global. - Keep specialized generators for custom-alphabet project domains and actual hash generation. - Remove direct `nanoid` dependencies from packages where no specialized use remains. - Do not migrate existing data or change database schemas. ## Todo - [x] Migrate Builder app ID creation. - [x] Migrate project runtime and template defaults. - [x] Migrate asset, project, domain, and authorization-token IDs. - [x] Preserve runtime ID injection. - [x] Review remaining direct generators as explicit exceptions. - [x] Add NanoID-format regression coverage for the default runtime context. - [x] Review documentation impact: no user-facing documentation changes are needed. - [x] Review fixture impact: no fixture input or generated output format changes are needed. - [x] Run targeted tests, typechecks, lint, and package-boundary checks. ## Verification - Targeted Builder tests: 153 passed after preserving runtime-context injection. - Project-build runtime tests: 270 passed. - Asset uploader tests: 61 passed. - Authorization-token tests: 17 passed. - Project tests: 52 passed. - Domain tests: 18 passed. - CLI tests: 32 passed. - Typechecks passed for Builder, project-build, asset-uploader, authorization-token, project, and domain. - `pnpm lint` passed. - `pnpm check:package-boundaries` passed. - The runtime-context format test was demonstrated to fail with a UUID default and pass with the NanoID default. - Agent evaluations were not run because they require separate explicit approval.
This commit is contained in:
1 parent
7ff42abfb5
commit
b832a8e808
47 files changed
+162
-147
No files matched your search
@@ -1,6 +1,5 @@
|
||||
import { Fragment, useState, useMemo } from "react";
|
||||
import { nanoid } from "nanoid";
|
||||
import type { Breakpoint } from "@webstudio-is/sdk";
|
||||
import { createId, type Breakpoint } from "@webstudio-is/sdk";
|
||||
import {
|
||||
theme,
|
||||
Flex,
|
||||
@@ -300,7 +299,7 @@ export const BreakpointsEditor = ({
|
||||
return;
|
||||
}
|
||||
const newBreakpoint: Breakpoint = {
|
||||
id: nanoid(),
|
||||
id: createId("nano"),
|
||||
label: "",
|
||||
minWidth: 0,
|
||||
};
|
||||
|
||||
+2
-3
@@ -1,6 +1,6 @@
|
||||
import { Select, toast } from "@webstudio-is/design-system";
|
||||
import { nanoid } from "nanoid";
|
||||
import { useState } from "react";
|
||||
import { createId, type AnimationAction } from "@webstudio-is/sdk";
|
||||
import {
|
||||
$hoveredInstanceSelector,
|
||||
$registeredComponentMetas,
|
||||
@@ -10,7 +10,6 @@ import { $instances } from "~/shared/sync/data-stores";
|
||||
import { getInstanceStyleDecl } from "~/builder/features/style-panel/shared/model";
|
||||
import { executeRuntimeMutation } from "~/shared/instance-utils/data";
|
||||
import { toValue } from "@webstudio-is/css-engine";
|
||||
import type { AnimationAction } from "@webstudio-is/sdk";
|
||||
import { getInstanceLabel } from "~/builder/shared/instance-label";
|
||||
|
||||
const initSubjects = () => {
|
||||
@@ -57,7 +56,7 @@ const initSubjects = () => {
|
||||
const isTimelineExists = viewTimelineName.startsWith("--");
|
||||
const value = isTimelineExists
|
||||
? viewTimelineName
|
||||
: `--generated-timeline-${nanoid()}`;
|
||||
: `--generated-timeline-${createId("nano")}`;
|
||||
|
||||
subjects.push({
|
||||
value,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { useState } from "react";
|
||||
import { computed } from "nanostores";
|
||||
import { useStore } from "@nanostores/react";
|
||||
import { matchSorter } from "match-sorter";
|
||||
import {
|
||||
createId,
|
||||
type Instance,
|
||||
type Prop,
|
||||
type Props,
|
||||
@@ -378,7 +378,7 @@ export const PropsSection = (props: PropsSectionProps) => {
|
||||
|
||||
if (isEphemeral && value !== undefined) {
|
||||
memoryInstanceProp.set(animationAction.propName, {
|
||||
id: nanoid(),
|
||||
id: createId("nano"),
|
||||
instanceId: props.instanceId,
|
||||
type: "animationAction",
|
||||
name: animationAction.propName,
|
||||
|
||||
+9
-7
@@ -1,4 +1,4 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import { useState } from "react";
|
||||
import { Flex, StorySection, Text, theme } from "@webstudio-is/design-system";
|
||||
import {
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
StyleSourceInput as StyleSourceInputComponent,
|
||||
} from ".";
|
||||
|
||||
const createNanoId = () => createId("nano");
|
||||
|
||||
export default {
|
||||
title: "Style panel/Style Source Input",
|
||||
component: StyleSourceInputComponent,
|
||||
@@ -22,7 +24,7 @@ type Item = {
|
||||
};
|
||||
|
||||
const localItem: Item = {
|
||||
id: nanoid(),
|
||||
id: createNanoId(),
|
||||
label: "Local",
|
||||
source: "local",
|
||||
disabled: false,
|
||||
@@ -32,7 +34,7 @@ const localItem: Item = {
|
||||
|
||||
const getItems = (): Array<Item> => [
|
||||
{
|
||||
id: nanoid(),
|
||||
id: createNanoId(),
|
||||
label: "Token",
|
||||
source: "token",
|
||||
disabled: false,
|
||||
@@ -40,7 +42,7 @@ const getItems = (): Array<Item> => [
|
||||
states: [],
|
||||
},
|
||||
{
|
||||
id: nanoid(),
|
||||
id: createNanoId(),
|
||||
label: "Tag",
|
||||
source: "tag",
|
||||
disabled: false,
|
||||
@@ -55,7 +57,7 @@ const createItem = (
|
||||
setValue: (value: Array<Item>) => void
|
||||
) => {
|
||||
const item: Item = {
|
||||
id: nanoid(),
|
||||
id: createNanoId(),
|
||||
label,
|
||||
source: "token",
|
||||
disabled: false,
|
||||
@@ -78,7 +80,7 @@ export const StyleSourceInput = () => {
|
||||
localItem,
|
||||
...getItems(),
|
||||
{
|
||||
id: nanoid(),
|
||||
id: createNanoId(),
|
||||
label: "Disabled",
|
||||
source: "token",
|
||||
disabled: true,
|
||||
@@ -91,7 +93,7 @@ export const StyleSourceInput = () => {
|
||||
>({ styleSourceId: localItem.id });
|
||||
const [editingItemId, setEditingItemId] = useState<undefined | Item["id"]>();
|
||||
|
||||
const truncatedId = nanoid();
|
||||
const truncatedId = createNanoId();
|
||||
const [truncated, setTruncated] = useState<Array<Item>>([
|
||||
{
|
||||
id: truncatedId,
|
||||
|
||||
@@ -5,8 +5,8 @@ import type {
|
||||
VideoAsset,
|
||||
AllowedFileExtension,
|
||||
} from "@webstudio-is/sdk";
|
||||
import { nanoid } from "nanoid";
|
||||
import {
|
||||
createId,
|
||||
getMimeTypeByExtension,
|
||||
getFileExtension,
|
||||
IMAGE_EXTENSIONS,
|
||||
@@ -51,7 +51,7 @@ const extractImageNameAndMimeTypeFromUrl = (url: URL) => {
|
||||
// Any image format is suitable
|
||||
const FALLBACK_URL_TYPE = "image/png";
|
||||
|
||||
return [FALLBACK_URL_TYPE, `${nanoid()}.png`] as const;
|
||||
return [FALLBACK_URL_TYPE, `${createId("nano")}.png`] as const;
|
||||
};
|
||||
|
||||
export const getSha256Hash = async (data: string) => {
|
||||
|
||||
@@ -50,9 +50,13 @@ import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
||||
import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
|
||||
import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
|
||||
|
||||
import { nanoid } from "nanoid";
|
||||
import { createRegularStyleSheet } from "@webstudio-is/css-engine";
|
||||
import type { Instance, Instances, Props } from "@webstudio-is/sdk";
|
||||
import {
|
||||
createId,
|
||||
type Instance,
|
||||
type Instances,
|
||||
type Props,
|
||||
} from "@webstudio-is/sdk";
|
||||
import {
|
||||
inflatedAttribute,
|
||||
idAttribute,
|
||||
@@ -149,7 +153,7 @@ const BindInstanceToNodePlugin = ({
|
||||
*/
|
||||
const CaretColorPlugin = () => {
|
||||
const [editor] = useLexicalComposerContext();
|
||||
const caretClassName = useState(() => `a${nanoid()}`)[0];
|
||||
const caretClassName = useState(() => `a${createId("nano")}`)[0];
|
||||
|
||||
useEffect(() => {
|
||||
const rootElement = editor.getRootElement();
|
||||
@@ -1552,8 +1556,8 @@ export const TextEditor = ({
|
||||
}: TextEditorProps) => {
|
||||
const [rootInstanceSelector] = useState(() => rootInstanceSelectorUnstable);
|
||||
// class names must be started with letter so we add a prefix
|
||||
const [paragraphClassName] = useState(() => `a${nanoid()}`);
|
||||
const [italicClassName] = useState(() => `a${nanoid()}`);
|
||||
const [paragraphClassName] = useState(() => `a${createId("nano")}`);
|
||||
const [italicClassName] = useState(() => `a${createId("nano")}`);
|
||||
const lastSavedStateJsonRef = useRef<SerializedEditorState | null>(null);
|
||||
const [newLinkKeyToInstanceId] = useState(() => new Map());
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useRevalidator, useSearchParams } from "react-router-dom";
|
||||
import { useState, type ComponentProps } from "react";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import {
|
||||
Text,
|
||||
theme,
|
||||
@@ -28,7 +29,6 @@ import {
|
||||
} from "@webstudio-is/design-system";
|
||||
import { nativeClient } from "~/shared/trpc/trpc-client";
|
||||
import type { User } from "~/shared/db/user.server";
|
||||
import { nanoid } from "nanoid";
|
||||
import { EllipsesIcon, SpinnerIcon } from "@webstudio-is/icons";
|
||||
|
||||
const tagColorPalette = Array.from({ length: 50 }, (_, index) => {
|
||||
@@ -322,7 +322,9 @@ export const TagsDialog = ({
|
||||
<DialogActions>
|
||||
<Button
|
||||
color="primary"
|
||||
onClick={() => setEditingTag({ id: nanoid(5), label: "" })}
|
||||
onClick={() =>
|
||||
setEditingTag({ id: createId("nano"), label: "" })
|
||||
}
|
||||
>
|
||||
Create tag
|
||||
</Button>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import { useRevalidator } from "@remix-run/react";
|
||||
import {
|
||||
Button,
|
||||
@@ -491,7 +492,7 @@ export const ManageMembersDialog = ({
|
||||
}
|
||||
if (succeeded.length > 0) {
|
||||
const optimistic: OptimisticPendingInvite[] = succeeded.map((email) => ({
|
||||
notificationId: crypto.randomUUID(),
|
||||
notificationId: createId(),
|
||||
email,
|
||||
relation,
|
||||
}));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { z } from "zod";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import { loadById, patchBuild } from "@webstudio-is/project/index.server";
|
||||
import type { CompactBuild } from "@webstudio-is/project-build";
|
||||
import {
|
||||
@@ -193,6 +193,6 @@ export const commitBuildPatch = async ({
|
||||
projectId,
|
||||
buildId: build.id,
|
||||
clientVersion: build.version,
|
||||
transactions: [{ id: nanoid(), payload }],
|
||||
transactions: [{ id: createId("nano"), payload }],
|
||||
});
|
||||
};
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
type ProjectBundle,
|
||||
} from "@webstudio-is/protocol";
|
||||
import {
|
||||
createId,
|
||||
getHomePage,
|
||||
normalizeAssetFolderData,
|
||||
assetFolders as assetFoldersSchema,
|
||||
@@ -340,7 +341,7 @@ export const importPublishedProjectBundle = async (
|
||||
|
||||
const buildUpdate = createBuildImportUpdate({
|
||||
data,
|
||||
lastTransactionId: crypto.randomUUID(),
|
||||
lastTransactionId: createId(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
version: nextVersion,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { JSX } from "react";
|
||||
import { test, expect, describe, beforeEach } from "vitest";
|
||||
import { nanoid } from "nanoid";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import {
|
||||
type NestingRule,
|
||||
createRegularStyleSheet,
|
||||
@@ -109,7 +109,7 @@ beforeEach(() => {
|
||||
$breakpoints.set(
|
||||
new Map(
|
||||
initialBreakpoints.map((breakpoint) => {
|
||||
const id = nanoid();
|
||||
const id = createId("nano");
|
||||
return [id, { ...breakpoint, id }];
|
||||
})
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Database } from "@webstudio-is/postgrest/index.server";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import {
|
||||
AuthorizationError,
|
||||
type AppContext,
|
||||
@@ -86,7 +87,7 @@ const genericCreateAccount = async (
|
||||
throw new Error("User not found");
|
||||
}
|
||||
|
||||
const userId = crypto.randomUUID();
|
||||
const userId = createId();
|
||||
|
||||
const newUser = await context.postgrest.client
|
||||
.from("User")
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { shallowEqual } from "shallow-equal";
|
||||
import type { ExoticComponent } from "react";
|
||||
import { atom } from "nanostores";
|
||||
@@ -9,6 +8,7 @@ import type {
|
||||
InstanceData,
|
||||
} from "@webstudio-is/react-sdk";
|
||||
import {
|
||||
createId,
|
||||
getIndexesWithinAncestors,
|
||||
type Instance,
|
||||
type WsComponentMeta,
|
||||
@@ -60,7 +60,7 @@ const createHookContext = (): HookContext => {
|
||||
const newProps = props.get(instanceKey) ?? new Map();
|
||||
|
||||
const propBase = {
|
||||
id: nanoid(),
|
||||
id: createId("nano"),
|
||||
instanceId: instanceData.id,
|
||||
name: propName,
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
$workspaceRole,
|
||||
$workspaces,
|
||||
} from "~/dashboard/workspace/workspace-stores";
|
||||
import { nanoid } from "nanoid";
|
||||
import type { AuthPermit } from "@webstudio-is/trpc-interface/index.server";
|
||||
import {
|
||||
defaultPlanFeatures,
|
||||
@@ -14,13 +13,14 @@ import {
|
||||
import type { Role } from "@webstudio-is/project";
|
||||
import type { User } from "~/shared/db/user.server";
|
||||
import { toast, type Placement } from "@webstudio-is/design-system";
|
||||
import type {
|
||||
Instance,
|
||||
Prop,
|
||||
Props,
|
||||
StyleDecl,
|
||||
StyleSource,
|
||||
AssetType,
|
||||
import {
|
||||
createId,
|
||||
type AssetType,
|
||||
type Instance,
|
||||
type Prop,
|
||||
type Props,
|
||||
type StyleDecl,
|
||||
type StyleSource,
|
||||
} from "@webstudio-is/sdk";
|
||||
import type { CssProperty, UnitValue } from "@webstudio-is/css-engine";
|
||||
import type { TokenPermissions } from "@webstudio-is/authorization-token";
|
||||
@@ -233,7 +233,7 @@ export const $selectedInstanceStyleSources = computed(
|
||||
// always put local style source last
|
||||
selectedInstanceStyleSources.push({
|
||||
type: "local",
|
||||
id: nanoid(),
|
||||
id: createId("nano"),
|
||||
});
|
||||
}
|
||||
return selectedInstanceStyleSources;
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
type Subscription,
|
||||
} from "./polling-manager";
|
||||
import type { TopicName, TopicRegistry, SubscriptionResponse } from "./types";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
|
||||
// ── Channel message types ────────────────────────────────────────
|
||||
|
||||
@@ -82,7 +83,7 @@ export const createCrossTabPollingManager = (
|
||||
channelName = DEFAULT_CHANNEL_NAME,
|
||||
heartbeatInterval = HEARTBEAT_INTERVAL,
|
||||
heartbeatTimeout = HEARTBEAT_TIMEOUT,
|
||||
tabId = crypto.randomUUID(),
|
||||
tabId = createId(),
|
||||
createChannel = (name: string) => new BroadcastChannel(name),
|
||||
...managerOptions
|
||||
} = options;
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
StorySection,
|
||||
} from "@webstudio-is/design-system";
|
||||
import { useEffect, useState } from "react";
|
||||
import { nanoid } from "nanoid";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import {
|
||||
type LinkOptions,
|
||||
ShareProject as ShareProjectComponent,
|
||||
@@ -20,7 +20,7 @@ export default {
|
||||
|
||||
const initialLinks: Array<LinkOptions> = [
|
||||
{
|
||||
token: nanoid(),
|
||||
token: createId("nano"),
|
||||
name: "View Only",
|
||||
relation: "viewers",
|
||||
canClone: false,
|
||||
@@ -29,7 +29,7 @@ const initialLinks: Array<LinkOptions> = [
|
||||
canUseApi: false,
|
||||
},
|
||||
{
|
||||
token: nanoid(),
|
||||
token: createId("nano"),
|
||||
name: "View and Edit",
|
||||
relation: "editors",
|
||||
canClone: false,
|
||||
@@ -38,7 +38,7 @@ const initialLinks: Array<LinkOptions> = [
|
||||
canUseApi: false,
|
||||
},
|
||||
{
|
||||
token: nanoid(),
|
||||
token: createId("nano"),
|
||||
name: "Build",
|
||||
relation: "builders",
|
||||
canClone: false,
|
||||
@@ -70,7 +70,7 @@ const useShareProject = (
|
||||
setLinks([
|
||||
...currentLinks,
|
||||
{
|
||||
token: nanoid(),
|
||||
token: createId("nano"),
|
||||
name: "Custom Link",
|
||||
relation: "viewers",
|
||||
canClone: false,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { createNanoEvents } from "nanoevents";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import type { Change, Store } from "immerhin";
|
||||
import type { WritableAtom } from "nanostores";
|
||||
import type {
|
||||
@@ -154,7 +154,11 @@ export class NanostoresSyncObject implements SyncObject {
|
||||
if (this.operation !== "local") {
|
||||
return;
|
||||
}
|
||||
const transaction = { id: nanoid(), object: this.name, payload };
|
||||
const transaction = {
|
||||
id: createId("nano"),
|
||||
object: this.name,
|
||||
payload,
|
||||
};
|
||||
sendTransaction(transaction);
|
||||
});
|
||||
signal.addEventListener("abort", unsubscribe);
|
||||
@@ -218,7 +222,7 @@ type SyncClientOptions = {
|
||||
};
|
||||
|
||||
export class SyncClient {
|
||||
clientId = nanoid();
|
||||
clientId = createId("nano");
|
||||
role: SyncClientOptions["role"];
|
||||
object: SyncObject;
|
||||
storages: SyncStorage[];
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Project } from "@webstudio-is/project";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import type { AuthPermit } from "@webstudio-is/trpc-interface/index.server";
|
||||
import { toast } from "@webstudio-is/design-system";
|
||||
import { nativeClient } from "~/shared/trpc/trpc-client";
|
||||
@@ -64,7 +65,7 @@ export const createMultiplayerSyncClient = ({
|
||||
}): MultiplayerSyncClient => {
|
||||
let buildId: string | undefined;
|
||||
let unsubscribePresence: (() => void) | undefined;
|
||||
const clientId = crypto.randomUUID();
|
||||
const clientId = createId();
|
||||
const emitter = createMultiplayerSyncEmitter({
|
||||
getAuthToken: createCollabAuthTokenLoader({
|
||||
authPermit,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Store } from "immerhin";
|
||||
import { enableMapSet, setAutoFreeze } from "immer";
|
||||
import { useEffect } from "react";
|
||||
import { batched } from "nanostores";
|
||||
import { nanoid } from "nanoid";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import { $project } from "./data-stores";
|
||||
import {
|
||||
$selectedPageHash,
|
||||
@@ -243,7 +243,11 @@ class SelectedPageAndInstanceSyncObject {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
sendTransaction({ id: nanoid(), object: this.name, payload: state });
|
||||
sendTransaction({
|
||||
id: createId("nano"),
|
||||
object: this.name,
|
||||
payload: state,
|
||||
});
|
||||
}
|
||||
);
|
||||
signal.addEventListener("abort", unsubscribe);
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
"fontkit": "^2.0.4",
|
||||
"image-meta": "^0.2.1",
|
||||
"immer": "^10.1.1",
|
||||
"nanoid": "^5.1.5",
|
||||
"warn-once": "^0.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
type ContentSource,
|
||||
} from "@webstudio-is/content-engine/compiler";
|
||||
import {
|
||||
createId,
|
||||
toAssetReferenceRuntimeData,
|
||||
type Asset,
|
||||
type AssetFolder,
|
||||
@@ -62,7 +63,6 @@ import type {
|
||||
AssetObjectStore,
|
||||
AssetObjectWriter,
|
||||
} from "./client";
|
||||
import { nanoid } from "nanoid";
|
||||
import {
|
||||
createUploadTicket,
|
||||
uploadFile,
|
||||
@@ -155,7 +155,7 @@ const defaultDependencies = {
|
||||
loadAssetFoldersByProjectWithClient,
|
||||
upsertAssetFolderWithClient,
|
||||
deleteAssetFoldersWithClient,
|
||||
createId: (): string => nanoid(),
|
||||
createId: (): string => createId("nano"),
|
||||
now: () => new Date(),
|
||||
loadCanonicalAssetBaseEntries,
|
||||
synchronizeCanonicalAssets,
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
getProjectPlanFeatures,
|
||||
} from "@webstudio-is/trpc-interface/index.server";
|
||||
import { createHash } from "node:crypto";
|
||||
import { nanoid } from "nanoid";
|
||||
import {
|
||||
createId as createSdkId,
|
||||
getFileExtension,
|
||||
getFileNameParts,
|
||||
type Asset,
|
||||
@@ -287,7 +287,7 @@ const cleanupUploadError = async (
|
||||
export const createUploadTicket = async (
|
||||
data: CreateUploadTicketInput,
|
||||
context: AppContext,
|
||||
createId: () => Asset["id"] = nanoid
|
||||
createId: () => Asset["id"] = () => createSdkId("nano")
|
||||
): Promise<UploadTicket> => {
|
||||
const {
|
||||
projectId,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { getFileNameParts } from "@webstudio-is/sdk";
|
||||
import { createId, getFileNameParts } from "@webstudio-is/sdk";
|
||||
|
||||
export const createUniqueAssetFilename = (filename: string) => {
|
||||
const { basename, extension } = getFileNameParts(filename);
|
||||
return `${basename}_${nanoid()}${extension === "" ? "" : `.${extension}`}`;
|
||||
return `${basename}_${createId("nano")}${extension === "" ? "" : `.${extension}`}`;
|
||||
};
|
||||
@@ -12,6 +12,7 @@
|
||||
"dependencies": {
|
||||
"@trpc/server": "^10.45.2",
|
||||
"@webstudio-is/postgrest": "workspace:*",
|
||||
"@webstudio-is/sdk": "workspace:*",
|
||||
"@webstudio-is/trpc-interface": "workspace:*",
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Database } from "@webstudio-is/postgrest/index.server";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import {
|
||||
type AppContext,
|
||||
authorizeProject,
|
||||
@@ -174,7 +175,7 @@ export const create = async (
|
||||
},
|
||||
context: AppContext
|
||||
) => {
|
||||
const tokenId = crypto.randomUUID();
|
||||
const tokenId = createId();
|
||||
|
||||
// Only owner of the project can create authorization tokens
|
||||
const canCreateToken = await authorizeProject.hasProjectPermit(
|
||||
|
||||
@@ -61,7 +61,6 @@
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"get-port": "^7.2.0",
|
||||
"immer": "^10.1.1",
|
||||
"nanoid": "^5.1.5",
|
||||
"p-limit": "^6.2.0",
|
||||
"parse5": "7.3.0",
|
||||
"path-key": "^4.0.0",
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
"@webstudio-is/project-build": "workspace:*",
|
||||
"@webstudio-is/sdk": "workspace:*",
|
||||
"@webstudio-is/trpc-interface": "workspace:*",
|
||||
"nanoid": "^5.1.5",
|
||||
"type-fest": "^4.37.0",
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
createErrorResponse,
|
||||
getPlanFeaturesByOwnerId,
|
||||
} from "@webstudio-is/trpc-interface/index.server";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import * as projectApi from "@webstudio-is/project/index.server";
|
||||
import { unpublishBuild } from "@webstudio-is/project-build/server";
|
||||
import { validateDomain } from "./validate";
|
||||
@@ -69,7 +70,7 @@ export const create = async (
|
||||
.from("Domain")
|
||||
.upsert(
|
||||
{
|
||||
id: crypto.randomUUID(),
|
||||
id: createId(),
|
||||
domain,
|
||||
status: "INITIALIZING",
|
||||
},
|
||||
@@ -94,7 +95,7 @@ export const create = async (
|
||||
}
|
||||
|
||||
const domainId = domainRow.data.id;
|
||||
const txtRecord = crypto.randomUUID();
|
||||
const txtRecord = createId();
|
||||
|
||||
const result = await context.postgrest.client.from("ProjectDomain").insert({
|
||||
domainId,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { z } from "zod";
|
||||
import * as projectApi from "@webstudio-is/project/index.server";
|
||||
import {
|
||||
@@ -7,6 +6,7 @@ import {
|
||||
} from "@webstudio-is/project-build/server";
|
||||
import { parseDeployment } from "@webstudio-is/project-build/persistence";
|
||||
import {
|
||||
createId,
|
||||
templates as templateSchema,
|
||||
type Deployment,
|
||||
} from "@webstudio-is/sdk";
|
||||
@@ -258,7 +258,7 @@ export const publishStaticProject = async (
|
||||
{
|
||||
projectId,
|
||||
templates,
|
||||
name = `${projectId}-${nanoid()}.zip`,
|
||||
name = `${projectId}-${createId("nano")}.zip`,
|
||||
}: {
|
||||
projectId: string;
|
||||
templates: z.infer<typeof templateSchema>[];
|
||||
@@ -441,4 +441,4 @@ export const verifyProjectDomainResult = async (
|
||||
return await db.verify(input, context);
|
||||
};
|
||||
|
||||
export const createUnpublishJobId = () => `unpublish-${nanoid()}`;
|
||||
export const createUnpublishJobId = () => `unpublish-${createId("nano")}`;
|
||||
@@ -95,7 +95,6 @@
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fastest-levenshtein": "^1.0.16",
|
||||
"immer": "^10.1.1",
|
||||
"nanoid": "^5.1.5",
|
||||
"papaparse": "^5.5.3",
|
||||
"slugify": "^1.6.6",
|
||||
"title-case": "^4.3.2",
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from "@webstudio-is/trpc-interface/index.server";
|
||||
import { db as authDb } from "@webstudio-is/authorization-token/index.server";
|
||||
import {
|
||||
createId,
|
||||
dataSource,
|
||||
type Deployment,
|
||||
type Resource,
|
||||
@@ -279,7 +280,7 @@ export const createBuild = async (
|
||||
const data = createPages();
|
||||
const pages = removeLegacyProjectSettingsFromPages(data.pages);
|
||||
const newBuild = await context.postgrest.client.from("Build").insert({
|
||||
id: crypto.randomUUID(),
|
||||
id: createId(),
|
||||
projectId: props.projectId,
|
||||
pages: JSON.stringify(serializePages(pages)),
|
||||
projectSettings: JSON.stringify({ meta: {}, compiler: {} }),
|
||||
|
||||
@@ -3,7 +3,7 @@ import { builderRuntimeContext } from "./context";
|
||||
|
||||
describe("builderRuntimeContext", () => {
|
||||
test("provides runtime-owned id generation", () => {
|
||||
expect(builderRuntimeContext.createId()).toEqual(expect.any(String));
|
||||
expect(builderRuntimeContext.createId()).toMatch(/^[\w-]{21}$/);
|
||||
expect(builderRuntimeContext.createId()).not.toEqual(
|
||||
builderRuntimeContext.createId()
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import type { ContentBlockApplication } from "./content-block-application";
|
||||
|
||||
export type BuilderRuntimeContext = {
|
||||
@@ -11,5 +11,5 @@ export type BuilderRuntimeContext = {
|
||||
};
|
||||
|
||||
export const builderRuntimeContext: BuilderRuntimeContext = {
|
||||
createId: nanoid,
|
||||
createId: () => createId("nano"),
|
||||
};
|
||||
@@ -1,9 +1,9 @@
|
||||
// Fragment utilities own extracting, copying, and conflict-checking portable
|
||||
// Webstudio fragments. Put serialization-style instance subtree cloning and
|
||||
// fragment asset/style/data remapping here, not live tree placement decisions.
|
||||
import { nanoid } from "nanoid";
|
||||
import { migrateCodeTextContentMutable } from "@webstudio-is/project-migrations";
|
||||
import {
|
||||
createId,
|
||||
type Asset,
|
||||
type Breakpoints,
|
||||
type DataSource,
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
portalComponent,
|
||||
webstudioFragment,
|
||||
} from "@webstudio-is/sdk";
|
||||
|
||||
import {
|
||||
findAvailableVariables,
|
||||
replaceDataSourcesInExpression,
|
||||
@@ -55,6 +56,8 @@ import {
|
||||
} from "./style-utils";
|
||||
import { countDataSourceAssetReferences } from "./assets";
|
||||
|
||||
const createNanoId = () => createId("nano");
|
||||
|
||||
export type ContentModeCopyableProp = (input: {
|
||||
prop: Prop;
|
||||
fragment: WebstudioFragment;
|
||||
@@ -609,7 +612,7 @@ export const insertWebstudioFragmentCopy = ({
|
||||
onBreakpointLimitMerge,
|
||||
metas,
|
||||
contentModeCopyableProp,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
// In content mode, insertion keeps content-editable instance data, creates
|
||||
// local styles for inserted instances, and avoids data/resource records.
|
||||
contentMode = false,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import type { WebstudioFragment } from "@webstudio-is/sdk";
|
||||
import { createId, type WebstudioFragment } from "@webstudio-is/sdk";
|
||||
import { renderTemplate } from "@webstudio-is/template";
|
||||
import { componentMetas } from "@webstudio-is/sdk-components-registry/metas";
|
||||
import {
|
||||
@@ -27,7 +26,7 @@ const isTemplateValidationMessage = (message: string) =>
|
||||
);
|
||||
|
||||
const createWebstudioJsxFragmentIdFactory = () => {
|
||||
const salt = randomUUID();
|
||||
const salt = createId();
|
||||
let index = 0;
|
||||
return () => `__webstudio_jsx_fragment_${salt}_${index++}`;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import {
|
||||
createId,
|
||||
ROOT_FOLDER_ID,
|
||||
ROOT_INSTANCE_ID,
|
||||
encodeDataVariableId,
|
||||
@@ -48,9 +49,10 @@ import {
|
||||
Variable,
|
||||
ws,
|
||||
} from "@webstudio-is/template";
|
||||
import { nanoid } from "nanoid";
|
||||
import { applyBuilderPatchTransactions } from "../state/patch";
|
||||
|
||||
const createNanoId = () => createId("nano");
|
||||
|
||||
const { deduplicateName, deduplicatePath, joinPath } = pageCopyTesting;
|
||||
|
||||
const toMap = <T extends { id: string }>(list: T[]) =>
|
||||
@@ -78,7 +80,7 @@ test("requires an explicit resolution for conflicting transferred root styles",
|
||||
}),
|
||||
},
|
||||
},
|
||||
{ createId: nanoid }
|
||||
{ createId: createNanoId }
|
||||
)
|
||||
).toThrow(/root style conflicts require an explicit/i);
|
||||
});
|
||||
@@ -94,7 +96,7 @@ test("requires an explicit resolution for conflicting copied root styles", () =>
|
||||
sourceData: source,
|
||||
pageId: "source-page",
|
||||
},
|
||||
{ createId: nanoid }
|
||||
{ createId: createNanoId }
|
||||
)
|
||||
).toThrow(/root style conflicts require an explicit/i);
|
||||
});
|
||||
@@ -114,7 +116,7 @@ test.each([
|
||||
pageId: "source-page",
|
||||
rootStyleConflictResolution,
|
||||
},
|
||||
{ createId: nanoid }
|
||||
{ createId: createNanoId }
|
||||
);
|
||||
const updated = applyBuilderPatchTransactions(target, [
|
||||
{ id: "copy-page", payload: mutation.payload },
|
||||
@@ -498,7 +500,7 @@ describe("insert page copy", () => {
|
||||
name: "Copy",
|
||||
path: "/copy",
|
||||
},
|
||||
{ createId: nanoid }
|
||||
{ createId: createNanoId }
|
||||
);
|
||||
|
||||
expect(result.result.pageId).toEqual(expect.any(String));
|
||||
@@ -572,7 +574,7 @@ describe("insert page copy", () => {
|
||||
name: "Copy",
|
||||
path: "/copy",
|
||||
},
|
||||
{ createId: nanoid }
|
||||
{ createId: createNanoId }
|
||||
);
|
||||
|
||||
expect(mutation.payload).toContainEqual({
|
||||
@@ -728,7 +730,7 @@ describe("insert page copy", () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
{ createId: nanoid }
|
||||
{ createId: createNanoId }
|
||||
)
|
||||
).toThrow('Copied variable "missing" was not found');
|
||||
expect(data.pages.pages.size).toBe(2);
|
||||
@@ -779,7 +781,7 @@ describe("insert page copy", () => {
|
||||
pageId: "pageId",
|
||||
path: "/copy",
|
||||
},
|
||||
{ createId: nanoid }
|
||||
{ createId: createNanoId }
|
||||
)
|
||||
).toThrow('Page path "/copy" is already in use');
|
||||
});
|
||||
@@ -827,7 +829,7 @@ describe("insert page copy", () => {
|
||||
projectId: "projectId",
|
||||
folderId: "folderId",
|
||||
},
|
||||
{ createId: nanoid }
|
||||
{ createId: createNanoId }
|
||||
);
|
||||
|
||||
expect(result.result.folderId).toEqual(expect.any(String));
|
||||
@@ -862,7 +864,7 @@ describe("insert page copy", () => {
|
||||
projectId: "projectId",
|
||||
folderId: "missing",
|
||||
},
|
||||
{ createId: nanoid }
|
||||
{ createId: createNanoId }
|
||||
)
|
||||
).toThrow("Folder parent folder was not found");
|
||||
});
|
||||
@@ -1297,7 +1299,7 @@ describe("insert page copy", () => {
|
||||
</$.Body>
|
||||
</ws.root>,
|
||||
// generate different ids in source and data projects
|
||||
nanoid
|
||||
createNanoId
|
||||
),
|
||||
};
|
||||
sourceData.instances.delete(ROOT_INSTANCE_ID);
|
||||
@@ -1310,7 +1312,7 @@ describe("insert page copy", () => {
|
||||
<$.Body ws:id="anotherBodyId"></$.Body>
|
||||
</ws.root>,
|
||||
// generate different ids in source and data projects
|
||||
nanoid
|
||||
createNanoId
|
||||
),
|
||||
};
|
||||
targetData.instances.delete(ROOT_INSTANCE_ID);
|
||||
@@ -1349,7 +1351,7 @@ describe("insert page copy", () => {
|
||||
</$.Body>
|
||||
</ws.root>,
|
||||
// generate different ids in source and data projects
|
||||
nanoid
|
||||
createNanoId
|
||||
),
|
||||
};
|
||||
sourceData.instances.delete(ROOT_INSTANCE_ID);
|
||||
@@ -1358,7 +1360,7 @@ describe("insert page copy", () => {
|
||||
rootInstanceId: "anotherBodyId",
|
||||
}),
|
||||
// generate different ids in source and data projects
|
||||
...renderData(<$.Body ws:id="anotherBodyId"></$.Body>, nanoid),
|
||||
...renderData(<$.Body ws:id="anotherBodyId"></$.Body>, createNanoId),
|
||||
};
|
||||
insertPageCopyMutable({
|
||||
source: { data: sourceData, pageId: sourceData.pages.homePageId },
|
||||
@@ -1738,7 +1740,7 @@ describe("insert page copy", () => {
|
||||
const result = duplicatePageTemplate(
|
||||
data,
|
||||
{ projectId: "projectId", templateId: "templateId" },
|
||||
{ createId: nanoid }
|
||||
{ createId: createNanoId }
|
||||
);
|
||||
|
||||
expect(result.result.templateId).toEqual(expect.any(String));
|
||||
@@ -1942,7 +1944,7 @@ describe("insert page copy", () => {
|
||||
name: "Landing",
|
||||
path: "/landing",
|
||||
},
|
||||
{ createId: nanoid }
|
||||
{ createId: createNanoId }
|
||||
)
|
||||
).toThrow('Page path "/landing" is already in use');
|
||||
});
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
resolveFragmentRootStyleConflicts,
|
||||
} from "./fragment";
|
||||
import { isFragmentContentModeCopyableProp } from "./content-mode-copy-policy";
|
||||
import { nanoid } from "nanoid";
|
||||
import { z } from "zod";
|
||||
import { parseStringLiteralExpression } from "@webstudio-is/expression";
|
||||
import {
|
||||
@@ -18,6 +17,7 @@ import {
|
||||
unsetExpressionVariables,
|
||||
} from "./data";
|
||||
import {
|
||||
createId,
|
||||
findParentFolderByChildId,
|
||||
findPageByIdOrPath,
|
||||
getFolderById,
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
type WebstudioData,
|
||||
ROOT_INSTANCE_ID,
|
||||
} from "@webstudio-is/sdk";
|
||||
|
||||
import type {
|
||||
ConflictResolution,
|
||||
RootStyleConflictResolution,
|
||||
@@ -65,6 +66,8 @@ import {
|
||||
type TemplateCopyData,
|
||||
} from "./data-formats/page-transfer";
|
||||
|
||||
const createNanoId = () => createId("nano");
|
||||
|
||||
type CreateId = () => string;
|
||||
|
||||
const pageDuplicateSubstitutionsInput = z.object({
|
||||
@@ -285,7 +288,7 @@ const copyPageRootAndBodyMutable = ({
|
||||
conflictResolution,
|
||||
rootStyleConflictResolution,
|
||||
contentModeCopyableProp,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
contentMode = false,
|
||||
}: {
|
||||
source: WebstudioData;
|
||||
@@ -337,7 +340,7 @@ const copyPageFragmentsMutable = ({
|
||||
rootStyleConflictResolution,
|
||||
contentModeCopyableProp,
|
||||
onBreakpointLimitMerge,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
contentMode = false,
|
||||
}: {
|
||||
target: WebstudioData;
|
||||
@@ -553,7 +556,7 @@ export const insertPageFromTemplateMutable = ({
|
||||
metas,
|
||||
conflictResolution,
|
||||
contentModeCopyableProp,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
contentMode = false,
|
||||
}: {
|
||||
templateId: PageTemplate["id"];
|
||||
@@ -615,7 +618,7 @@ const copyPageMutable = ({
|
||||
projectId,
|
||||
conflictResolution,
|
||||
rootStyleConflictResolution,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
}: {
|
||||
source: { data: WebstudioData; pageId: Page["id"] };
|
||||
target: { data: WebstudioData; folderId: Folder["id"] };
|
||||
@@ -770,7 +773,7 @@ export const createPageDuplicatePayload = ({
|
||||
name,
|
||||
path,
|
||||
substitutions,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
}: {
|
||||
build: Parameters<typeof createWebstudioDataFromBuild>[0]["build"];
|
||||
assets?: Asset[];
|
||||
@@ -1336,7 +1339,7 @@ export const insertPageCopyFromFragmentsMutable = ({
|
||||
rootStyleConflictResolution,
|
||||
contentModeCopyableProp,
|
||||
onBreakpointLimitMerge,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
}: {
|
||||
source: {
|
||||
page: Page;
|
||||
@@ -1382,7 +1385,7 @@ export const insertTemplateCopyFromFragmentsMutable = ({
|
||||
rootStyleConflictResolution,
|
||||
contentModeCopyableProp,
|
||||
onBreakpointLimitMerge,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
}: {
|
||||
source: {
|
||||
template: PageTemplate;
|
||||
@@ -1561,7 +1564,7 @@ export const insertFolderCopyFromDataMutable = ({
|
||||
contentModeCopyableProp,
|
||||
onBreakpointLimitMerge,
|
||||
forceFolderCopySuffix = false,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
}: {
|
||||
source: FolderCopyData;
|
||||
target: { data: WebstudioData; parentFolderId: Folder["id"] };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { toValue } from "@webstudio-is/css-engine";
|
||||
import {
|
||||
createId,
|
||||
getStyleDeclKey,
|
||||
ROOT_INSTANCE_ID,
|
||||
type Breakpoint,
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
} from "@webstudio-is/sdk";
|
||||
import { getUniqueNameWithSuffix } from "./style-utils";
|
||||
|
||||
const createNanoId = () => createId("nano");
|
||||
|
||||
export type ConflictResolution = "ours" | "theirs" | "merge";
|
||||
export type RootStyleConflictResolution = "ours" | "theirs";
|
||||
|
||||
@@ -291,7 +293,7 @@ export const insertStyleSources = ({
|
||||
breakpoints,
|
||||
mergedBreakpointIds,
|
||||
conflictResolution = "theirs",
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
}: {
|
||||
fragmentStyleSources: StyleSource[];
|
||||
fragmentStyles: StyleDecl[];
|
||||
@@ -598,7 +600,7 @@ export const insertLocalStyleSourcesWithNewIds = ({
|
||||
styleSources,
|
||||
styleSourceSelections,
|
||||
styles,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
contentMode = false,
|
||||
breakpoints,
|
||||
styleSourceIdMap = new Map(),
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import { nanoid } from "nanoid";
|
||||
import deepEqual from "fast-deep-equal";
|
||||
import {
|
||||
camelCaseProperty,
|
||||
@@ -15,6 +14,7 @@ import {
|
||||
type StyleValue,
|
||||
} from "@webstudio-is/css-engine";
|
||||
import {
|
||||
createId,
|
||||
getStyleDeclKey,
|
||||
ROOT_INSTANCE_ID,
|
||||
styleDecl as styleDeclSchema,
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
type StyleSources,
|
||||
type Styles,
|
||||
} from "@webstudio-is/sdk";
|
||||
|
||||
import type { BuilderPatch, BuilderPatchChange } from "../contracts/patch";
|
||||
import {
|
||||
paginateOutput,
|
||||
@@ -46,6 +47,8 @@ import { createPropValue } from "./props";
|
||||
import { getStyleSourceStylesSignature } from "./style-copy";
|
||||
import { isBaseWidthBreakpoint } from "./breakpoints";
|
||||
|
||||
const createNanoId = () => createId("nano");
|
||||
|
||||
export const serializeDesignTokens = ({
|
||||
styleSources,
|
||||
styles,
|
||||
@@ -1706,7 +1709,7 @@ export const createLocalStyleSourcePlan = ({
|
||||
styleSourceSelection,
|
||||
styleSources,
|
||||
instanceId,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
}: {
|
||||
styleSourceSelection: StyleSourceSelection | undefined;
|
||||
styleSources: Pick<StyleSources, "get">;
|
||||
@@ -1762,7 +1765,7 @@ export const createLocalStyleSourcePatchPlan = ({
|
||||
styleSources,
|
||||
styleSourceSelection,
|
||||
shouldCreate,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
}: {
|
||||
createdLocalSourceIds: Map<Instance["id"], StyleSource["id"]>;
|
||||
instanceId: Instance["id"];
|
||||
@@ -1831,7 +1834,7 @@ export const getOrCreateLocalStyleSourceIdMutable = ({
|
||||
styleSourceSelections,
|
||||
styleSources,
|
||||
instanceId,
|
||||
createId = nanoid,
|
||||
createId = createNanoId,
|
||||
}: {
|
||||
styleSourceSelections: StyleSourceSelections;
|
||||
styleSources: StyleSources;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import {
|
||||
createId,
|
||||
type Pages,
|
||||
type Folder,
|
||||
ROOT_FOLDER_ID,
|
||||
@@ -19,7 +19,7 @@ export const createRootFolder = (
|
||||
export const createDefaultPages = ({
|
||||
rootInstanceId,
|
||||
systemDataSourceId,
|
||||
homePageId = nanoid(),
|
||||
homePageId = createId("nano"),
|
||||
}: {
|
||||
rootInstanceId: Instance["id"];
|
||||
systemDataSourceId?: DataSource["id"];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import {
|
||||
createId,
|
||||
initialBreakpoints,
|
||||
type Pages,
|
||||
type WebstudioData,
|
||||
@@ -11,12 +11,12 @@ import { createRootFolder } from "./shared/pages-utils";
|
||||
export const createPages = (): WebstudioData => {
|
||||
const breakpoints = initialBreakpoints.map((breakpoint) => ({
|
||||
...breakpoint,
|
||||
id: nanoid(),
|
||||
id: createId("nano"),
|
||||
}));
|
||||
const homePageId = nanoid();
|
||||
const homeBodyId = nanoid();
|
||||
const notFoundPageId = nanoid();
|
||||
const notFoundBodyId = nanoid();
|
||||
const homePageId = createId("nano");
|
||||
const homeBodyId = createId("nano");
|
||||
const notFoundPageId = createId("nano");
|
||||
const notFoundBodyId = createId("nano");
|
||||
|
||||
const data = renderData(
|
||||
<>
|
||||
@@ -94,7 +94,7 @@ export const createPages = (): WebstudioData => {
|
||||
{coreTemplates.builtWithWebstudio.template}
|
||||
</ws.element>
|
||||
</>,
|
||||
nanoid,
|
||||
() => createId("nano"),
|
||||
breakpoints
|
||||
);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
AuthorizationError,
|
||||
getPlanFeaturesByOwnerId,
|
||||
} from "@webstudio-is/trpc-interface/index.server";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import {
|
||||
type NotificationType,
|
||||
type NotificationStatus,
|
||||
@@ -89,7 +90,7 @@ export const create = async (
|
||||
}
|
||||
}
|
||||
|
||||
const newId = crypto.randomUUID();
|
||||
const newId = createId();
|
||||
|
||||
const result = await context.postgrest.client
|
||||
.from("Notification")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { nanoid } from "nanoid";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import {
|
||||
authorizeProject,
|
||||
type AppContext,
|
||||
@@ -99,7 +99,7 @@ export const create = async (
|
||||
throw new Error("The user must be authenticated to create a project");
|
||||
}
|
||||
|
||||
const projectId = crypto.randomUUID();
|
||||
const projectId = createId();
|
||||
|
||||
// When creating inside a workspace, the project is owned by the workspace
|
||||
// owner — not the creating user. This ensures the workspace owner retains
|
||||
@@ -225,7 +225,7 @@ export const softDeleteProject = async (
|
||||
.update({
|
||||
isDeleted: true,
|
||||
// Free the subdomain — each project needs a unique value
|
||||
domain: nanoid(),
|
||||
domain: createId("nano"),
|
||||
})
|
||||
.eq("id", projectId);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Database } from "@webstudio-is/postgrest/index.server";
|
||||
import { createId } from "@webstudio-is/sdk";
|
||||
import {
|
||||
type AppContext,
|
||||
AuthorizationError,
|
||||
@@ -67,7 +68,7 @@ export const create = async (
|
||||
const result = await context.postgrest.client
|
||||
.from("Workspace")
|
||||
.insert({
|
||||
id: crypto.randomUUID(),
|
||||
id: createId(),
|
||||
name: trimmed,
|
||||
isDefault: false,
|
||||
userId,
|
||||
|
||||
@@ -37,8 +37,7 @@
|
||||
"@webstudio-is/icons": "workspace:^",
|
||||
"@webstudio-is/image": "workspace:*",
|
||||
"@webstudio-is/sdk": "workspace:*",
|
||||
"change-case": "^5.4.4",
|
||||
"nanoid": "^5.1.5"
|
||||
"change-case": "^5.4.4"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
"@emotion/hash": "^0.9.2",
|
||||
"@webstudio-is/multiplayer-protocol": "workspace:*",
|
||||
"nanostores": "^0.11.3",
|
||||
"nanoid": "^5.1.5",
|
||||
"immerhin": "*",
|
||||
"partysocket": "^1.1.18"
|
||||
},
|
||||
|
||||
Generated
+3
-18
@@ -1192,9 +1192,6 @@ importers:
|
||||
immer:
|
||||
specifier: ^10.1.1
|
||||
version: 10.1.1
|
||||
nanoid:
|
||||
specifier: ^5.1.5
|
||||
version: 5.1.5
|
||||
warn-once:
|
||||
specifier: ^0.1.1
|
||||
version: 0.1.1
|
||||
@@ -1226,6 +1223,9 @@ importers:
|
||||
'@webstudio-is/postgrest':
|
||||
specifier: workspace:*
|
||||
version: link:../postgrest
|
||||
'@webstudio-is/sdk':
|
||||
specifier: workspace:*
|
||||
version: link:../sdk
|
||||
'@webstudio-is/trpc-interface':
|
||||
specifier: workspace:*
|
||||
version: link:../trpc-interface
|
||||
@@ -1311,9 +1311,6 @@ importers:
|
||||
immer:
|
||||
specifier: ^10.1.1
|
||||
version: 10.1.1
|
||||
nanoid:
|
||||
specifier: ^5.1.5
|
||||
version: 5.1.5
|
||||
p-limit:
|
||||
specifier: ^6.2.0
|
||||
version: 6.2.0
|
||||
@@ -1911,9 +1908,6 @@ importers:
|
||||
'@webstudio-is/trpc-interface':
|
||||
specifier: workspace:*
|
||||
version: link:../trpc-interface
|
||||
nanoid:
|
||||
specifier: ^5.1.5
|
||||
version: 5.1.5
|
||||
type-fest:
|
||||
specifier: ^4.37.0
|
||||
version: 4.37.0
|
||||
@@ -2332,9 +2326,6 @@ importers:
|
||||
immer:
|
||||
specifier: ^10.1.1
|
||||
version: 10.1.1
|
||||
nanoid:
|
||||
specifier: ^5.1.5
|
||||
version: 5.1.5
|
||||
papaparse:
|
||||
specifier: ^5.5.3
|
||||
version: 5.5.3
|
||||
@@ -2514,9 +2505,6 @@ importers:
|
||||
change-case:
|
||||
specifier: ^5.4.4
|
||||
version: 5.4.4
|
||||
nanoid:
|
||||
specifier: ^5.1.5
|
||||
version: 5.1.5
|
||||
devDependencies:
|
||||
'@types/react':
|
||||
specifier: ^18.2.70
|
||||
@@ -3057,9 +3045,6 @@ importers:
|
||||
immerhin:
|
||||
specifier: '*'
|
||||
version: 0.10.0
|
||||
nanoid:
|
||||
specifier: ^5.1.5
|
||||
version: 5.1.5
|
||||
nanostores:
|
||||
specifier: ^0.11.3
|
||||
version: 0.11.3
|
||||
|
||||
Reference in new issue
Block a user