@wix/astro 1.0.25 → 1.0.27

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/package.json CHANGED
@@ -1,11 +1,15 @@
1
1
  {
2
2
  "name": "@wix/astro",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "devDependencies": {
5
5
  "@wix/dashboard": "^1.3.35",
6
6
  "@wix/essentials": "^0.1.23",
7
+ "@wix/headless-node": "^1.4.0",
8
+ "@wix/headless-site": "^1.0.0",
9
+ "@wix/headless-site-assets": "^1.0.2",
7
10
  "@wix/sdk": "^1.15.23",
8
11
  "@wix/sdk-context": "^0.0.1",
12
+ "@wix/sdk-types": "^1.13.32",
9
13
  "astro": "^5.10.1",
10
14
  "chalk": "^5.4.1",
11
15
  "chokidar": "^3.6.0",
@@ -45,5 +49,5 @@
45
49
  "artifactId": "wix-astro"
46
50
  }
47
51
  },
48
- "falconPackageHash": "3da19a908e980407fdedf672c3eef63699108f51ec265ed13f707d46"
52
+ "falconPackageHash": "d63557661fd785b25ed8a39da82d8812517f4690bfd1c928ef0454ae"
49
53
  }
@@ -1,7 +1,7 @@
1
- import type { WixClient } from '@wix/sdk';
2
- import { createClient, TokenRole } from '@wix/sdk';
1
+ import type { Tokens, WixClient } from '@wix/sdk';
2
+ import { headlessSite } from '@wix/headless-site';
3
+ import { createClient } from '@wix/sdk';
3
4
  import { SiteSessionAuth } from '@wix/sdk/auth/site-session';
4
- import * as z from 'zod/v4';
5
5
 
6
6
  export function getSessionClient(options: { clientId: string }): WixClient {
7
7
  return createClient({
@@ -9,19 +9,10 @@ export function getSessionClient(options: { clientId: string }): WixClient {
9
9
  tokens: getCookieAsJson('wixSession')?.tokens,
10
10
  ...options,
11
11
  }),
12
+ host: headlessSite.host(),
12
13
  });
13
14
  }
14
15
 
