@canva/cli 0.0.1-beta.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +131 -31
- package/cli.js +852 -427
- package/lib/cjs/index.cjs +11 -0
- package/lib/esm/index.mjs +11 -0
- package/package.json +19 -4
- package/templates/base/backend/routers/auth.ts +4 -4
- package/templates/base/backend/routers/oauth.ts +3 -3
- package/templates/base/eslint.config.mjs +2 -25
- package/templates/base/package.json +29 -26
- package/templates/base/scripts/ssl/ssl.ts +1 -1
- package/templates/base/scripts/start/app_runner.ts +42 -5
- package/templates/base/scripts/start/context.ts +12 -6
- package/templates/base/scripts/start/start.ts +12 -1
- package/templates/base/scripts/start/tests/start.tests.ts +61 -0
- package/templates/base/utils/backend/base_backend/create.ts +3 -3
- package/templates/base/utils/backend/bearer_middleware/bearer_middleware.ts +2 -2
- package/templates/base/utils/backend/jwt_middleware/jwt_middleware.ts +4 -4
- package/templates/base/utils/backend/jwt_middleware/tests/jwt_middleware.tests.ts +1 -1
- package/templates/base/utils/use_add_element.ts +1 -1
- package/templates/base/utils/use_feature_support.ts +1 -1
- package/templates/{dam/webpack.config.cjs → base/webpack.config.ts} +51 -67
- package/templates/common/.env.template +3 -3
- package/templates/common/README.md +16 -17
- package/templates/common/jest.config.mjs +29 -2
- package/templates/common/jest.setup.ts +20 -0
- package/templates/common/utils/backend/base_backend/create.ts +3 -3
- package/templates/common/utils/backend/jwt_middleware/jwt_middleware.ts +4 -4
- package/templates/common/utils/backend/jwt_middleware/tests/jwt_middleware.tests.ts +1 -1
- package/templates/common/utils/tests/table_wrapper.tests.ts +1 -1
- package/templates/common/utils/use_add_element.ts +1 -1
- package/templates/common/utils/use_feature_support.ts +1 -1
- package/templates/dam/backend/routers/dam.ts +24 -20
- package/templates/dam/backend/server.ts +1 -1
- package/templates/dam/canva-app.json +16 -0
- package/templates/dam/eslint.config.mjs +2 -28
- package/templates/dam/package.json +43 -40
- package/templates/dam/scripts/ssl/ssl.ts +1 -1
- package/templates/dam/scripts/start/app_runner.ts +42 -5
- package/templates/dam/scripts/start/context.ts +12 -6
- package/templates/dam/scripts/start/start.ts +12 -1
- package/templates/dam/scripts/start/tests/start.tests.ts +61 -0
- package/templates/dam/src/app.tsx +24 -3
- package/templates/dam/src/config.ts +212 -87
- package/templates/dam/src/index.tsx +1 -1
- package/templates/dam/utils/backend/base_backend/create.ts +3 -3
- package/templates/dam/utils/backend/jwt_middleware/jwt_middleware.ts +4 -4
- package/templates/dam/utils/backend/jwt_middleware/tests/jwt_middleware.tests.ts +1 -1
- package/templates/{base/webpack.config.cjs → dam/webpack.config.ts} +51 -67
- package/templates/data_connector/README.md +84 -0
- package/templates/data_connector/canva-app.json +21 -0
- package/templates/data_connector/declarations/declarations.d.ts +29 -0
- package/templates/data_connector/eslint.config.mjs +14 -0
- package/templates/data_connector/package.json +91 -0
- package/templates/data_connector/scripts/ssl/ssl.ts +131 -0
- package/templates/data_connector/scripts/start/app_runner.ts +201 -0
- package/templates/data_connector/scripts/start/context.ts +171 -0
- package/templates/data_connector/scripts/start/start.ts +46 -0
- package/templates/data_connector/scripts/start/tests/start.tests.ts +61 -0
- package/templates/data_connector/src/api/connect_client.ts +6 -0
- package/templates/data_connector/src/api/data_source.ts +96 -0
- package/templates/data_connector/src/api/data_sources/designs.tsx +296 -0
- package/templates/data_connector/src/api/data_sources/index.ts +4 -0
- package/templates/data_connector/src/api/data_sources/templates.tsx +329 -0
- package/templates/data_connector/src/api/fetch_data_table.ts +55 -0
- package/templates/data_connector/src/api/index.ts +4 -0
- package/templates/data_connector/src/api/oauth.ts +8 -0
- package/templates/data_connector/src/api/tests/data_source.test.tsx +99 -0
- package/templates/data_connector/src/app.tsx +20 -0
- package/templates/data_connector/src/components/app_error.tsx +15 -0
- package/templates/data_connector/src/components/footer.tsx +26 -0
- package/templates/data_connector/src/components/header.tsx +40 -0
- package/templates/data_connector/src/components/index.ts +3 -0
- package/templates/data_connector/src/components/inputs/messages.tsx +99 -0
- package/templates/data_connector/src/components/inputs/search_filter.tsx +108 -0
- package/templates/data_connector/src/components/inputs/select_field.tsx +26 -0
- package/templates/data_connector/src/context/app_context.tsx +124 -0
- package/templates/data_connector/src/context/index.ts +2 -0
- package/templates/data_connector/src/context/use_app_context.ts +17 -0
- package/templates/data_connector/src/entrypoint.tsx +70 -0
- package/templates/data_connector/src/home.tsx +21 -0
- package/templates/data_connector/src/index.tsx +68 -0
- package/templates/data_connector/src/pages/data_source_config.tsx +9 -0
- package/templates/data_connector/src/pages/error.tsx +37 -0
- package/templates/data_connector/src/pages/index.ts +4 -0
- package/templates/data_connector/src/pages/login.tsx +145 -0
- package/templates/data_connector/src/pages/select_source.tsx +24 -0
- package/templates/data_connector/src/routes/index.ts +2 -0
- package/templates/data_connector/src/routes/protected_route.tsx +25 -0
- package/templates/data_connector/src/routes/routes.tsx +46 -0
- package/templates/data_connector/src/utils/data_params.ts +17 -0
- package/templates/data_connector/src/utils/data_table.ts +115 -0
- package/templates/data_connector/src/utils/fetch_result.ts +36 -0
- package/templates/data_connector/src/utils/index.ts +2 -0
- package/templates/data_connector/src/utils/tests/data_table.test.ts +133 -0
- package/templates/data_connector/styles/components.css +38 -0
- package/templates/data_connector/tsconfig.json +54 -0
- package/templates/{gen_ai/webpack.config.cjs → data_connector/webpack.config.ts} +51 -67
- package/templates/gen_ai/backend/routers/image.ts +8 -8
- package/templates/gen_ai/backend/server.ts +1 -1
- package/templates/gen_ai/canva-app.json +20 -0
- package/templates/gen_ai/eslint.config.mjs +2 -25
- package/templates/gen_ai/package.json +47 -42
- package/templates/gen_ai/scripts/ssl/ssl.ts +1 -1
- package/templates/gen_ai/scripts/start/app_runner.ts +42 -5
- package/templates/gen_ai/scripts/start/context.ts +12 -6
- package/templates/gen_ai/scripts/start/start.ts +12 -1
- package/templates/gen_ai/scripts/start/tests/start.tests.ts +61 -0
- package/templates/gen_ai/src/app.tsx +16 -10
- package/templates/gen_ai/src/components/footer.tsx +4 -4
- package/templates/gen_ai/src/components/image_grid.tsx +1 -1
- package/templates/gen_ai/src/components/loading_results.tsx +8 -8
- package/templates/gen_ai/src/components/prompt_input.tsx +3 -3
- package/templates/gen_ai/src/components/remaining_credits.tsx +1 -1
- package/templates/gen_ai/src/components/report_box.tsx +1 -1
- package/templates/gen_ai/src/components/tests/remaining_credit.tests.tsx +43 -0
- package/templates/gen_ai/src/home.tsx +13 -0
- package/templates/gen_ai/src/index.tsx +2 -18
- package/templates/gen_ai/src/pages/error.tsx +2 -2
- package/templates/gen_ai/src/pages/results.tsx +1 -1
- package/templates/gen_ai/src/routes/routes.tsx +2 -2
- package/templates/gen_ai/utils/backend/base_backend/create.ts +3 -3
- package/templates/gen_ai/utils/backend/bearer_middleware/bearer_middleware.ts +2 -2
- package/templates/{hello_world/webpack.config.cjs → gen_ai/webpack.config.ts} +51 -67
- package/templates/hello_world/canva-app.json +16 -0
- package/templates/hello_world/eslint.config.mjs +2 -25
- package/templates/hello_world/package.json +42 -37
- package/templates/hello_world/scripts/copy_env.ts +10 -0
- package/templates/hello_world/scripts/ssl/ssl.ts +1 -1
- package/templates/hello_world/scripts/start/app_runner.ts +42 -5
- package/templates/hello_world/scripts/start/context.ts +12 -6
- package/templates/hello_world/scripts/start/start.ts +12 -1
- package/templates/hello_world/scripts/start/tests/start.tests.ts +61 -0
- package/templates/hello_world/src/app.tsx +21 -1
- package/templates/hello_world/src/index.tsx +1 -1
- package/templates/hello_world/src/tests/__snapshots__/app.tests.tsx.snap +45 -0
- package/templates/hello_world/src/tests/app.tests.tsx +86 -0
- package/templates/hello_world/utils/use_add_element.ts +1 -1
- package/templates/hello_world/utils/use_feature_support.ts +1 -1
- package/templates/hello_world/webpack.config.ts +254 -0
- package/templates/optional/.cursor/mcp.json +8 -0
- package/templates/optional/.vscode/mcp.json +9 -0
- package/templates/optional/AGENTS.md +76 -0
- package/templates/optional/CLAUDE.md +76 -0
- package/templates/common/conf/eslint-general.mjs +0 -303
- package/templates/common/conf/eslint-i18n.mjs +0 -38
- /package/templates/base/scripts/{copy-env.ts → copy_env.ts} +0 -0
- /package/templates/dam/scripts/{copy-env.ts → copy_env.ts} +0 -0
- /package/templates/{gen_ai/scripts/copy-env.ts → data_connector/scripts/copy_env.ts} +0 -0
- /package/templates/{hello_world/scripts/copy-env.ts → gen_ai/scripts/copy_env.ts} +0 -0
- /package/templates/{common → optional}/.vscode/extensions.json +0 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
import type { ChildProcess } from "child_process";
|
|
4
|
+
import { spawn } from "child_process";
|
|
5
|
+
import * as treeKill from "tree-kill";
|
|
6
|
+
|
|
7
|
+
describe("start script", () => {
|
|
8
|
+
let serverProcess: ChildProcess;
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
if (serverProcess?.pid && !serverProcess.exitCode) {
|
|
12
|
+
treeKill(serverProcess.pid);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should execute 'npm run start' and start a dev server", async () => {
|
|
17
|
+
const testServerPort = 8089;
|
|
18
|
+
serverProcess = await spawn(
|
|
19
|
+
`npm run start -- -p ${testServerPort} --no-preview`,
|
|
20
|
+
{
|
|
21
|
+
shell: true,
|
|
22
|
+
},
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
if (!serverProcess.pid) {
|
|
26
|
+
throw new Error("Unable to start server");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// wait for the server to start and collect output until it reports the running URL
|
|
30
|
+
let output = "";
|
|
31
|
+
await new Promise<void>((resolve, reject) => {
|
|
32
|
+
serverProcess.stdout?.on("data", (data) => {
|
|
33
|
+
output += data.toString();
|
|
34
|
+
if (output.includes("Development URL")) {
|
|
35
|
+
resolve();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
serverProcess.stderr?.on("data", (data) => {
|
|
40
|
+
console.error("Server process error: ", data.toString());
|
|
41
|
+
reject();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// timeout and fail test if the server hasn't correctly started in 10 seconds
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
if (serverProcess?.pid && !serverProcess.exitCode) {
|
|
47
|
+
treeKill(serverProcess.pid);
|
|
48
|
+
}
|
|
49
|
+
reject(new Error("Test timed out"));
|
|
50
|
+
}, 10000);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// check that the server is running and accessible
|
|
54
|
+
const expectedServerURL = `http://localhost:${testServerPort}`;
|
|
55
|
+
expect(output).toContain(expectedServerURL);
|
|
56
|
+
expect(serverProcess.exitCode).toBeNull();
|
|
57
|
+
|
|
58
|
+
// clean up
|
|
59
|
+
treeKill(serverProcess.pid);
|
|
60
|
+
}, 15000); // 15 seconds timeout to allow for the server to start
|
|
61
|
+
});
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
1
|
+
import { AppI18nProvider } from "@canva/app-i18n-kit";
|
|
2
|
+
import { AppUiProvider } from "@canva/app-ui-kit";
|
|
3
|
+
import { ErrorBoundary } from "react-error-boundary";
|
|
4
|
+
import { createHashRouter, RouterProvider } from "react-router-dom";
|
|
5
|
+
import { ContextProvider } from "./context";
|
|
6
|
+
import { ErrorPage } from "./pages";
|
|
7
|
+
import { routes } from "./routes";
|
|
5
8
|
|
|
6
9
|
export const App = () => (
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
<AppI18nProvider>
|
|
11
|
+
<AppUiProvider>
|
|
12
|
+
<ErrorBoundary fallback={<ErrorPage />}>
|
|
13
|
+
<ContextProvider>
|
|
14
|
+
<RouterProvider router={createHashRouter(routes)} />
|
|
15
|
+
</ContextProvider>
|
|
16
|
+
</ErrorBoundary>
|
|
17
|
+
</AppUiProvider>
|
|
18
|
+
</AppI18nProvider>
|
|
13
19
|
);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { Button, Rows } from "@canva/app-ui-kit";
|
|
2
|
+
import { useIntl } from "react-intl";
|
|
3
|
+
import { useLocation, useNavigate } from "react-router-dom";
|
|
4
|
+
import { purchaseCredits, queueImageGeneration } from "src/api";
|
|
4
5
|
import { RemainingCredits } from "src/components";
|
|
5
6
|
import { NUMBER_OF_IMAGES_TO_GENERATE } from "src/config";
|
|
6
7
|
import { useAppContext } from "src/context";
|
|
7
8
|
import { Paths } from "src/routes";
|
|
8
9
|
import { getObsceneWords } from "src/utils";
|
|
9
|
-
import { useIntl } from "react-intl";
|
|
10
10
|
import { FooterMessages as Messages } from "./footer.messages";
|
|
11
11
|
|
|
12
12
|
export const Footer = () => {
|
|
@@ -2,10 +2,10 @@ import { Grid, ImageCard, Rows, Text } from "@canva/app-ui-kit";
|
|
|
2
2
|
import type { QueuedImage } from "@canva/asset";
|
|
3
3
|
import { upload } from "@canva/asset";
|
|
4
4
|
import { addElementAtPoint, ui } from "@canva/design";
|
|
5
|
+
import { FormattedMessage, useIntl } from "react-intl";
|
|
5
6
|
import type { ImageType } from "src/api";
|
|
6
7
|
import { useAppContext } from "src/context";
|
|
7
8
|
import * as styles from "styles/utils.css";
|
|
8
|
-
import { FormattedMessage, useIntl } from "react-intl";
|
|
9
9
|
|
|
10
10
|
const THUMBNAIL_HEIGHT = 150;
|
|
11
11
|
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
import { useNavigate } from "react-router-dom";
|
|
3
1
|
import {
|
|
4
|
-
|
|
2
|
+
Box,
|
|
3
|
+
Button,
|
|
5
4
|
Grid,
|
|
6
5
|
Placeholder,
|
|
7
6
|
ProgressBar,
|
|
7
|
+
Rows,
|
|
8
8
|
Text,
|
|
9
|
-
Button,
|
|
10
|
-
Box,
|
|
11
9
|
} from "@canva/app-ui-kit";
|
|
12
|
-
import {
|
|
13
|
-
import { useAppContext } from "src/context";
|
|
14
|
-
import { cancelImageGenerationJob, getImageGenerationJobStatus } from "src/api";
|
|
10
|
+
import { useEffect, useState } from "react";
|
|
15
11
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
12
|
+
import { useNavigate } from "react-router-dom";
|
|
13
|
+
import { cancelImageGenerationJob, getImageGenerationJobStatus } from "src/api";
|
|
14
|
+
import { useAppContext } from "src/context";
|
|
15
|
+
import { Paths } from "src/routes";
|
|
16
16
|
|
|
17
17
|
const INTERVAL_DURATION_IN_MS = 100;
|
|
18
18
|
const TOTAL_PROGRESS_PERCENTAGE = 100;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
2
|
-
import { useLocation } from "react-router-dom";
|
|
3
1
|
import {
|
|
4
2
|
Box,
|
|
5
3
|
Button,
|
|
@@ -7,10 +5,12 @@ import {
|
|
|
7
5
|
LightBulbIcon,
|
|
8
6
|
MultilineInput,
|
|
9
7
|
} from "@canva/app-ui-kit";
|
|
8
|
+
import { useState } from "react";
|
|
9
|
+
import { useIntl } from "react-intl";
|
|
10
|
+
import { useLocation } from "react-router-dom";
|
|
10
11
|
import { useAppContext } from "src/context";
|
|
11
12
|
import { Paths } from "src/routes";
|
|
12
13
|
import { PromptInputMessages as Messages } from "./prompt_input.messages";
|
|
13
|
-
import { useIntl } from "react-intl";
|
|
14
14
|
|
|
15
15
|
// @TODO: Adjust according to your specific requirements.
|
|
16
16
|
const MAX_INPUT_LENGTH = 280;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Link, Rows, Text, TextPlaceholder } from "@canva/app-ui-kit";
|
|
2
2
|
import { requestOpenExternalUrl } from "@canva/platform";
|
|
3
|
-
import { useAppContext } from "src/context";
|
|
4
3
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
4
|
+
import { useAppContext } from "src/context";
|
|
5
5
|
|
|
6
6
|
// @TODO: Replace this URL with your custom upselling link.
|
|
7
7
|
const PURCHASE_URL = "https://example.com";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Box,
|
|
1
|
+
import { Box, Column, Columns, FlagIcon, Link, Text } from "@canva/app-ui-kit";
|
|
2
2
|
import { requestOpenExternalUrl } from "@canva/platform";
|
|
3
3
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
4
4
|
import { APP_NAME } from "src/config";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/* eslint-disable formatjs/no-literal-string-in-jsx */
|
|
2
|
+
import { TestAppI18nProvider } from "@canva/app-i18n-kit";
|
|
3
|
+
import { TestAppUiProvider } from "@canva/app-ui-kit";
|
|
4
|
+
import { requestOpenExternalUrl } from "@canva/platform";
|
|
5
|
+
import type { RenderResult } from "@testing-library/react";
|
|
6
|
+
import { fireEvent, render } from "@testing-library/react";
|
|
7
|
+
import React from "react";
|
|
8
|
+
import { RemainingCredits } from "../remaining_credits";
|
|
9
|
+
|
|
10
|
+
function renderInTestProvider(node: React.ReactNode): RenderResult {
|
|
11
|
+
return render(
|
|
12
|
+
// In a test environment, you should wrap your apps in `TestAppI18nProvider` and `TestAppUiProvider`, rather than `AppI18nProvider` and `AppUiProvider`
|
|
13
|
+
<TestAppI18nProvider>
|
|
14
|
+
<TestAppUiProvider>{node}</TestAppUiProvider>,
|
|
15
|
+
</TestAppI18nProvider>,
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// This test demonstrates how to test code that uses functions from the Canva Apps SDK
|
|
20
|
+
// For more information on testing with the Canva Apps SDK, see https://www.canva.dev/docs/apps/testing/
|
|
21
|
+
describe("Remaining Credit Tests", () => {
|
|
22
|
+
const mockRequestOpenExternalUrl = jest.mocked(requestOpenExternalUrl);
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
jest.resetAllMocks();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should call requestOpenExternalUrl when the link is clicked", () => {
|
|
29
|
+
// assert that the mock is in the expected clean state
|
|
30
|
+
expect(mockRequestOpenExternalUrl).not.toHaveBeenCalled();
|
|
31
|
+
|
|
32
|
+
const result = renderInTestProvider(<RemainingCredits />);
|
|
33
|
+
|
|
34
|
+
// get a reference to the link to purchase more credits
|
|
35
|
+
const purchaseMoreLink = result.getByRole("button");
|
|
36
|
+
|
|
37
|
+
// programmatically simulate clicking the button
|
|
38
|
+
fireEvent.click(purchaseMoreLink);
|
|
39
|
+
|
|
40
|
+
// we expect that requestOpenExternalUrl has been called
|
|
41
|
+
expect(mockRequestOpenExternalUrl).toHaveBeenCalled();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Rows } from "@canva/app-ui-kit";
|
|
2
|
+
import { Outlet } from "react-router-dom";
|
|
3
|
+
import * as styles from "styles/components.css";
|
|
4
|
+
import { Footer } from "./components";
|
|
5
|
+
|
|
6
|
+
export const Home = () => (
|
|
7
|
+
<div className={styles.scrollContainer}>
|
|
8
|
+
<Rows spacing="3u">
|
|
9
|
+
<Outlet />
|
|
10
|
+
<Footer />
|
|
11
|
+
</Rows>
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
@@ -1,27 +1,11 @@
|
|
|
1
1
|
import { createRoot } from "react-dom/client";
|
|
2
|
-
import { createHashRouter, RouterProvider } from "react-router-dom";
|
|
3
|
-
import { ErrorBoundary } from "react-error-boundary";
|
|
4
|
-
import { AppUiProvider } from "@canva/app-ui-kit";
|
|
5
|
-
import { routes } from "./routes";
|
|
6
|
-
import { ErrorPage } from "./pages";
|
|
7
|
-
import { ContextProvider } from "./context";
|
|
8
2
|
import "@canva/app-ui-kit/styles.css";
|
|
9
|
-
import {
|
|
3
|
+
import { App } from "./app";
|
|
10
4
|
|
|
11
5
|
const root = createRoot(document.getElementById("root") as Element);
|
|
12
6
|
|
|
13
7
|
function render() {
|
|
14
|
-
root.render(
|
|
15
|
-
<AppI18nProvider>
|
|
16
|
-
<AppUiProvider>
|
|
17
|
-
<ErrorBoundary fallback={<ErrorPage />}>
|
|
18
|
-
<ContextProvider>
|
|
19
|
-
<RouterProvider router={createHashRouter(routes)} />
|
|
20
|
-
</ContextProvider>
|
|
21
|
-
</ErrorBoundary>
|
|
22
|
-
</AppUiProvider>
|
|
23
|
-
</AppI18nProvider>,
|
|
24
|
-
);
|
|
8
|
+
root.render(<App />);
|
|
25
9
|
}
|
|
26
10
|
|
|
27
11
|
render();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { useNavigate } from "react-router-dom";
|
|
2
1
|
import { Button, Rows, Text } from "@canva/app-ui-kit";
|
|
2
|
+
import { FormattedMessage, useIntl } from "react-intl";
|
|
3
|
+
import { useNavigate } from "react-router-dom";
|
|
3
4
|
import { useAppContext } from "src/context";
|
|
4
5
|
import { Paths } from "src/routes";
|
|
5
6
|
import * as styles from "styles/components.css";
|
|
6
|
-
import { FormattedMessage, useIntl } from "react-intl";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Bare bones Error Page, please add relevant information and behavior that your app requires.
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
PromptInput,
|
|
7
7
|
ReportBox,
|
|
8
8
|
} from "src/components";
|
|
9
|
-
import { useAppContext } from "src/context";
|
|
10
9
|
import { EXPECTED_LOADING_TIME_IN_SECONDS } from "src/config";
|
|
10
|
+
import { useAppContext } from "src/context";
|
|
11
11
|
|
|
12
12
|
export const ResultsPage = () => {
|
|
13
13
|
const { isLoadingImages } = useAppContext();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Home } from "src/home";
|
|
2
2
|
import { ErrorPage, GeneratePage, ResultsPage } from "src/pages";
|
|
3
3
|
|
|
4
4
|
export enum Paths {
|
|
@@ -9,7 +9,7 @@ export enum Paths {
|
|
|
9
9
|
export const routes = [
|
|
10
10
|
{
|
|
11
11
|
path: Paths.HOME,
|
|
12
|
-
element: <
|
|
12
|
+
element: <Home />,
|
|
13
13
|
errorElement: <ErrorPage />,
|
|
14
14
|
children: [
|
|
15
15
|
{
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
+
import debug from "debug";
|
|
2
3
|
import * as express from "express";
|
|
4
|
+
import type { NextFunction, Request, Response } from "express";
|
|
5
|
+
import * as fs from "fs";
|
|
3
6
|
import * as http from "http";
|
|
4
7
|
import * as https from "https";
|
|
5
|
-
import * as fs from "fs";
|
|
6
|
-
import type { Request, Response, NextFunction } from "express";
|
|
7
|
-
import debug from "debug";
|
|
8
8
|
|
|
9
9
|
const serverDebug = debug("server");
|
|
10
10
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import * as debug from "debug";
|
|
3
|
-
import type { Request, Response
|
|
3
|
+
import type { NextFunction, Request, Response } from "express";
|
|
4
4
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
5
5
|
import Express from "express-serve-static-core";
|
|
6
6
|
|
|
@@ -45,7 +45,7 @@ export function createBearerMiddleware(
|
|
|
45
45
|
throw new AuthorizationError("Token is invalid");
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
req
|
|
48
|
+
req["user_id"] = user;
|
|
49
49
|
|
|
50
50
|
next();
|
|
51
51
|
} catch (e) {
|
|
@@ -1,30 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import type { Configuration } from "webpack";
|
|
2
|
+
import { DefinePlugin, optimize } from "webpack";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as TerserPlugin from "terser-webpack-plugin";
|
|
5
|
+
import { transform } from "@formatjs/ts-transformer";
|
|
6
|
+
import * as chalk from "chalk";
|
|
7
|
+
import { config } from "dotenv";
|
|
8
|
+
import { Configuration as DevServerConfiguration } from "webpack-dev-server";
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* @returns {Object}
|
|
22
|
-
*/
|
|
23
|
-
function buildConfig({
|
|
10
|
+
config();
|
|
11
|
+
|
|
12
|
+
type DevConfig = {
|
|
13
|
+
port: number;
|
|
14
|
+
enableHmr: boolean;
|
|
15
|
+
enableHttps: boolean;
|
|
16
|
+
appOrigin?: string;
|
|
17
|
+
appId?: string; // Deprecated in favour of appOrigin
|
|
18
|
+
certFile?: string;
|
|
19
|
+
keyFile?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function buildConfig({
|
|
24
23
|
devConfig,
|
|
25
24
|
appEntry = path.join(process.cwd(), "src", "index.tsx"),
|
|
26
25
|
backendHost = process.env.CANVA_BACKEND_HOST,
|
|
27
|
-
|
|
26
|
+
// For IN_HARNESS, refer to the following docs for more information: https://www.canva.dev/docs/apps/test-harness/
|
|
27
|
+
inHarness = process.env.IN_HARNESS?.toLowerCase() === "true",
|
|
28
|
+
}: {
|
|
29
|
+
devConfig?: DevConfig;
|
|
30
|
+
appEntry?: string;
|
|
31
|
+
backendHost?: string;
|
|
32
|
+
inHarness?: boolean;
|
|
33
|
+
} = {}): Configuration & DevServerConfiguration {
|
|
28
34
|
const mode = devConfig ? "development" : "production";
|
|
29
35
|
|
|
30
36
|
if (!backendHost) {
|
|
@@ -45,9 +51,14 @@ function buildConfig({
|
|
|
45
51
|
return {
|
|
46
52
|
mode,
|
|
47
53
|
context: path.resolve(process.cwd(), "./"),
|
|
48
|
-
entry:
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
entry: inHarness
|
|
55
|
+
? {
|
|
56
|
+
harness: path.join(process.cwd(), "harness", "harness.tsx"),
|
|
57
|
+
init: path.join(process.cwd(), "harness", "init.ts"),
|
|
58
|
+
}
|
|
59
|
+
: {
|
|
60
|
+
app: appEntry,
|
|
61
|
+
},
|
|
51
62
|
target: "web",
|
|
52
63
|
resolve: {
|
|
53
64
|
alias: {
|
|
@@ -59,7 +70,7 @@ function buildConfig({
|
|
|
59
70
|
extensions: [".ts", ".tsx", ".js", ".css", ".svg", ".woff", ".woff2"],
|
|
60
71
|
},
|
|
61
72
|
infrastructureLogging: {
|
|
62
|
-
level: "none",
|
|
73
|
+
level: inHarness ? "info" : "none",
|
|
63
74
|
},
|
|
64
75
|
module: {
|
|
65
76
|
rules: [
|
|
@@ -171,34 +182,26 @@ function buildConfig({
|
|
|
171
182
|
new DefinePlugin({
|
|
172
183
|
BACKEND_HOST: JSON.stringify(backendHost),
|
|
173
184
|
}),
|
|
174
|
-
// Apps can only submit a single JS file via the
|
|
185
|
+
// Apps can only submit a single JS file via the Developer Portal
|
|
175
186
|
new optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
|
|
176
|
-
],
|
|
187
|
+
].filter(Boolean),
|
|
177
188
|
...buildDevConfig(devConfig),
|
|
178
189
|
};
|
|
179
190
|
}
|
|
180
191
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
* @param {boolean} [options.enableHmr]
|
|
186
|
-
* @param {boolean} [options.enableHttps]
|
|
187
|
-
* @param {string} [options.appOrigin]
|
|
188
|
-
* @param {string} [options.appId] - Deprecated in favour of appOrigin
|
|
189
|
-
* @param {string} [options.certFile]
|
|
190
|
-
* @param {string} [options.keyFile]
|
|
191
|
-
* @returns {Object|null}
|
|
192
|
-
*/
|
|
193
|
-
function buildDevConfig(options) {
|
|
192
|
+
function buildDevConfig(options?: DevConfig): {
|
|
193
|
+
devtool?: string;
|
|
194
|
+
devServer?: DevServerConfiguration;
|
|
195
|
+
} {
|
|
194
196
|
if (!options) {
|
|
195
|
-
return
|
|
197
|
+
return {};
|
|
196
198
|
}
|
|
197
199
|
|
|
198
200
|
const { port, enableHmr, appOrigin, appId, enableHttps, certFile, keyFile } =
|
|
199
201
|
options;
|
|
202
|
+
const host = "localhost";
|
|
200
203
|
|
|
201
|
-
let devServer = {
|
|
204
|
+
let devServer: DevServerConfiguration = {
|
|
202
205
|
server: enableHttps
|
|
203
206
|
? {
|
|
204
207
|
type: "https",
|
|
@@ -208,7 +211,8 @@ function buildDevConfig(options) {
|
|
|
208
211
|
},
|
|
209
212
|
}
|
|
210
213
|
: "http",
|
|
211
|
-
host
|
|
214
|
+
host,
|
|
215
|
+
allowedHosts: [host],
|
|
212
216
|
historyApiFallback: {
|
|
213
217
|
rewrites: [{ from: /^\/$/, to: "/app.js" }],
|
|
214
218
|
},
|
|
@@ -225,31 +229,13 @@ function buildDevConfig(options) {
|
|
|
225
229
|
if (enableHmr && appOrigin) {
|
|
226
230
|
devServer = {
|
|
227
231
|
...devServer,
|
|
228
|
-
allowedHosts: new URL(appOrigin).hostname,
|
|
232
|
+
allowedHosts: [host, new URL(appOrigin).hostname],
|
|
229
233
|
headers: {
|
|
230
234
|
"Access-Control-Allow-Origin": appOrigin,
|
|
231
235
|
"Access-Control-Allow-Credentials": "true",
|
|
232
236
|
"Access-Control-Allow-Private-Network": "true",
|
|
233
237
|
},
|
|
234
238
|
};
|
|
235
|
-
} else if (enableHmr && appId) {
|
|
236
|
-
// Deprecated - App ID should not be used to configure HMR in the future and can be safely removed
|
|
237
|
-
// after a few months.
|
|
238
|
-
|
|
239
|
-
console.warn(
|
|
240
|
-
"Enabling Hot Module Replacement (HMR) with an App ID is deprecated, please see the README.md on how to update.",
|
|
241
|
-
);
|
|
242
|
-
|
|
243
|
-
const appDomain = `app-${appId.toLowerCase().trim()}.canva-apps.com`;
|
|
244
|
-
devServer = {
|
|
245
|
-
...devServer,
|
|
246
|
-
allowedHosts: appDomain,
|
|
247
|
-
headers: {
|
|
248
|
-
"Access-Control-Allow-Origin": `https://${appDomain}`,
|
|
249
|
-
"Access-Control-Allow-Credentials": "true",
|
|
250
|
-
"Access-Control-Allow-Private-Network": "true",
|
|
251
|
-
},
|
|
252
|
-
};
|
|
253
239
|
} else {
|
|
254
240
|
if (enableHmr && !appOrigin) {
|
|
255
241
|
console.warn(
|
|
@@ -265,6 +251,4 @@ function buildDevConfig(options) {
|
|
|
265
251
|
};
|
|
266
252
|
}
|
|
267
253
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
module.exports.buildConfig = buildConfig;
|
|
254
|
+
export default buildConfig;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://www.canva.dev/schemas/app/v1/manifest-schema.json",
|
|
3
|
+
"manifest_schema_version": 1,
|
|
4
|
+
"runtime": {
|
|
5
|
+
"permissions": [
|
|
6
|
+
{
|
|
7
|
+
"name": "canva:design:content:read",
|
|
8
|
+
"type": "mandatory"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "canva:design:content:write",
|
|
12
|
+
"type": "mandatory"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
-
import js from "@eslint/js";
|
|
4
|
-
import { FlatCompat } from "@eslint/eslintrc";
|
|
5
|
-
import general from "./conf/eslint-general.mjs";
|
|
6
|
-
import i18n from "./conf/eslint-i18n.mjs";
|
|
7
|
-
|
|
8
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = path.dirname(__filename);
|
|
10
|
-
const compat = new FlatCompat({
|
|
11
|
-
baseDirectory: __dirname,
|
|
12
|
-
recommendedConfig: js.configs.recommended,
|
|
13
|
-
allConfig: js.configs.all,
|
|
14
|
-
});
|
|
1
|
+
import canvaPlugin from "@canva/app-eslint-plugin";
|
|
15
2
|
|
|
16
3
|
export default [
|
|
17
4
|
{
|
|
@@ -23,15 +10,5 @@ export default [
|
|
|
23
10
|
"**/*.config.*",
|
|
24
11
|
],
|
|
25
12
|
},
|
|
26
|
-
...
|
|
27
|
-
"eslint:recommended",
|
|
28
|
-
"plugin:@typescript-eslint/recommended",
|
|
29
|
-
"plugin:@typescript-eslint/eslint-recommended",
|
|
30
|
-
"plugin:@typescript-eslint/strict",
|
|
31
|
-
"plugin:@typescript-eslint/stylistic",
|
|
32
|
-
"plugin:react/recommended",
|
|
33
|
-
"plugin:jest/recommended",
|
|
34
|
-
),
|
|
35
|
-
...general,
|
|
36
|
-
...i18n,
|
|
13
|
+
...canvaPlugin.configs.apps,
|
|
37
14
|
];
|