@sanity/workbench 0.1.0-alpha.6 → 0.1.0-alpha.8
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/{log.js → _chunks-es/index.js} +7 -2
- package/dist/_chunks-es/index.js.map +1 -0
- package/dist/_internal.d.ts +13 -6
- package/dist/_internal.js +20 -9
- package/dist/_internal.js.map +1 -1
- package/dist/core.d.ts +1464 -0
- package/dist/core.js +744 -0
- package/dist/core.js.map +1 -0
- package/package.json +12 -4
- package/src/_exports/core.ts +1 -0
- package/src/_internal/index.ts +2 -1
- package/src/_internal/render.test.ts +91 -4
- package/src/_internal/render.ts +53 -33
- package/src/core/__tests__/__fixtures__.ts +245 -0
- package/src/core/applications/application-list.test.ts +222 -0
- package/src/core/applications/application-list.ts +103 -0
- package/src/core/applications/application.ts +78 -0
- package/src/core/applications/local-application.test.ts +93 -0
- package/src/core/applications/local-application.ts +56 -0
- package/src/core/canvases.test.ts +38 -0
- package/src/core/canvases.ts +81 -0
- package/src/core/config.ts +34 -0
- package/src/core/index.ts +12 -0
- package/src/{log → core/log}/index.ts +12 -0
- package/src/core/media-libraries.test.ts +38 -0
- package/src/core/media-libraries.ts +83 -0
- package/src/core/organizations.test.ts +134 -0
- package/src/core/organizations.ts +115 -0
- package/src/core/projects.test.ts +248 -0
- package/src/core/projects.ts +114 -0
- package/src/core/shared/urls.test.ts +182 -0
- package/src/core/shared/urls.ts +128 -0
- package/src/core/user-applications/core-app.test.ts +236 -0
- package/src/core/user-applications/core-app.ts +113 -0
- package/src/core/user-applications/studios/index.ts +3 -0
- package/src/core/user-applications/studios/schemas.test.ts +113 -0
- package/src/core/user-applications/studios/schemas.ts +106 -0
- package/src/core/user-applications/studios/studio.test.ts +997 -0
- package/src/core/user-applications/studios/studio.ts +498 -0
- package/src/core/user-applications/studios/workspace.ts +143 -0
- package/src/core/user-applications/user-application.test.ts +125 -0
- package/src/core/user-applications/user-application.ts +107 -0
- package/src/vite-env.d.ts +8 -0
- package/dist/log.d.ts +0 -48
- package/dist/log.js.map +0 -1
- package/src/_exports/log.ts +0 -1
- /package/src/{log → core/log}/index.test.ts +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// eslint-disable-next-line no-restricted-imports
|
|
2
|
+
import type { ApplicationResource as ProtocolApplicationResource } from "@sanity/message-protocol";
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
|
|
5
|
+
import { APPLICATION_DATA } from "../__tests__/__fixtures__";
|
|
6
|
+
import type { CoreAppUserApplication } from "./core-app";
|
|
7
|
+
import { UserApplication as AbstractUserApplication } from "./user-application";
|
|
8
|
+
|
|
9
|
+
class UserApplication extends AbstractUserApplication<
|
|
10
|
+
CoreAppUserApplication,
|
|
11
|
+
"coreApp",
|
|
12
|
+
ProtocolApplicationResource
|
|
13
|
+
> {
|
|
14
|
+
constructor(application: CoreAppUserApplication) {
|
|
15
|
+
super(application, "coreApp");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get title(): string {
|
|
19
|
+
return this.application.title;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get subtitle() {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get href(): string {
|
|
27
|
+
return "";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
toProtocolResource() {
|
|
31
|
+
return {
|
|
32
|
+
...this.application,
|
|
33
|
+
type: "application",
|
|
34
|
+
url: this.url.toString(),
|
|
35
|
+
} as const;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const setup = (overrides?: Partial<CoreAppUserApplication>) =>
|
|
40
|
+
new UserApplication({
|
|
41
|
+
...APPLICATION_DATA,
|
|
42
|
+
...overrides,
|
|
43
|
+
} as CoreAppUserApplication);
|
|
44
|
+
|
|
45
|
+
describe("UserApplication", () => {
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
vi.unstubAllEnvs();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("should generate a url for an internal application", () => {
|
|
51
|
+
vi.stubEnv("VITE_SANITY_ENV", "staging");
|
|
52
|
+
vi.stubEnv("VITE_SANITY_DOMAIN", "sanity.work");
|
|
53
|
+
const application = setup();
|
|
54
|
+
expect(application.url).toBeInstanceOf(URL);
|
|
55
|
+
expect(application.url.toString()).toMatchInlineSnapshot(
|
|
56
|
+
`"https://x7apsmr6fxvc.studio.sanity.work/"`,
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should respect the SANITY_ENV", () => {
|
|
61
|
+
vi.stubEnv("VITE_SANITY_ENV", "production");
|
|
62
|
+
const application = setup();
|
|
63
|
+
expect(application.url).toBeInstanceOf(URL);
|
|
64
|
+
expect(application.url.toString()).toMatchInlineSnapshot(
|
|
65
|
+
`"https://x7apsmr6fxvc.sanity.studio/"`,
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should generate a url for an external application", () => {
|
|
70
|
+
const application = setup({
|
|
71
|
+
...APPLICATION_DATA,
|
|
72
|
+
activeDeployment: null,
|
|
73
|
+
appHost: "https://my-app.com",
|
|
74
|
+
urlType: "external",
|
|
75
|
+
});
|
|
76
|
+
expect(application.url).toBeInstanceOf(URL);
|
|
77
|
+
expect(application.url.toString()).toMatchInlineSnapshot(
|
|
78
|
+
`"https://my-app.com/"`,
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("initials", () => {
|
|
83
|
+
const initials = (title: string) => setup({ title }).initials;
|
|
84
|
+
|
|
85
|
+
it("should return the initials of a name", () => {
|
|
86
|
+
expect(initials("John Doe")).toBe("JD");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should return the initials of a name with extra spaces", () => {
|
|
90
|
+
expect(initials(" John Doe ")).toBe("JD");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should return intials even if the name is only one word", () => {
|
|
94
|
+
expect(initials("John")).toBe("J");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should return a maximum of two initials", () => {
|
|
98
|
+
expect(initials("John Doe Smith")).toBe("JS");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should handle empty string", () => {
|
|
102
|
+
expect(initials("")).toBe("");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("should handle symbols-only string", () => {
|
|
106
|
+
expect(initials("@#$%")).toBe("");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should handle a single character", () => {
|
|
110
|
+
expect(initials("A")).toBe("A");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should handle strings containing numbers", () => {
|
|
114
|
+
expect(initials("0xHoldings")).toBe("0X");
|
|
115
|
+
expect(initials("7-Eleven")).toBe("7E");
|
|
116
|
+
expect(initials("Forever 21")).toBe("F2");
|
|
117
|
+
expect(initials("Motel 6")).toBe("M6");
|
|
118
|
+
expect(initials("2 Wire")).toBe("2W");
|
|
119
|
+
|
|
120
|
+
expect(initials("010101")).toBe("01");
|
|
121
|
+
expect(initials("W4t")).toBe("W4");
|
|
122
|
+
expect(initials("H4xx0r")).toBe("H4");
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// eslint-disable-next-line no-restricted-imports
|
|
2
|
+
import type { Resource as ProtocolResource } from "@sanity/message-protocol";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
AbstractApplication,
|
|
7
|
+
type AbstractApplicationType,
|
|
8
|
+
} from "../applications/application";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* User application ID schema, branded for type safety.
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
export const UserApplicationId = z
|
|
15
|
+
.string()
|
|
16
|
+
.nonempty()
|
|
17
|
+
.brand("UserApplicationId");
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* User application ID type, branded for type safety.
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export type UserApplicationId = z.output<typeof UserApplicationId>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Validates and brands a string as a UserApplicationId.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export function brandUserApplicationId(id: string): UserApplicationId {
|
|
30
|
+
return UserApplicationId.parse(id);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @public
|
|
35
|
+
*/
|
|
36
|
+
export const UserApplicationBase = z.object({
|
|
37
|
+
id: UserApplicationId,
|
|
38
|
+
appHost: z.string(),
|
|
39
|
+
urlType: z.enum(["internal", "external"]),
|
|
40
|
+
createdAt: z.string(),
|
|
41
|
+
updatedAt: z.string(),
|
|
42
|
+
dashboardStatus: z.enum(["default", "disabled"]),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
export type UserApplicationBase = z.output<typeof UserApplicationBase>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
export const ActiveDeployment = z.object({
|
|
54
|
+
id: z.string(),
|
|
55
|
+
version: z.string(),
|
|
56
|
+
isActiveDeployment: z.boolean(),
|
|
57
|
+
userApplicationId: z.string(),
|
|
58
|
+
isAutoUpdating: z.boolean(),
|
|
59
|
+
size: z.number(),
|
|
60
|
+
deployedAt: z.string(),
|
|
61
|
+
deployedBy: z.string(),
|
|
62
|
+
createdAt: z.string(),
|
|
63
|
+
updatedAt: z.string(),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @internal
|
|
68
|
+
*/
|
|
69
|
+
export abstract class UserApplication<
|
|
70
|
+
TUserApplication extends UserApplicationBase,
|
|
71
|
+
TType extends Extract<AbstractApplicationType, "coreApp" | "studio">,
|
|
72
|
+
TProtocolResource extends ProtocolResource = Extract<
|
|
73
|
+
ProtocolResource,
|
|
74
|
+
{ type: TType }
|
|
75
|
+
>,
|
|
76
|
+
> extends AbstractApplication<TType, TProtocolResource> {
|
|
77
|
+
readonly application: TUserApplication;
|
|
78
|
+
|
|
79
|
+
readonly id: UserApplicationId;
|
|
80
|
+
|
|
81
|
+
constructor(application: TUserApplication, type: TType) {
|
|
82
|
+
super(type);
|
|
83
|
+
this.application = application;
|
|
84
|
+
this.id = brandUserApplicationId(application.id);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
abstract get subtitle(): string | undefined;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @returns A fully resolved URL instance for the application.
|
|
91
|
+
* For internal applications, constructs a URL using the Sanity studio domain
|
|
92
|
+
* pattern resolved from the environment at the consuming app's build time.
|
|
93
|
+
* For external applications, returns the provided app host as a URL.
|
|
94
|
+
*/
|
|
95
|
+
get url(): URL {
|
|
96
|
+
if (this.application.urlType === "internal") {
|
|
97
|
+
if (import.meta.env.VITE_SANITY_ENV === "production") {
|
|
98
|
+
return new URL(`https://${this.application.appHost}.sanity.studio`);
|
|
99
|
+
}
|
|
100
|
+
return new URL(
|
|
101
|
+
`https://${this.application.appHost}.studio.${import.meta.env.VITE_SANITY_DOMAIN}`,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return new URL(this.application.appHost);
|
|
106
|
+
}
|
|
107
|
+
}
|
package/dist/log.d.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @public
|
|
3
|
-
*/
|
|
4
|
-
export declare function createLogger({
|
|
5
|
-
namespace,
|
|
6
|
-
context: baseContext,
|
|
7
|
-
logLevel,
|
|
8
|
-
}?: LoggerOptions): Logger;
|
|
9
|
-
|
|
10
|
-
declare type LogContext = {
|
|
11
|
-
[key: string]: unknown;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @public
|
|
16
|
-
*/
|
|
17
|
-
export declare interface Logger {
|
|
18
|
-
error: (message: string, context?: LogContext) => void;
|
|
19
|
-
warn: (message: string, context?: LogContext) => void;
|
|
20
|
-
info: (message: string, context?: LogContext) => void;
|
|
21
|
-
debug: (message: string, context?: LogContext) => void;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
declare interface LoggerOptions {
|
|
25
|
-
namespace?: LogNamespace;
|
|
26
|
-
context?: LogContext;
|
|
27
|
-
logLevel?: LogLevel;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Log levels in order of verbosity (least to most)
|
|
32
|
-
* - none: Silent
|
|
33
|
-
* - error: Critical failures that prevent operation
|
|
34
|
-
* - warn: Issues that may cause problems but don't stop execution
|
|
35
|
-
* - info: High-level informational messages (default)
|
|
36
|
-
* - debug: Detailed debugging information (maintainer level)
|
|
37
|
-
* - trace: Very detailed tracing — sets `internal: true` on context
|
|
38
|
-
* @public
|
|
39
|
-
*/
|
|
40
|
-
export declare type LogLevel = "none" | "error" | "warn" | "info" | "debug";
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Namespaces organize logs by functional domain.
|
|
44
|
-
* @internal
|
|
45
|
-
*/
|
|
46
|
-
export declare type LogNamespace = string;
|
|
47
|
-
|
|
48
|
-
export {};
|
package/dist/log.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"log.js","sources":["../src/log/index.ts"],"sourcesContent":["/**\n * Log levels in order of verbosity (least to most)\n * - none: Silent\n * - error: Critical failures that prevent operation\n * - warn: Issues that may cause problems but don't stop execution\n * - info: High-level informational messages (default)\n * - debug: Detailed debugging information (maintainer level)\n * - trace: Very detailed tracing — sets `internal: true` on context\n * @public\n */\nexport type LogLevel = \"none\" | \"error\" | \"warn\" | \"info\" | \"debug\";\n\n/**\n * Namespaces organize logs by functional domain.\n * @internal\n */\nexport type LogNamespace = string;\n\ntype LogContext = { [key: string]: unknown };\n\n/**\n * @public\n */\nexport interface Logger {\n error: (message: string, context?: LogContext) => void;\n warn: (message: string, context?: LogContext) => void;\n info: (message: string, context?: LogContext) => void;\n debug: (message: string, context?: LogContext) => void;\n}\n\nconst LEVELS: readonly LogLevel[] = [\"none\", \"error\", \"warn\", \"info\", \"debug\"];\n\ninterface LoggerOptions {\n namespace?: LogNamespace;\n context?: LogContext;\n logLevel?: LogLevel;\n}\n\n/**\n * @public\n */\nexport function createLogger({\n namespace,\n context: baseContext,\n logLevel = \"info\",\n}: LoggerOptions = {}): Logger {\n function isLevelEnabled(level: LogLevel): boolean {\n return LEVELS.indexOf(level) <= LEVELS.indexOf(logLevel);\n }\n\n function logAtLevel(\n level: LogLevel,\n message: string,\n context?: LogContext,\n ): void {\n if (!isLevelEnabled(level)) return;\n\n const merged =\n (baseContext ?? context) ? { ...baseContext, ...context } : undefined;\n const args: unknown[] = [\n ...(namespace ? [`[${namespace}]`] : []),\n message,\n ...(merged ? [merged] : []),\n ];\n\n if (level === \"error\") console.error(...args);\n else if (level === \"warn\") console.warn(...args);\n // oxlint-disable-next-line no-console\n else if (level === \"info\") console.info(...args);\n // oxlint-disable-next-line no-console\n else console.debug(...args);\n }\n\n return {\n error: (message, context) => logAtLevel(\"error\", message, context),\n warn: (message, context) => logAtLevel(\"warn\", message, context),\n info: (message, context) => logAtLevel(\"info\", message, context),\n debug: (message, context) => logAtLevel(\"debug\", message, context),\n };\n}\n"],"names":[],"mappings":"AA8BA,MAAM,SAA8B,CAAC,QAAQ,SAAS,QAAQ,QAAQ,OAAO;AAWtE,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA,SAAS;AAAA,EACT,WAAW;AACb,IAAmB,IAAY;AAC7B,WAAS,eAAe,OAA0B;AAChD,WAAO,OAAO,QAAQ,KAAK,KAAK,OAAO,QAAQ,QAAQ;AAAA,EACzD;AAEA,WAAS,WACP,OACA,SACA,SACM;AACN,QAAI,CAAC,eAAe,KAAK,EAAG;AAE5B,UAAM,SACH,eAAe,UAAW,EAAE,GAAG,aAAa,GAAG,QAAA,IAAY,QACxD,OAAkB;AAAA,MACtB,GAAI,YAAY,CAAC,IAAI,SAAS,GAAG,IAAI,CAAA;AAAA,MACrC;AAAA,MACA,GAAI,SAAS,CAAC,MAAM,IAAI,CAAA;AAAA,IAAC;AAGvB,cAAU,UAAS,QAAQ,MAAM,GAAG,IAAI,IACnC,UAAU,SAAQ,QAAQ,KAAK,GAAG,IAAI,IAEtC,UAAU,SAAQ,QAAQ,KAAK,GAAG,IAAI,IAE1C,QAAQ,MAAM,GAAG,IAAI;AAAA,EAC5B;AAEA,SAAO;AAAA,IACL,OAAO,CAAC,SAAS,YAAY,WAAW,SAAS,SAAS,OAAO;AAAA,IACjE,MAAM,CAAC,SAAS,YAAY,WAAW,QAAQ,SAAS,OAAO;AAAA,IAC/D,MAAM,CAAC,SAAS,YAAY,WAAW,QAAQ,SAAS,OAAO;AAAA,IAC/D,OAAO,CAAC,SAAS,YAAY,WAAW,SAAS,SAAS,OAAO;AAAA,EAAA;AAErE;"}
|
package/src/_exports/log.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "../log";
|
|
File without changes
|