@netlify/plugin-nextjs 5.0.0-rc.5 → 5.0.0-rc.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.
package/README.md CHANGED
@@ -40,6 +40,8 @@ create it. These also run nightly and on release PRs.
40
40
 
41
41
  ### Integration testing
42
42
 
43
+ > **Prerequisite** Run `npm run build` before running integration tests.
44
+
43
45
  How to add new integration test scenarios to the application:
44
46
 
45
47
  1. Create a new folder under `tests/fixtures/<your-name>`
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/build/content/next-shims/telemetry-storage.cts
21
+ var telemetry_storage_exports = {};
22
+ __export(telemetry_storage_exports, {
23
+ TelemetryShim: () => TelemetryShim
24
+ });
25
+ module.exports = __toCommonJS(telemetry_storage_exports);
26
+ var TelemetryShim = class {
27
+ sessionId = "shim";
28
+ get anonymousId() {
29
+ return "shim";
30
+ }
31
+ get salt() {
32
+ return "shim";
33
+ }
34
+ setEnabled() {
35
+ return null;
36
+ }
37
+ get isEnabled() {
38
+ return false;
39
+ }
40
+ oneWayHash() {
41
+ return "shim";
42
+ }
43
+ record() {
44
+ return Promise.resolve({ isFulfilled: true, isRejected: false });
45
+ }
46
+ flush() {
47
+ return Promise.resolve(null);
48
+ }
49
+ flushDetached() {
50
+ }
51
+ };
52
+ // Annotate the CommonJS export names for ESM import in node:
53
+ 0 && (module.exports = {
54
+ TelemetryShim
55
+ });
@@ -7,7 +7,9 @@
7
7
  import {
8
8
  copyFetchContent,
9
9
  copyPrerenderedContent
10
- } from "../../esm-chunks/chunk-VSH4JS2L.js";
10
+ } from "../../esm-chunks/chunk-4635LKT6.js";
11
+ import "../../esm-chunks/chunk-PDPDW32D.js";
12
+ import "../../esm-chunks/chunk-Y3K5Q6FP.js";
11
13
  import "../../esm-chunks/chunk-VZNKO4OO.js";
12
14
  import "../../esm-chunks/chunk-TYCYFZ22.js";
13
15
  import "../../esm-chunks/chunk-5JVNISGM.js";
@@ -7,9 +7,12 @@
7
7
  import {
8
8
  copyNextDependencies,
9
9
  copyNextServerCode,
10
+ getPatchesToApply,
10
11
  verifyHandlerDirStructure,
11
12
  writeTagsManifest
12
- } from "../../esm-chunks/chunk-CSTSA3JJ.js";
13
+ } from "../../esm-chunks/chunk-YSGPGDIG.js";
14
+ import "../../esm-chunks/chunk-PDPDW32D.js";
15
+ import "../../esm-chunks/chunk-Y3K5Q6FP.js";
13
16
  import "../../esm-chunks/chunk-VZNKO4OO.js";
14
17
  import "../../esm-chunks/chunk-MGPEWDDD.js";
15
18
  import "../../esm-chunks/chunk-PJG75HGC.js";
@@ -18,6 +21,7 @@ import "../../esm-chunks/chunk-5JVNISGM.js";
18
21
  export {
19
22
  copyNextDependencies,
20
23
  copyNextServerCode,
24
+ getPatchesToApply,
21
25
  verifyHandlerDirStructure,
22
26
  writeTagsManifest
23
27
  };
@@ -10,7 +10,9 @@ import {
10
10
  copyStaticExport,
11
11
  publishStaticDir,
12
12
  unpublishStaticDir
13
- } from "../../esm-chunks/chunk-WFVNEURA.js";
13
+ } from "../../esm-chunks/chunk-GV3YIJ33.js";
14
+ import "../../esm-chunks/chunk-PDPDW32D.js";
15
+ import "../../esm-chunks/chunk-Y3K5Q6FP.js";
14
16
  import "../../esm-chunks/chunk-VZNKO4OO.js";
15
17
  import "../../esm-chunks/chunk-TYCYFZ22.js";
