@dressed/react 1.1.0 → 1.3.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/dist/index.d.ts CHANGED
@@ -1,49 +1,3 @@
1
- import type { ReactNode } from "react";
2
- import { type APIInteractionResponseCallbackData, type APIModalInteractionResponseCallbackData } from "discord-api-types/v10";
3
- import type { createInteraction, RawFile } from "dressed/server";
4
- type ReplyProps = [
5
- components: ReactNode,
6
- data?: Omit<APIInteractionResponseCallbackData, "content"> & {
7
- /** Whether the message is ephemeral */
8
- ephemeral?: boolean;
9
- /** The files to send with the message */
10
- files?: RawFile[];
11
- /** Whether to return the source message with the response */
12
- with_response?: boolean;
13
- }
14
- ];
15
- type EditReplyProps = [
16
- components: ReactNode,
17
- data?: Omit<APIInteractionResponseCallbackData, "content"> & {
18
- /** The files to send with the message */
19
- files?: RawFile[];
20
- }
21
- ];
22
- type FollowUpProps = [
23
- components: ReactNode,
24
- data?: Omit<APIInteractionResponseCallbackData, "content"> & {
25
- /** The files to send with the message */
26
- files?: RawFile[];
27
- /** Whether the message is ephemeral */
28
- ephemeral?: boolean;
29
- }
30
- ];
31
- type ShowModalProps = [
32
- components: ReactNode,
33
- data?: Omit<APIModalInteractionResponseCallbackData, "components">
34
- ];
35
- type ReactivatedInteraction<T extends NonNullable<ReturnType<typeof createInteraction>>> = OverrideMethodParams<T, {
36
- reply: ReplyProps;
37
- editReply: EditReplyProps;
38
- update: EditReplyProps;
39
- followUp: FollowUpProps;
40
- showModal: ShowModalProps;
41
- }>;
42
- type OverrideMethodParams<T, Overrides extends Record<string, unknown[]>> = {
43
- [K in keyof T]: K extends keyof Overrides ? T[K] extends (...args: any) => any ? (...args: Overrides[K]) => ReturnType<T[K]> : T[K] : T[K];
44
- };
45
- export declare function render(component: ReactNode): Promise<import("./react/renderer.ts").Renderer>;
46
- export declare function patchInteraction<T extends NonNullable<ReturnType<typeof createInteraction>>>(interaction: T): ReactivatedInteraction<T>;
47
1
  export { ActionRow } from "./components/action-row.ts";
48
2
  export { Button } from "./components/button.ts";
49
3
  export { Container } from "./components/container.ts";
@@ -55,3 +9,6 @@ export { Separator } from "./components/separator.ts";
55
9
  export { TextDisplay } from "./components/text-display.ts";
56
10
  export { TextInput } from "./components/text-input.ts";
57
11
  export { Thumbnail } from "./components/thumbnail.ts";
12
+ export * from "./rendering/index.ts";
13
+ export * from "./rendering/interaction.ts";
14
+ export * from "./rendering/message.ts";
package/dist/index.js CHANGED
@@ -1,39 +1,4 @@
1
- import { MessageFlags, } from "discord-api-types/v10";
2
- import { createRenderer } from "./react/renderer.js";
3
- import { reconciler } from "./react/reconciler.js";
4
- export async function render(component) {
5
- const container = createRenderer();
6
- const root = reconciler.createContainer(container, 0, null, false, null, "dressed", (error) => console.error(error), null);
7
- if (root !== null) {
8
- await new Promise((r) => reconciler.updateContainer(component, root, null, r));
9
- await container.render();
10
- }
11
- return container;
12
- }
13
- export function patchInteraction(interaction) {
14
- if (!interaction)
15
- throw new Error("No interaction");
16
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
- const newInteraction = interaction;
18
- for (const method of [
19
- "reply",
20
- "editReply",
21
- "update",
22
- "followUp",
23
- ]) {
24
- if (!(method in interaction))
25
- continue;
26
- const original = interaction[method];
27
- newInteraction[method] = async (components, data = {}) => {
28
- var _a;
29
- const flags = ((_a = data.flags) !== null && _a !== void 0 ? _a : 0) | MessageFlags.IsComponentsV2;
30
- data.flags = flags;
31
- data.components = (await render(components)).components;
32
- return original(data);
33
- };
34
- }
35
- return newInteraction;
36
- }
1
+ // Components
37
2
  export { ActionRow } from "./components/action-row.js";
