@sanity/workbench 0.1.0-alpha.6 → 0.1.0-alpha.7

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.
Files changed (43) hide show
  1. package/dist/{log.js → _chunks-es/index.js} +1 -1
  2. package/dist/_chunks-es/index.js.map +1 -0
  3. package/dist/_internal.d.ts +13 -6
  4. package/dist/_internal.js +19 -3
  5. package/dist/_internal.js.map +1 -1
  6. package/dist/core.d.ts +906 -0
  7. package/dist/core.js +642 -0
  8. package/dist/core.js.map +1 -0
  9. package/package.json +10 -4
  10. package/src/_exports/core.ts +1 -0
  11. package/src/_internal/index.ts +2 -1
  12. package/src/_internal/render.test.ts +56 -1
  13. package/src/_internal/render.ts +51 -24
  14. package/src/core/__tests__/__fixtures__.ts +248 -0
  15. package/src/core/applications/application-list.test.ts +222 -0
  16. package/src/core/applications/application-list.ts +103 -0
  17. package/src/core/applications/application.ts +78 -0
  18. package/src/core/applications/local-application.test.ts +93 -0
  19. package/src/core/applications/local-application.ts +52 -0
  20. package/src/core/canvases.test.ts +38 -0
  21. package/src/core/canvases.ts +81 -0
  22. package/src/core/config.ts +34 -0
  23. package/src/core/index.ts +12 -0
  24. package/src/core/media-libraries.test.ts +38 -0
  25. package/src/core/media-libraries.ts +83 -0
  26. package/src/core/organizations.test.ts +134 -0
  27. package/src/core/organizations.ts +115 -0
  28. package/src/core/projects.test.ts +248 -0
  29. package/src/core/projects.ts +114 -0
  30. package/src/core/shared/urls.test.ts +182 -0
  31. package/src/core/shared/urls.ts +128 -0
  32. package/src/core/user-applications/core-app.test.ts +151 -0
  33. package/src/core/user-applications/core-app.ts +57 -0
  34. package/src/core/user-applications/studio.test.ts +928 -0
  35. package/src/core/user-applications/studio.ts +656 -0
  36. package/src/core/user-applications/user-application.test.ts +126 -0
  37. package/src/core/user-applications/user-application.ts +76 -0
  38. package/src/vite-env.d.ts +8 -0
  39. package/dist/log.d.ts +0 -48
  40. package/dist/log.js.map +0 -1
  41. package/src/_exports/log.ts +0 -1
  42. /package/src/{log → core/log}/index.test.ts +0 -0
  43. /package/src/{log → core/log}/index.ts +0 -0