16
18
  import "../../esm-chunks/chunk-5JVNISGM.js";
@@ -6,8 +6,10 @@
6
6
 
7
7
  import {
8
8
  createServerHandler
9
- } from "../../esm-chunks/chunk-W7XTKMHH.js";
10
- import "../../esm-chunks/chunk-CSTSA3JJ.js";
9
+ } from "../../esm-chunks/chunk-757FQQND.js";
10
+ import "../../esm-chunks/chunk-YSGPGDIG.js";
11
+ import "../../esm-chunks/chunk-PDPDW32D.js";
12
+ import "../../esm-chunks/chunk-Y3K5Q6FP.js";
11
13
  import "../../esm-chunks/chunk-VZNKO4OO.js";
12
14
  import "../../esm-chunks/chunk-3NYX5FXN.js";
13
15
  import "../../esm-chunks/chunk-MGPEWDDD.js";
@@ -1,4 +1,9 @@
1
- import tracing, { trace } from '{{cwd}}/.netlify/dist/run/handlers/tracing.js'
1
+ import {
2
+ createRequestContext,
3
+ runWithRequestContext,
4
+ } from '{{cwd}}/.netlify/dist/run/handlers/request-context.cjs'
5
+ import { getTracer } from '{{cwd}}/.netlify/dist/run/handlers/tracer.cjs'
6
+ import tracing from '{{cwd}}/.netlify/dist/run/handlers/tracing.js'
2
7
 
3
8
  process.chdir('{{cwd}}')
4
9
 
@@ -8,10 +13,13 @@ export default async function (req, context) {
8
13
  tracing.start()
9
14
  }
10
15
 