38
3
  export { Button } from "./components/button.js";
39
4
  export { Container } from "./components/container.js";
@@ -45,4 +10,8 @@ export { Separator } from "./components/separator.js";
45
10
  export { TextDisplay } from "./components/text-display.js";
46
11
  export { TextInput } from "./components/text-input.js";
47
12
  export { Thumbnail } from "./components/thumbnail.js";
13
+ // Rendering
14
+ export * from "./rendering/index.js";
15
+ export * from "./rendering/interaction.js";
16
+ export * from "./rendering/message.js";
48
17
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,GAGb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAyDnD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,SAAoB;IAC/C,MAAM,SAAS,GAAG,cAAc,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,UAAU,CAAC,eAAe,CACrC,SAAS,EACT,CAAC,EACD,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,SAAS,EACT,CAAC,KAAY,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EACtC,IAAI,CACL,CAAC;IAEF,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAC5B,UAAU,CAAC,eAAe,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CACrD,CAAC;QACF,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC;IAC3B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAE9B,WAAc;IACd,IAAI,CAAC,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACpD,8DAA8D;IAC9D,MAAM,cAAc,GAAG,WAAkB,CAAC;IAC1C,KAAK,MAAM,MAAM,IAAI;QACnB,OAAO;QACP,WAAW;QACX,QAAQ;QACR,UAAU;KACI,EAAE,CAAC;QACjB,IAAI,CAAC,CAAC,MAAM,IAAI,WAAW,CAAC;YAAE,SAAS;QACvC,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAA4B,CAAC;QAChE,cAAc,CAAC,MAAM,CAAC,GAAG,KAAK,EAC5B,UAAyB,EACzB,OAAsB,EAAE,EACxB,EAAE;;YACF,MAAM,KAAK,GAAG,CAAC,MAAA,IAAI,CAAC,KAAK,mCAAI,CAAC,CAAC,GAAG,YAAY,CAAC,cAAc,CAAC;YAC9D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;YACnB,IAAI,CAAC,UAAU,GAAG,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,UAAmB,CAAC;YACjE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,cAA2C,CAAC;AACrD,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAEtD,YAAY;AACZ,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ReactNode } from "react";
2
+ export declare function render(children: ReactNode): Promise<import("../react/renderer.ts").Renderer>;
@@ -0,0 +1,12 @@
1
+ import { createRenderer } from "../react/renderer.js";
2
+ import { reconciler } from "../react/reconciler.js";
3
+ export async function render(children) {
4
+ const container = createRenderer();
5
+ const root = reconciler.createContainer(container, 0, null, false, null, "dressed", (error) => console.error(error), null);
6
+ if (root !== null) {
7
+ await new Promise((r) => reconciler.updateContainer(children, root, null, r));
8
+ await container.render();
9
+ }
10
+ return container;
11
+ }
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rendering/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,QAAmB;IAC9C,MAAM,SAAS,GAAG,cAAc,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,UAAU,CAAC,eAAe,CACrC,SAAS,EACT,CAAC,EACD,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,SAAS,EACT,CAAC,KAAY,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EACtC,IAAI,CACL,CAAC;IAEF,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAC5B,UAAU,CAAC,eAAe,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CACpD,CAAC;QACF,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC;IAC3B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { CommandInteraction as DressedCommandInteraction, MessageComponentInteraction as DressedMessageComponentInteraction, ModalSubmitInteraction as DressedModalSubmitInteraction } from "dressed";
2
+ import type { createInteraction, RawFile } from "dressed/server";
3
+ import { type APIInteractionResponseCallbackData, type APIModalInteractionResponseCallbackData } from "discord-api-types/v10";
4
+ import type { ReactNode } from "react";
5
+ type ReplyProps = [
6
+ components: ReactNode,
7
+ data?: Omit<APIInteractionResponseCallbackData, "content"> & {
8
+ /** Whether the message is ephemeral */
9
+ ephemeral?: boolean;
10
+ /** The files to send with the message */
11
+ files?: RawFile[];
12
+ /** Whether to return the source message with the response */
13
+ with_response?: boolean;
14
+ }
15
+ ];
16
+ type EditReplyProps = [
17
+ components: ReactNode,
18
+ data?: Omit<APIInteractionResponseCallbackData, "content"> & {
19
+ /** The files to send with the message */
20
+ files?: RawFile[];
21
+ }
22
+ ];
23
+ type FollowUpProps = [
24
+ components: ReactNode,
25
+ data?: Omit<APIInteractionResponseCallbackData, "content"> & {
26
+ /** The files to send with the message */
27
+ files?: RawFile[];
28
+ /** Whether the message is ephemeral */
29
+ ephemeral?: boolean;
30
+ }
31
+ ];
32
+ type ShowModalProps = [
33
+ components: ReactNode,
34
+ data: Omit<APIModalInteractionResponseCallbackData, "components">
35
+ ];
36
+ type ReactivatedInteraction<T extends NonNullable<ReturnType<typeof createInteraction>>> = OverrideMethodParams<T, {
37
+ reply: ReplyProps;
38
+ editReply: EditReplyProps;
39
+ update: EditReplyProps;
40
+ followUp: FollowUpProps;
41
+ showModal: ShowModalProps;
42
+ }>;
43
+ type OverrideMethodParams<T, Overrides extends Record<string, unknown[]>> = {
44
+ [K in keyof T]: K extends keyof Overrides ? T[K] extends (...args: any) => any ? (...args: Overrides[K]) => ReturnType<T[K]> : T[K] : T[K];
45
+ };
46
+ export type CommandInteraction = ReactivatedInteraction<DressedCommandInteraction>;
47
+ export type MessageComponentInteraction = ReactivatedInteraction<DressedMessageComponentInteraction>;
48
+ export type ModalSubmitInteraction = ReactivatedInteraction<DressedModalSubmitInteraction>;
49
+ export declare function patchInteraction<T extends NonNullable<ReturnType<typeof createInteraction>>>(interaction: T): ReactivatedInteraction<T>;
50
+ export {};
@@ -0,0 +1,28 @@
1
+ import { MessageFlags, } from "discord-api-types/v10";
2
+ import { render } from "./index.js";
3
+ export function patchInteraction(interaction) {
4
+ if (!interaction)
5
+ throw new Error("No interaction");
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ const newInteraction = interaction;
8
+ for (const method of [
9
+ "reply",
10
+ "editReply",
11
+ "update",
12
+ "followUp",
13
+ "showModal",
14
+ ]) {
15
+ if (!(method in interaction))
16
+ continue;
17
+ const original = interaction[method];
18
+ newInteraction[method] = async (components, data = {}) => {
19
+ var _a;
20
+ const flags = ((_a = data.flags) !== null && _a !== void 0 ? _a : 0) | MessageFlags.IsComponentsV2;
21
+ data.flags = flags;
22
+ data.components = (await render(components)).components;
23
+ return original(data);
24
+ };
25
+ }
26
+ return newInteraction;
27
+ }
28
+ //# sourceMappingURL=interaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction.js","sourceRoot":"","sources":["../../src/rendering/interaction.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,YAAY,GAGb,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AA+DpC,MAAM,UAAU,gBAAgB,CAE9B,WAAc;IACd,IAAI,CAAC,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACpD,8DAA8D;IAC9D,MAAM,cAAc,GAAG,WAAkB,CAAC;IAC1C,KAAK,MAAM,MAAM,IAAI;QACnB,OAAO;QACP,WAAW;QACX,QAAQ;QACR,UAAU;QACV,WAAW;KACG,EAAE,CAAC;QACjB,IAAI,CAAC,CAAC,MAAM,IAAI,WAAW,CAAC;YAAE,SAAS;QACvC,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAA4B,CAAC;QAChE,cAAc,CAAC,MAAM,CAAC,GAAG,KAAK,EAC5B,UAAyB,EACzB,OAAsB,EAAE,EACxB,EAAE;;YACF,MAAM,KAAK,GAAG,CAAC,MAAA,IAAI,CAAC,KAAK,mCAAI,CAAC,CAAC,GAAG,YAAY,CAAC,cAAc,CAAC;YAC9D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;YACnB,IAAI,CAAC,UAAU,GAAG,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,UAAmB,CAAC;YACjE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,cAAc,CAAC;AACxB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { RawFile } from "dressed/server";
2
+ import { type RESTPatchAPIChannelMessageJSONBody, type RESTPostAPIChannelMessageJSONBody, type Snowflake } from "discord-api-types/v10";
3
+ import type { ReactNode } from "react";
4
+ /**
5
+ * Renders the provided children and posts a message to a guild text or DM channel with the `IsComponentsV2` flag.
6
+ * @example createMessage(channelId, <Button label="Foo" />)
7
+ * @param channel The channel to post the message to
8
+ * @param components The contents of the message
9
+ * @param data The message data
10
+ */
11
+ export declare function createMessage(channel: Snowflake, components: ReactNode, data: Omit<RESTPostAPIChannelMessageJSONBody, "content"> & {
12
+ files?: RawFile[];
13
+ }): Promise<import("discord-api-types/v10").APIMessage>;
14
+ /**
15
+ * Renders the provided children and edits a previously sent message.
16
+ * @example editMessage(channelId, messageId, <Button label="Bar" />)
17
+ * @param channel The channel to edit the message in
18
+ * @param components The contents of the message
19
+ * @param data The new message data
20
+ */
21
+ export declare function editMessage(channel: Snowflake, message: Snowflake, components: ReactNode, data: Omit<RESTPatchAPIChannelMessageJSONBody, "content"> & {
22
+ files?: RawFile[];
23
+ }): Promise<import("discord-api-types/v10").APIMessage>;
@@ -0,0 +1,32 @@
1
+ import { createMessage as dressedCreateMessage, editMessage as dressedEditMessage, } from "dressed";
2
+ import { MessageFlags, } from "discord-api-types/v10";
3
+ import { render } from "./index.js";
4
+ /**
5
+ * Renders the provided children and posts a message to a guild text or DM channel with the `IsComponentsV2` flag.
6
+ * @example createMessage(channelId, <Button label="Foo" />)
7
+ * @param channel The channel to post the message to
8
+ * @param components The contents of the message
9
+ * @param data The message data
10
+ */
11
+ export async function createMessage(channel, components, data) {
12
+ var _a;
13
+ const flags = ((_a = data.flags) !== null && _a !== void 0 ? _a : 0) | MessageFlags.IsComponentsV2;
14
+ data.flags = flags;
15
+ data.components = (await render(components)).components;
16
+ return dressedCreateMessage(channel, data);
17
+ }
18
+ /**
19
+ * Renders the provided children and edits a previously sent message.
20
+ * @example editMessage(channelId, messageId, <Button label="Bar" />)
21
+ * @param channel The channel to edit the message in
22
+ * @param components The contents of the message
23
+ * @param data The new message data
24
+ */
25
+ export async function editMessage(channel, message, components, data) {
26
+ var _a;
27
+ const flags = ((_a = data.flags) !== null && _a !== void 0 ? _a : 0) | MessageFlags.IsComponentsV2;
28
+ data.flags = flags;
29
+ data.components = (await render(components)).components;
30
+ return dressedEditMessage(channel, message, data);
31
+ }
32
+ //# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.js","sourceRoot":"","sources":["../../src/rendering/message.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,IAAI,oBAAoB,EACrC,WAAW,IAAI,kBAAkB,GAClC,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,YAAY,GAIb,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAkB,EAClB,UAAqB,EACrB,IAEC;;IAED,MAAM,KAAK,GAAG,CAAC,MAAA,IAAI,CAAC,KAAK,mCAAI,CAAC,CAAC,GAAG,YAAY,CAAC,cAAc,CAAC;IAC9D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC,UAAU,GAAG,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,UAAmB,CAAC;IACjE,OAAO,oBAAoB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAAkB,EAClB,OAAkB,EAClB,UAAqB,EACrB,IAEC;;IAED,MAAM,KAAK,GAAG,CAAC,MAAA,IAAI,CAAC,KAAK,mCAAI,CAAC,CAAC,GAAG,YAAY,CAAC,cAAc,CAAC;IAC9D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC,UAAU,GAAG,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,UAAmB,CAAC;IACjE,OAAO,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AACpD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dressed/react",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Inbestigator/dressed.git",