@@ -0,0 +1,126 @@
1
+ import type {
2
+ ApplicationResource as ProtocolApplicationResource,
3
+ CoreApplication,
4
+ } from "@sanity/message-protocol";
5
+ import { afterEach, describe, expect, it, vi } from "vitest";
6
+
7
+ import { APPLICATION_DATA } from "../__tests__/__fixtures__";
8
+ import { UserApplication as AbstractUserApplication } from "./user-application";
9
+
10
+ class UserApplication extends AbstractUserApplication<
11
+ CoreApplication,
12
+ "coreApp",
13
+ ProtocolApplicationResource
14
+ > {
15
+ constructor(application: CoreApplication) {
16
+ super(application, "coreApp");
17
+ }
18
+
19
+ get title(): string {
20
+ return this.application.title;
21
+ }
22
+
23
+ get subtitle() {
24
+ return undefined;
25
+ }
26
+
27
+ get href(): string {
28
+ return "";
29
+ }
30
+
31
+ toProtocolResource() {
32
+ return {
33
+ ...this.application,
34
+ type: "application",
35
+ url: this.url.toString(),
36
+ } as const;
37
+ }
38
+ }
39
+
40
+ const setup = (overrides?: Partial<CoreApplication>) =>
41
+ new UserApplication({
42
+ ...APPLICATION_DATA,
43
+ ...overrides,
44
+ } as CoreApplication);
45
+
46
+ describe("UserApplication", () => {
47
+ afterEach(() => {
48
+ vi.unstubAllEnvs();
49
+ });
50
+
51
+ it("should generate a url for an internal application", () => {
52
+ vi.stubEnv("VITE_SANITY_ENV", "staging");
53
+ vi.stubEnv("VITE_SANITY_DOMAIN", "sanity.work");
54
+ const application = setup();
55
+ expect(application.url).toBeInstanceOf(URL);
56
+ expect(application.url.toString()).toMatchInlineSnapshot(
57
+ `"https://x7apsmr6fxvc.studio.sanity.work/"`,
58
+ );
59
+ });
60
+
61
+ it("should respect the SANITY_ENV", () => {
62
+ vi.stubEnv("VITE_SANITY_ENV", "production");
63
+ const application = setup();
64
+ expect(application.url).toBeInstanceOf(URL);
65
+ expect(application.url.toString()).toMatchInlineSnapshot(
66
+ `"https://x7apsmr6fxvc.sanity.studio/"`,
67
+ );
68
+ });
69
+
70
+ it("should generate a url for an external application", () => {
71
+ const application = setup({
72
+ ...APPLICATION_DATA,
73
+ activeDeployment: null,
74
+ appHost: "https://my-app.com",
75
+ urlType: "external",
76
+ });
77
+ expect(application.url).toBeInstanceOf(URL);
78
+ expect(application.url.toString()).toMatchInlineSnapshot(
79
+ `"https://my-app.com/"`,
80
+ );
81
+ });
82
+
83
+ describe("initials", () => {
84
+ const initials = (title: string) => setup({ title }).initials;
85
+
86
+ it("should return the initials of a name", () => {
87
+ expect(initials("John Doe")).toBe("JD");
88
+ });
89
+
90
+ it("should return the initials of a name with extra spaces", () => {
91
+ expect(initials(" John Doe ")).toBe("JD");
92
+ });
93
+
94
+ it("should return intials even if the name is only one word", () => {
95
+ expect(initials("John")).toBe("J");
96
+ });
97
+
98
+ it("should return a maximum of two initials", () => {
99
+ expect(initials("John Doe Smith")).toBe("JS");
100
+ });
101
+
102
+ it("should handle empty string", () => {
103
+ expect(initials("")).toBe("");
104
+ });
105
+
106
+ it("should handle symbols-only string", () => {
107
+ expect(initials("@#$%")).toBe("");
108
+ });
109
+
110
+ it("should handle a single character", () => {
111
+ expect(initials("A")).toBe("A");
112
+ });
113
+
114
+ it("should handle strings containing numbers", () => {
115
+ expect(initials("0xHoldings")).toBe("0X");
116
+ expect(initials("7-Eleven")).toBe("7E");
117
+ expect(initials("Forever 21")).toBe("F2");
118
+ expect(initials("Motel 6")).toBe("M6");
119
+ expect(initials("2 Wire")).toBe("2W");
120
+
121
+ expect(initials("010101")).toBe("01");
122
+ expect(initials("W4t")).toBe("W4");
123
+ expect(initials("H4xx0r")).toBe("H4");
124
+ });
125
+ });
126
+ });
@@ -0,0 +1,76 @@
1
+ import type {
2
+ Resource as ProtocolResource,
3
+ UserApplication as UserApplicationData,
4
+ } from "@sanity/message-protocol";
5
+ import { z } from "zod";
6
+
7
+ import {
8
+ AbstractApplication,
9
+ type AbstractApplicationType,
10
+ } from "../applications/application";
11
+
12
+ /**
13
+ * User application ID schema, branded for type safety.
14
+ * @public
15
+ */
16
+ export const UserApplicationId = z
17
+ .string()
18
+ .nonempty()
19
+ .brand("UserApplicationId");
20
+
21
+ /**
22
+ * User application ID type, branded for type safety.
23
+ * @public
24
+ */
25
+ export type UserApplicationId = z.output<typeof UserApplicationId>;
26
+
27
+ /**
28
+ * Validates and brands a string as a UserApplicationId.
29
+ * @public
30
+ */
31
+ export function brandUserApplicationId(id: string): UserApplicationId {
32
+ return UserApplicationId.parse(id);
33
+ }
34
+
35
+ /**
36
+ * @internal
37
+ */
38
+ export abstract class UserApplication<
39
+ TUserApplication extends UserApplicationData,
40
+ TType extends Extract<AbstractApplicationType, "coreApp" | "studio">,
41
+ TProtocolResource extends ProtocolResource = Extract<
42
+ ProtocolResource,
43
+ { type: TType }
44
+ >,
45
+ > extends AbstractApplication<TType, TProtocolResource> {
46
+ readonly application: TUserApplication;
47
+
48
+ readonly id: UserApplicationId;
49
+
50
+ constructor(application: TUserApplication, type: TType) {
51
+ super(type);
52
+ this.application = application;
53
+ this.id = brandUserApplicationId(application.id);
54
+ }
55
+
56
+ abstract get subtitle(): string | undefined;
57
+
58
+ /**
59
+ * @returns A fully resolved URL instance for the application.
60
+ * For internal applications, constructs a URL using the Sanity studio domain
61
+ * pattern resolved from the environment at the consuming app's build time.
62
+ * For external applications, returns the provided app host as a URL.
63
+ */
64
+ get url(): URL {
65
+ if (this.application.urlType === "internal") {
66
+ if (import.meta.env.VITE_SANITY_ENV === "production") {
67
+ return new URL(`https://${this.application.appHost}.sanity.studio`);
68
+ }
69
+ return new URL(
70
+ `https://${this.application.appHost}.studio.${import.meta.env.VITE_SANITY_DOMAIN}`,
71
+ );
72
+ }
73
+
74
+ return new URL(this.application.appHost);
75
+ }
76
+ }
@@ -0,0 +1,8 @@
1
+ interface ImportMetaEnv {
2
+ readonly VITE_SANITY_ENV: "production" | "staging";
3
+ readonly VITE_SANITY_DOMAIN: "sanity.work" | "sanity.io";
4
+ }
5
+
6
+ interface ImportMeta {
7
+ readonly env: ImportMetaEnv;
8
+ }
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;"}
@@ -1 +0,0 @@
1
- export * from "../log";
File without changes
File without changes