15
- const cookieSchema = z.object({
16
- tokens: z.object({
17
- accessToken: z.object({ expiresAt: z.number(), value: z.string() }),
18
- refreshToken: z.object({
19
- role: z.enum([TokenRole.MEMBER, TokenRole.NONE, TokenRole.VISITOR]),
20
- value: z.string(),
21
- }),
22
- }),
23
- });
24
-
25
16
  function getCookieAsJson(name: string) {
26
17
  const cookies = document.cookie.split('; ');
27
18
  const cookie = cookies.find((row) => row.startsWith(`${name}=`));
@@ -32,9 +23,37 @@ function getCookieAsJson(name: string) {
32
23
 
33
24
  try {
34
25
  const jsonString = decodeURIComponent(cookie.split('=')[1] ?? '');
35
- return cookieSchema.parse(JSON.parse(jsonString));
26
+ const cookieValue = JSON.parse(jsonString) as unknown;
27
+
28
+ if (isCookieValue(cookieValue)) {
29
+ return cookieValue;
30
+ }
31
+
32
+ throw new Error('Invalid cookie value');
36
33
  } catch (error) {
37
34
  console.error('Error parsing cookie JSON:', error);
38
35
  return null;
39
36
  }
40
37
  }
38
+
39
+ function isCookieValue(value: unknown): value is { tokens: Tokens } {
40
+ if (value == null || typeof value !== 'object') {
41
+ return false;
42
+ }
43
+
44
+ if (!('tokens' in value)) {
45
+ return false;
46
+ }
47
+
48
+ const tokens = value.tokens;
49
+
50
+ if (tokens == null || typeof tokens !== 'object') {
51
+ return false;
52
+ }
53
+
54
+ if (!('accessToken' in tokens) || !('refreshToken' in tokens)) {
55
+ return false;
56
+ }
57
+
58
+ return true;
59
+ }
@@ -5,6 +5,7 @@ import {
5
5
  WIX_CLIENT_PUBLIC_KEY,
6
6
  WIX_CLIENT_SECRET,
7
7
  } from 'astro:env/server';
8
+ import { createHostProxy } from './hostProxy.js';
8
9
 
9
10
  const elevatedContextClient = createClient({
10
11
  auth: AppStrategy({
@@ -13,6 +14,7 @@ const elevatedContextClient = createClient({
13
14
  instanceId: WIX_CLIENT_INSTANCE_ID,
14
15
  publicKey: WIX_CLIENT_PUBLIC_KEY,
15
16
  }),
17
+ host: createHostProxy(),
16
18
  });
17
19
 
18
20
  elevatedContextClient.enableContext('global', { elevated: true });
@@ -0,0 +1,38 @@
1
+ import type { Host } from '@wix/sdk-types';
2
+ import { headlessNode } from '@wix/headless-node';
3
+ import { authAsyncLocalStorage } from '../utils/authAsyncLocalStorage.js';
4
+
5
+ const createHostWithCurrentRequest = () => {
6
+ const store = authAsyncLocalStorage.getStore();
7
+
8
+ return headlessNode.host({ req: store?.request });
9
+ };
10
+
11
+ export const createHostProxy = (): Host => {
12
+ return new Proxy<Host>(
13
+ {},
14
+ {
15
+ get(target, prop: keyof Host) {
16
+ // host might be created before async local storage was set
17
+ const host = createHostWithCurrentRequest();
18
+ const value = host[prop];
19
+
20
+ if (typeof value !== 'function') {
21
+ return value;
22
+ }
23
+
24
+ // for functions, create the host again when the function runs,
25
+ // so that the middleware has a chance to set the async local storage
26
+ // before we access the current request
27
+ return function (...args: unknown[]) {
28
+ const anotherHost = createHostWithCurrentRequest();
29
+
30
+ return (anotherHost[prop] as (...args: unknown[]) => unknown).apply(
31
+ anotherHost,
32
+ args
33
+ );
34
+ };
35
+ },
36
+ }
37
+ );
38
+ };
@@ -2,6 +2,7 @@ import type { IOAuthStrategy } from '@wix/sdk';
2
2
  import { createClient, OAuthStrategy } from '@wix/sdk';
3
3
  import { WIX_CLIENT_ID } from 'astro:env/client';
4
4
  import { authAsyncLocalStorage } from '../utils/authAsyncLocalStorage.js';
5
+ import { createHostProxy } from './hostProxy.js';
5
6
 
6
7
  const authProxy = new Proxy(
7
8
  {},
@@ -35,6 +36,7 @@ const authProxy = new Proxy(
35
36
 
36
37
  const contextClient = createClient({
37
38
  auth: authProxy,
39
+ host: createHostProxy(),
38
40
  });
39
41
 
40
42
  contextClient.enableContext('global');
package/src/index.ts CHANGED
@@ -31,11 +31,12 @@ const createIntegration = (
31
31
  return {
32
32
  hooks: {
33
33
  async 'astro:build:done'({ logger }) {
34
- const model = await createProjectModel(logger);
34
+ const rootDir = fileURLToPath(_config.root);
35
+
36
+ const model = await createProjectModel({ logger, rootDir });
35
37
  const appManifest = generateAppManifest(model);
36
38
 
37
39
  const outDir = fileURLToPath(_config.outDir);
38
- const rootDir = fileURLToPath(_config.root);
39
40
 
40
41
  const appManifestPath = join(outDir, '_wix/app-manifest.json');
41
42
 
@@ -67,7 +68,7 @@ const createIntegration = (
67
68
  const rootDir = fileURLToPath(config.root);
68
69
  const extensionsDir = join(codegenDir, 'extensions');
69
70
 
70
- const model = await createProjectModel(logger);
71
+ const model = await createProjectModel({ logger, rootDir });
71
72
 
72
73
  // support client-side context calls
73
74
  injectScript(
@@ -219,7 +220,7 @@ const createIntegration = (
219
220
  useFsEvents: false,
220
221
  })
221
222
  .on('all', async () => {
222
- const model = await createProjectModel(logger);
223
+ const model = await createProjectModel({ logger, rootDir });
223
224
 
224
225
  await removeUnusedCodegenFiles({ extensionsDir, model });
225
226
 
@@ -233,9 +234,11 @@ const createIntegration = (
233
234
  }
234
235
  },
235
236
  'astro:server:setup': ({ logger, server }) => {
237
+ const rootDir = fileURLToPath(_config.root);
238
+
236
239
  server.middlewares.use(async (req, res, next) => {
237
240
  if (req.url === '/_wix/app-manifest.json') {
238
- const model = await createProjectModel(logger);
241
+ const model = await createProjectModel({ logger, rootDir });
239
242
  const appManifest = generateAppManifest(model);
240
243
  res.setHeader('Content-Type', 'application/json');
241
244
  res.end(JSON.stringify(appManifest));
@@ -9,6 +9,7 @@ export const onRequest: MiddlewareHandler = async (context, next) => {
9
9
  const usedTokens = existingTokens ?? (await generateVisitorTokens());
10
10
 
11
11
  const store = {
12
+ request: context.request,
12
13
  sessionTokens: usedTokens,
13
14
  };
14
15
 
@@ -1,15 +1,10 @@
1
1
  import type { MiddlewareHandler } from 'astro';
2
- import { httpClient } from '@wix/essentials';
2
+ import { scripts } from '@wix/headless-site-assets';
3
3
  import {
4
4
  injectAfterTransformStream,
5
5
  injectBeforeTransformStream,
6
6
  } from '../utils/transformStreamUtils.js';
7
7
 
8
- interface SiteScript {
9
- html: string;
10
- position: 'BODY_END' | 'BODY_START' | 'HEAD';
11
- }
12
-
13
8
  const bodyEndTransformStream = (htmlToInject: string) =>
14
9
  injectBeforeTransformStream('</body>', htmlToInject);
15
10
 
@@ -19,13 +14,6 @@ const headTransformStream = (htmlToInject: string) =>
19
14
  const bodyStartTransformStream = (htmlToInject: string) =>
20
15
  injectAfterTransformStream(/<body(?![^>]*\/>)[^>]*>/, htmlToInject);
21
16
 
22
- async function fetchScripts() {
23
- return httpClient
24
- .fetchWithAuth('https://edge.wixapis.com/assets/scripts/v1/site-scripts')
25
- .then(async (res) => res.json() as Promise<{ siteScripts: SiteScript[] }>)
26
- .then((data) => data.siteScripts);
27
- }
28
-
29
17
  export const onRequest: MiddlewareHandler = async (context, next) => {
30
18
  const response = await next();
31
19
  const contentType = response.headers.get('Content-Type');
@@ -38,19 +26,23 @@ export const onRequest: MiddlewareHandler = async (context, next) => {
38
26
  return response;
39
27
  }
40
28
 
41
- const scripts = await fetchScripts();
29
+ const { siteScripts } = await scripts.listSiteScripts();
30
+
31
+ if (siteScripts == null) {
32
+ throw new Error('Could not fetch site scripts');
33
+ }
42
34
 
43
- const headInjection = scripts
35
+ const headInjection = siteScripts
44
36
  .filter((x) => x.position === 'HEAD')
45
37
  .map((x) => x.html)
46
38
  .join('\n');
47
39
 
48
- const bodyStartInjection = scripts
40
+ const bodyStartInjection = siteScripts
49
41
  .filter((x) => x.position === 'BODY_START')
50
42
  .map((x) => x.html)
51
43
  .join('\n');
52
44
 
53
- const bodyEndInjection = scripts
45
+ const bodyEndInjection = siteScripts
54
46
  .filter((x) => x.position === 'BODY_END')
55
47
  .map((x) => x.html)
56
48
  .join('\n');
@@ -2,5 +2,6 @@ import { AsyncLocalStorage } from 'node:async_hooks';
2
2
  import type { Tokens } from '@wix/sdk';
3
3
 
4
4
  export const authAsyncLocalStorage = new AsyncLocalStorage<{
5
+ request: Request;
5
6
  sessionTokens: Tokens;
6
7
  }>();
@@ -14,19 +14,17 @@ export async function buildBackofficeComponent({
14
14
  component,
15
15
  entryFileName,
16
16
  injectRoute,
17
- rootDir,
18
17
  }: {
19
18
  codegenDir: string;
20
19
  component: BackofficeExtensionWidget | BackofficeModal | BackofficePage;
21
20
  entryFileName: string;
22
21
  injectRoute: (injectRoute: InjectedRoute) => void;
23
- rootDir: string;
24
22
  }): Promise<void> {
25
23
  const directory = join(codegenDir, component.manifest.compId);
26
24
 
27
25
  await outputDir(directory);
28
26
 
29
- const entryFilePath = join(rootDir, component.directory, entryFileName);
27
+ const entryFilePath = join(component.directory, entryFileName);
30
28
 
31
29
  const entrypoint = join(directory, `entry.astro`);
32
30
  const HocEntrypoint = join(directory, `wrapper.tsx`);
@@ -16,8 +16,6 @@ export async function buildComponents({
16
16
  isDev: boolean;
17
17
  model: Model;
18
18
  }): Promise<void> {
19
- const { rootDir } = model;
20
-
21
19
  // during dev, a single dynamic route is injected so adding or removing
22
20
  // components doesn't require re-running the dev command
23
21
  const injectRoute = isDev ? () => null : originalInjectRoute;
@@ -46,7 +44,6 @@ export async function buildComponents({
46
44
  component,
47
45
  entryFileName: 'widget.tsx',
48
46
  injectRoute,
49
- rootDir,
50
47
  });
51
48
 
52
49
  break;
@@ -61,7 +58,6 @@ export async function buildComponents({
61
58
  component,
62
59
  entryFileName: 'modal.tsx',
63
60
  injectRoute,
64
- rootDir,
65
61
  });
66
62
 
67
63
  break;
@@ -76,7 +72,6 @@ export async function buildComponents({
76
72
  component,
77
73
  entryFileName: 'page.tsx',
78
74
  injectRoute,
79
- rootDir,
80
75
  });
81
76
 
82
77
  break;
@@ -92,7 +87,6 @@ export async function buildComponents({
92
87
  codegenDir: servicePluginsCodegenDir,
93
88
  component,
94
89
  injectRoute,
95
- rootDir,
96
90
  });
97
91
 
98
92
  break;
@@ -108,7 +102,6 @@ export async function buildComponents({
108
102
  codegenDir: servicePluginsCodegenDir,
109
103
  component,
110
104
  injectRoute,
111
- rootDir,
112
105
  });
113
106
 
114
107
  break;
@@ -124,7 +117,6 @@ export async function buildComponents({
124
117
  codegenDir: servicePluginsCodegenDir,
125
118
  component,
126
119
  injectRoute,
127
- rootDir,
128
120
  });
129
121
 
130
122
  break;
@@ -140,7 +132,6 @@ export async function buildComponents({
140
132
  codegenDir: servicePluginsCodegenDir,
141
133
  component,
142
134
  injectRoute,
143
- rootDir,
144
135
  });
145
136
 
146
137
  break;
@@ -156,7 +147,6 @@ export async function buildComponents({
156
147
  codegenDir: servicePluginsCodegenDir,
157
148
  component,
158
149
  injectRoute,
159
- rootDir,
160
150
  });
161
151
 
162
152
  break;
@@ -170,7 +160,6 @@ export async function buildComponents({
170
160
  codegenDir: servicePluginsCodegenDir,
171
161
  component,
172
162
  injectRoute,
173
- rootDir,
174
163
  });
175
164
 
176
165
  break;
@@ -184,7 +173,6 @@ export async function buildComponents({
184
173
  codegenDir: webhooksCodegenDir,
185
174
  component,
186
175
  injectRoute,
187
- rootDir,
188
176
  });
189
177
 
190
178
  break;
@@ -16,7 +16,6 @@ export async function buildServicePluginComponent({
16
16
  codegenDir,
17
17
  component,
18
18
  injectRoute,
19
- rootDir,
20
19
  }: {
21
20
  codegenDir: string;
22
21
  component:
@@ -27,14 +26,13 @@ export async function buildServicePluginComponent({
27
26
  | EcomShippingRates
28
27
  | EcomValidations;
29
28
  injectRoute: (injectRoute: InjectedRoute) => void;
30
- rootDir: string;
31
29
  }): Promise<void> {
32
30
  const directory = join(codegenDir, component.manifest.compId);
33
31
 
34
32
  await outputDir(directory);
35
33
 
36
34
  const entrypoint = join(directory, `entry.ts`);
37
- const entryFilePath = join(rootDir, component.directory, 'plugin.ts');
35
+ const entryFilePath = join(component.directory, 'plugin.ts');
38
36
 
39
37
  await writeFile(
40
38
  entrypoint,
@@ -9,19 +9,17 @@ export async function buildWebhookComponent({
9
9
  codegenDir,
10
10
  component,
11
11
  injectRoute,
12
- rootDir,
13
12
  }: {
14
13
  codegenDir: string;
15
14
  component: Webhook;
16
15
  injectRoute: (injectRoute: InjectedRoute) => void;
17
- rootDir: string;
18
16
  }): Promise<void> {
19
17
  const directory = join(codegenDir, component.manifest.compId);
20
18
 
21
19
  await outputDir(directory);
22
20
 
23
21
  const entrypoint = join(directory, `entry.ts`);
24
- const entryFilePath = join(rootDir, component.directory, 'event.ts');
22
+ const entryFilePath = join(component.directory, 'event.ts');
25
23
 
26
24
  await writeFile(
27
25
  entrypoint,
@@ -1,5 +1,4 @@
1
1
  import { join } from 'node:path';
2
- import { cwd } from 'node:process';
3
2
  import type { AstroIntegrationLogger } from 'astro';
4
3
  import { globby } from 'globby';
5
4
  import { outdent } from 'outdent';
@@ -14,11 +13,14 @@ import {
14
13
  import { pathExists, readJson } from './fs-utils.js';
15
14
  import { loadEnvVars } from './loadEnvVars.js';
16
15
 
17
- export async function createProjectModel(
18
- logger: AstroIntegrationLogger
19
- ): Promise<Model> {
20
- const rootDir = cwd();
21
- const { appId, env } = loadEnvVars(logger);
16
+ export async function createProjectModel({
17
+ logger,
18
+ rootDir,
19
+ }: {
20
+ logger: AstroIntegrationLogger;
21
+ rootDir: string;
22
+ }): Promise<Model> {
23
+ const { appId, env } = loadEnvVars({ logger, rootDir });
22
24
 
23
25
  const componentsPaths = await globby(
24
26
  pathToGlobby(join(EXTENSIONS_DIR, '*')),
@@ -31,7 +33,9 @@ export async function createProjectModel(
31
33
  const components: Component[] = [];
32
34
  const unknownComponents: UnknownComponent[] = [];
33
35
 
34
- for (const componentPath of componentsPaths) {
36
+ for (const componentRelativePath of componentsPaths) {
37
+ const componentPath = join(rootDir, componentRelativePath);
38
+
35
39
  const extensionManifest = await readExtensionManifest(componentPath);
36
40
  const knownManifest = parseKnownExtensionManifest(extensionManifest);
37
41
 
@@ -5,11 +5,17 @@ import { loadEnv } from 'vite';
5
5
 
6
6
  const wixClientIdEnvVar = 'WIX_CLIENT_ID';
7
7
 
8
- export function loadEnvVars(logger: AstroIntegrationLogger): {
8
+ export function loadEnvVars({
9
+ logger,
10
+ rootDir,
11
+ }: {
12
+ logger: AstroIntegrationLogger;
13
+ rootDir: string;
14
+ }): {
9
15
  appId: string;
10
16
  env: Record<string, string>;
11
17
  } {
12
- const env = loadEnv(process.env.NODE_ENV ?? 'development', process.cwd(), '');
18
+ const env = loadEnv(process.env.NODE_ENV ?? 'development', rootDir, '');
13
19
  const appId = env[wixClientIdEnvVar];
14
20
 
15
21
  if (appId == null) {
package/tsconfig.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "extends": "../../tsconfig.base.json",
3
- "include": ["src", "test"],
3
+ "include": ["src"],
4
4
  "compilerOptions": {
5
5
  "outDir": "build",
6
6
  "declaration": true,