11
- /** @type {import('@opentelemetry/api').Tracer} */
12
- const tracer = trace.getTracer('Next.js Runtime')
13
- return tracer.startActiveSpan('Next.js Server Handler', async (span) => {
14
- try {
16
+ const requestContext = createRequestContext(
17
+ req.headers.get('x-nf-debug-logging') || req.headers.get('x-next-debug-logging'),
18
+ )
19
+ const tracer = getTracer()
20
+
21
+ const handlerResponse = await runWithRequestContext(requestContext, () => {
22
+ return tracer.withActiveSpan('Next.js Server Handler', async (span) => {
15
23
  span.setAttributes({
16
24
  'account.id': context.account.id,
17
25
  'deploy.id': context.deploy.id,
@@ -31,16 +39,14 @@ export default async function (req, context) {
31
39
  'http.status_code': response.status,
32
40
  })
33
41
  return response
34
- } catch (error) {
35
- span.recordException(error)
36
- if (error instanceof Error) {
37
- span.addEvent({ name: error.name, message: error.message })
38
- }
39
- throw error
40
- } finally {
41
- span.end()
42
- }
42
+ })
43
43
  })
44
+
45
+ if (requestContext.serverTiming) {
46
+ handlerResponse.headers.set('server-timing', requestContext.serverTiming)
47
+ }
48
+
49
+ return handlerResponse
44
50
  }
45
51
 
46
52
  export const config = {
@@ -1,15 +1,22 @@
1
+ import {
2
+ createRequestContext,
3
+ runWithRequestContext,
4
+ } from './.netlify/dist/run/handlers/request-context.cjs'
1
5
  import serverHandler from './.netlify/dist/run/handlers/server.js'
2
- import tracing, { trace } from './.netlify/dist/run/handlers/tracing.js'
6
+ import { getTracer } from './.netlify/dist/run/handlers/tracer.cjs'
7
+ import tracing from './.netlify/dist/run/handlers/tracing.js'
3
8
 
4
9
  export default async function handler(req, context) {
5
10
  if (process.env.NETLIFY_OTLP_TRACE_EXPORTER_URL) {
6
11
  tracing.start()
7
12
  }
13
+ const requestContext = createRequestContext(
14
+ req.headers.get('x-nf-debug-logging') || req.headers.get('x-next-debug-logging'),
15
+ )
16
+ const tracer = getTracer()
8
17
 
9
- /** @type {import('@opentelemetry/api').Tracer} */
10
- const tracer = trace.getTracer('Next.js Runtime')
11
- return tracer.startActiveSpan('Next.js Server Handler', async (span) => {
12
- try {
18
+ const handlerResponse = await runWithRequestContext(requestContext, () => {
19
+ return tracer.withActiveSpan('Next.js Server Handler', async (span) => {
13
20
  span.setAttributes({
14
21
  'account.id': context.account.id,
15
22
  'deploy.id': context.deploy.id,
@@ -25,16 +32,14 @@ export default async function handler(req, context) {
25
32
  'http.status_code': response.status,
26
33
  })
27
34
  return response
28
- } catch (error) {
29
- span.recordException(error)
30
- if (error instanceof Error) {
31
- span.addEvent({ name: error.name, message: error.message })
32
- }
33
- throw error
34
- } finally {
35
- span.end()
36
- }
35
+ })
37
36
  })
37
+
38
+ if (requestContext.serverTiming) {
39
+ handlerResponse.headers.set('server-timing', requestContext.serverTiming)
40
+ }
41
+
42
+ return handlerResponse
38
43
  }
39
44
 
40
45
  export const config = {
@@ -0,0 +1,244 @@
1
+
2
+ var require = await (async () => {
3
+ var { createRequire } = await import("node:module");
4
+ return createRequire(import.meta.url);
5
+ })();
6
+
7
+ import {
8
+ wrapTracer
9
+ } from "./chunk-PDPDW32D.js";
10
+ import {
11
+ init_esm,
12
+ trace
13
+ } from "./chunk-Y3K5Q6FP.js";
14
+ import {
15
+ require_out
16
+ } from "./chunk-VZNKO4OO.js";
17
+ import {
18
+ encodeBlobKey
19
+ } from "./chunk-TYCYFZ22.js";
20
+ import {
21
+ __toESM
22
+ } from "./chunk-5JVNISGM.js";
23
+
24
+ // src/build/content/prerendered.ts
25
+ init_esm();
26
+ import { existsSync } from "node:fs";
27
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
28
+ import { join } from "node:path";
29
+ var import_fast_glob = __toESM(require_out(), 1);
30
+
31
+ // node_modules/yocto-queue/index.js
32
+ var Node = class {
33
+ value;
34
+ next;
35
+ constructor(value) {
36
+ this.value = value;
37
+ }
38
+ };
39
+ var Queue = class {
40
+ #head;
41
+ #tail;
42
+ #size;
43
+ constructor() {
44
+ this.clear();
45
+ }
46
+ enqueue(value) {
47
+ const node = new Node(value);
48
+ if (this.#head) {
49
+ this.#tail.next = node;
50
+ this.#tail = node;
51
+ } else {
52
+ this.#head = node;
53
+ this.#tail = node;
54
+ }
55
+ this.#size++;
56
+ }
57
+ dequeue() {
58
+ const current = this.#head;
59
+ if (!current) {
60
+ return;
61
+ }
62
+ this.#head = this.#head.next;
63
+ this.#size--;
64
+ return current.value;
65
+ }
66
+ clear() {
67
+ this.#head = void 0;
68
+ this.#tail = void 0;
69
+ this.#size = 0;
70
+ }
71
+ get size() {
72
+ return this.#size;
73
+ }
74
+ *[Symbol.iterator]() {
75
+ let current = this.#head;
76
+ while (current) {
77
+ yield current.value;
78
+ current = current.next;
79
+ }
80
+ }
81
+ };
82
+
83
+ // node_modules/p-limit/index.js
84
+ function pLimit(concurrency) {
85
+ if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
86
+ throw new TypeError("Expected `concurrency` to be a number from 1 and up");
87
+ }
88
+ const queue = new Queue();
89
+ let activeCount = 0;
90
+ const next = () => {
91
+ activeCount--;
92
+ if (queue.size > 0) {
93
+ queue.dequeue()();
94
+ }
95
+ };
96
+ const run = async (fn, resolve, args) => {
97
+ activeCount++;
98
+ const result = (async () => fn(...args))();
99
+ resolve(result);
100
+ try {
101
+ await result;
102
+ } catch {
103
+ }
104
+ next();
105
+ };
106
+ const enqueue = (fn, resolve, args) => {
107
+ queue.enqueue(run.bind(void 0, fn, resolve, args));
108
+ (async () => {
109
+ await Promise.resolve();
110
+ if (activeCount < concurrency && queue.size > 0) {
111
+ queue.dequeue()();
112
+ }
113
+ })();
114
+ };
115
+ const generator = (fn, ...args) => new Promise((resolve) => {
116
+ enqueue(fn, resolve, args);
117
+ });
118
+ Object.defineProperties(generator, {
119
+ activeCount: {
120
+ get: () => activeCount
121
+ },
122
+ pendingCount: {
123
+ get: () => queue.size
124
+ },
125
+ clearQueue: {
126
+ value: () => {
127
+ queue.clear();
128
+ }
129
+ }
130
+ });
131
+ return generator;
132
+ }
133
+
134
+ // src/build/content/prerendered.ts
135
+ var tracer = wrapTracer(trace.getTracer("Next runtime"));
136
+ var writeCacheEntry = async (route, value, lastModified, ctx) => {
137
+ const path = join(ctx.blobDir, await encodeBlobKey(route));
138
+ const entry = JSON.stringify({
139
+ lastModified,
140
+ value
141
+ });
142
+ await writeFile(path, entry, "utf-8");
143
+ };
144
+ var routeToFilePath = (path) => path === "/" ? "/index" : path;
145
+ var buildPagesCacheValue = async (path) => ({
146
+ kind: "PAGE",
147
+ html: await readFile(`${path}.html`, "utf-8"),
148
+ pageData: JSON.parse(await readFile(`${path}.json`, "utf-8")),
149
+ postponed: void 0,
150
+ headers: void 0,
151
+ status: void 0
152
+ });
153
+ var buildAppCacheValue = async (path) => {
154
+ const meta = JSON.parse(await readFile(`${path}.meta`, "utf-8"));
155
+ const rsc = await readFile(`${path}.rsc`, "utf-8").catch(
156
+ () => readFile(`${path}.prefetch.rsc`, "utf-8")
157
+ );
158
+ if (!meta.status && rsc.includes("NEXT_NOT_FOUND")) {
159
+ meta.status = 404;
160
+ }
161
+ return {
162
+ kind: "PAGE",
163
+ html: await readFile(`${path}.html`, "utf-8"),
164
+ pageData: rsc,
165
+ ...meta
166
+ };
167
+ };
168
+ var buildRouteCacheValue = async (path) => ({
169
+ kind: "ROUTE",
170
+ body: await readFile(`${path}.body`, "base64"),
171
+ ...JSON.parse(await readFile(`${path}.meta`, "utf-8"))
172
+ });
173
+ var buildFetchCacheValue = async (path) => ({
174
+ kind: "FETCH",
175
+ ...JSON.parse(await readFile(path, "utf-8"))
176
+ });
177
+ var copyPrerenderedContent = async (ctx) => {
178
+ return tracer.withActiveSpan("copyPrerenderedContent", async () => {
179
+ try {
180
+ await mkdir(ctx.blobDir, { recursive: true });
181
+ const manifest = await ctx.getPrerenderManifest();
182
+ const limitConcurrentPrerenderContentHandling = pLimit(10);
183
+ await Promise.all(
184
+ Object.entries(manifest.routes).map(
185
+ ([route, meta]) => limitConcurrentPrerenderContentHandling(async () => {
186
+ const lastModified = meta.initialRevalidateSeconds ? Date.now() - 31536e6 : Date.now();
187
+ const key = routeToFilePath(route);
188
+ let value;
189
+ switch (true) {
190
+ case (meta.dataRoute?.endsWith("/default.rsc") && !existsSync(join(ctx.publishDir, "server/app", `${key}.html`))):
191
+ return;
192
+ case meta.dataRoute?.endsWith(".json"):
193
+ if (manifest.notFoundRoutes.includes(route)) {
194
+ return;
195
+ }
196
+ value = await buildPagesCacheValue(join(ctx.publishDir, "server/pages", key));
197
+ break;
198
+ case meta.dataRoute?.endsWith(".rsc"):
199
+ value = await buildAppCacheValue(join(ctx.publishDir, "server/app", key));
200
+ break;
201
+ case meta.dataRoute === null:
202
+ value = await buildRouteCacheValue(join(ctx.publishDir, "server/app", key));
203
+ break;
204
+ default:
205
+ throw new Error(`Unrecognized content: ${route}`);
206
+ }
207
+ await writeCacheEntry(key, value, lastModified, ctx);
208
+ })
209
+ )
210
+ );
211
+ if (existsSync(join(ctx.publishDir, `server/app/_not-found.html`))) {
212
+ const lastModified = Date.now();
213
+ const key = "/404";
214
+ const value = await buildAppCacheValue(join(ctx.publishDir, "server/app/_not-found"));
215
+ await writeCacheEntry(key, value, lastModified, ctx);
216
+ }
217
+ } catch (error) {
218
+ ctx.failBuild("Failed assembling prerendered content for upload", error);
219
+ }
220
+ });
221
+ };
222
+ var copyFetchContent = async (ctx) => {
223
+ try {
224
+ const paths = await (0, import_fast_glob.glob)(["!(*.*)"], {
225
+ cwd: join(ctx.publishDir, "cache/fetch-cache"),
226
+ extglob: true
227
+ });
228
+ await Promise.all(
229
+ paths.map(async (key) => {
230
+ const lastModified = Date.now() - 31536e6;
231
+ const path = join(ctx.publishDir, "cache/fetch-cache", key);
232
+ const value = await buildFetchCacheValue(path);
233
+ await writeCacheEntry(key, value, lastModified, ctx);
234
+ })
235
+ );
236
+ } catch (error) {
237
+ ctx.failBuild("Failed assembling fetch content for upload", error);
238
+ }
239
+ };
240
+
241
+ export {
242
+ copyPrerenderedContent,
243
+ copyFetchContent
244
+ };
@@ -9,7 +9,14 @@ import {
9
9
  copyNextServerCode,
10
10
  verifyHandlerDirStructure,
11
11
  writeTagsManifest
12
- } from "./chunk-CSTSA3JJ.js";
12
+ } from "./chunk-YSGPGDIG.js";
13
+ import {
14
+ wrapTracer
15
+ } from "./chunk-PDPDW32D.js";
16
+ import {
17
+ init_esm,
18
+ trace
19
+ } from "./chunk-Y3K5Q6FP.js";
13
20
  import {
14
21
  require_out
15
22
  } from "./chunk-VZNKO4OO.js";
@@ -21,44 +28,49 @@ import {
21
28
  } from "./chunk-5JVNISGM.js";
22
29
 
23
30
  // src/build/functions/server.ts
24
- var import_fast_glob = __toESM(require_out(), 1);
31
+ init_esm();
25
32
  import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
26
33
  import { join, relative } from "node:path";
27
34
  import { join as posixJoin } from "node:path/posix";
35
+ var import_fast_glob = __toESM(require_out(), 1);
36
+ var tracer = wrapTracer(trace.getTracer("Next runtime"));
28
37
  var copyHandlerDependencies = async (ctx) => {
29
- const promises = [];
30
- const { included_files: includedFiles = [] } = ctx.netlifyConfig.functions?.["*"] || {};
31
- if (includedFiles.length !== 0) {
32
- const resolvedFiles = await Promise.all(
33
- includedFiles.map((globPattern) => (0, import_fast_glob.glob)(globPattern, { cwd: process.cwd() }))
34
- );
35
- for (const filePath of resolvedFiles.flat()) {
38
+ await tracer.withActiveSpan("copyHandlerDependencies", async (span) => {
39
+ const promises = [];
40
+ const { included_files: includedFiles = [] } = ctx.netlifyConfig.functions?.["*"] || {};
41
+ span.setAttribute("next.includedFiles", includedFiles.join(","));
42
+ if (includedFiles.length !== 0) {
43
+ const resolvedFiles = await Promise.all(
44
+ includedFiles.map((globPattern) => (0, import_fast_glob.glob)(globPattern, { cwd: process.cwd() }))
45
+ );
46
+ for (const filePath of resolvedFiles.flat()) {
47
+ promises.push(
48
+ cp(
49
+ join(process.cwd(), filePath),
50
+ // the serverHandlerDir is aware of the dist dir.
51
+ // The distDir must not be the package path therefore we need to rely on the
52
+ // serverHandlerDir instead of the serverHandlerRootDir
53
+ // therefore we need to remove the package path from the filePath
54
+ join(ctx.serverHandlerDir, relative(ctx.relativeAppDir, filePath)),
55
+ {
56
+ recursive: true,
57
+ force: true
58
+ }
59
+ )
60
+ );
61
+ }
62
+ }
63
+ const fileList = await (0, import_fast_glob.glob)("dist/**/*", { cwd: ctx.pluginDir });
64
+ for (const filePath of fileList) {
36
65
  promises.push(
37
- cp(
38
- join(process.cwd(), filePath),
39
- // the serverHandlerDir is aware of the dist dir.
40
- // The distDir must not be the package path therefore we need to rely on the
41
- // serverHandlerDir instead of the serverHandlerRootDir
42
- // therefore we need to remove the package path from the filePath
43
- join(ctx.serverHandlerDir, relative(ctx.relativeAppDir, filePath)),
44
- {
45
- recursive: true,
46
- force: true
47
- }
48
- )
66
+ cp(join(ctx.pluginDir, filePath), join(ctx.serverHandlerDir, ".netlify", filePath), {
67
+ recursive: true,
68
+ force: true
69
+ })
49
70
  );
50
71
  }
51
- }
52
- const fileList = await (0, import_fast_glob.glob)("dist/**/*", { cwd: ctx.pluginDir });
53
- for (const filePath of fileList) {
54
- promises.push(
55
- cp(join(ctx.pluginDir, filePath), join(ctx.serverHandlerDir, ".netlify", filePath), {
56
- recursive: true,
57
- force: true
58
- })
59
- );
60
- }
61
- await Promise.all(promises);
72
+ await Promise.all(promises);
73
+ });
62
74
  };
63
75
  var writeHandlerManifest = async (ctx) => {
64
76
  await writeFile(
@@ -96,18 +108,18 @@ var writeHandlerFile = async (ctx) => {
96
108
  await writeFile(join(ctx.serverHandlerRootDir, `${SERVER_HANDLER_NAME}.mjs`), handler);
97
109
  };
98
110
  var createServerHandler = async (ctx) => {
99
- await rm(ctx.serverFunctionsDir, { recursive: true, force: true });
100
- await mkdir(join(ctx.serverHandlerDir, ".netlify"), { recursive: true });
101
- await Promise.all([
102
- copyNextServerCode(ctx),
103
- copyNextDependencies(ctx),
104
- writeTagsManifest(ctx),
105
- copyHandlerDependencies(ctx),
106
- writeHandlerManifest(ctx),
107
- writePackageMetadata(ctx),
108
- writeHandlerFile(ctx)
109
- ]);
110
- await verifyHandlerDirStructure(ctx);
111
+ await tracer.withActiveSpan("createServerHandler", async () => {
112
+ await rm(ctx.serverFunctionsDir, { recursive: true, force: true });
113
+ await mkdir(join(ctx.serverHandlerDir, ".netlify"), { recursive: true });
114
+ await copyNextServerCode(ctx);
115
+ await copyNextDependencies(ctx);
116
+ await writeTagsManifest(ctx);
117
+ await copyHandlerDependencies(ctx);
118
+ await writeHandlerManifest(ctx);
119
+ await writePackageMetadata(ctx);
120
+ await writeHandlerFile(ctx);
121
+ await verifyHandlerDirStructure(ctx);
122
+ });
111
123
  };
112
124
 
113
125
  export {