@teleporthq/teleport-plugin-next-static-paths 0.44.0-alpha.0 → 0.44.1

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.
@@ -0,0 +1,52 @@
1
+ import { ComponentStructure } from '@teleporthq/teleport-types'
2
+ import { createStaticPathsPlugin } from '../src/index'
3
+
4
+ // A page that seeds a state from a data source renders per request (its
5
+ // getStaticProps is turned into getServerSideProps at the end of the page
6
+ // pipeline), and Next.js refuses getStaticPaths beside getServerSideProps. The
7
+ // plugin must therefore stay out of such a dynamic page — and only of such a
8
+ // page: a state resolved in the browser keeps the page statically generated.
9
+
10
+ const DS_ID = 'ds-1'
11
+
12
+ const makeStructure = (query: string): ComponentStructure =>
13
+ ({
14
+ uidl: {
15
+ name: 'Profile',
16
+ node: { type: 'element', content: { elementType: 'container' } },
17
+ stateDefinitions: {
18
+ rows: {
19
+ type: 'array',
20
+ defaultValue: [],
21
+ dataSourceBinding: { dataSourceId: DS_ID, refPath: ['profiles'] },
22
+ query,
23
+ },
24
+ },
25
+ outputOptions: { folderPath: ['profile'], fileName: '[id]' },
26
+ },
27
+ chunks: [{ name: 'jsx-component' }],
28
+ dependencies: {},
29
+ options: {
30
+ dataSources: { [DS_ID]: { id: DS_ID, type: 'teleport', config: {} } },
31
+ resources: { items: {}, path: ['utils', 'data-sources'] },
32
+ },
33
+ } as unknown as ComponentStructure)
34
+
35
+ describe('teleport-plugin-next-static-paths: data-source state skip', () => {
36
+ const plugin = createStaticPathsPlugin()
37
+
38
+ it('emits no getStaticPaths for a dynamic page that seeds a state from a data source', async () => {
39
+ const result = await plugin(makeStructure('SELECT * FROM profiles LIMIT 5'))
40
+
41
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticPaths')).toBeUndefined()
42
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticProps')).toBeUndefined()
43
+ })
44
+
45
+ it('still emits the fallback getStaticPaths when the state is only resolved in the browser', async () => {
46
+ const result = await plugin(
47
+ makeStructure("SELECT * FROM profiles WHERE user_id = '{{Current User.id}}'")
48
+ )
49
+
50
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticPaths')).toBeDefined()
51
+ })
52
+ })
@@ -0,0 +1,75 @@
1
+ import { ComponentStructure } from '@teleporthq/teleport-types'
2
+ import { createStaticPathsPlugin } from '../src/index'
3
+
4
+ /**
5
+ * Regression guard for the `pages/resources/[id].js` build break — the
6
+ * getStaticPaths half of it:
7
+ *
8
+ * Module not found: Can't resolve '../fetch_content_items_paths'
9
+ *
10
+ * See the sibling test in teleport-plugin-next-static-props for the full story.
11
+ */
12
+
13
+ const RESOURCE_ID = 'fetch-content-item-paths'
14
+ const RESOURCE_NAME = 'fetch_content_items_paths'
15
+
16
+ const makeStructure = (params: {
17
+ folderPath: string[]
18
+ resourcesPath?: string[]
19
+ pagesPath?: string[]
20
+ }): ComponentStructure => {
21
+ const { folderPath, resourcesPath = ['resources'], pagesPath } = params
22
+ return {
23
+ uidl: {
24
+ name: 'CustomResources',
25
+ node: { type: 'element', content: { elementType: 'container' } },
26
+ outputOptions: {
27
+ folderPath,
28
+ fileName: '[id]',
29
+ initialPathsData: {
30
+ exposeAs: { name: 'id', valuePath: [], itemValuePath: ['id'] },
31
+ resource: { id: RESOURCE_ID, params: {} },
32
+ },
33
+ },
34
+ },
35
+ chunks: [{ name: 'jsx-component' }],
36
+ dependencies: {},
37
+ options: {
38
+ ...(pagesPath && { pagesPath }),
39
+ resources: {
40
+ items: { [RESOURCE_ID]: { id: RESOURCE_ID, name: RESOURCE_NAME } },
41
+ path: resourcesPath,
42
+ },
43
+ },
44
+ } as unknown as ComponentStructure
45
+ }
46
+
47
+ describe('teleport-plugin-next-static-paths: resource import path', () => {
48
+ const plugin = createStaticPathsPlugin()
49
+
50
+ it('reaches the project resources folder from a page whose folder is named "resources"', async () => {
51
+ const structure = await plugin(makeStructure({ folderPath: ['resources'] }))
52
+
53
+ expect(structure.dependencies.fetchContentItemsPathsResource.path).toBe(
54
+ `../../resources/${RESOURCE_NAME}`
55
+ )
56
+ })
57
+
58
+ it('keeps working for a page in a non-colliding subfolder', async () => {
59
+ const structure = await plugin(makeStructure({ folderPath: ['blog'] }))
60
+
61
+ expect(structure.dependencies.fetchContentItemsPathsResource.path).toBe(
62
+ `../../resources/${RESOURCE_NAME}`
63
+ )
64
+ })
65
+
66
+ it('honours a pages root that is not the project root child', async () => {
67
+ const structure = await plugin(
68
+ makeStructure({ folderPath: ['resources'], pagesPath: ['src', 'pages'] })
69
+ )
70
+
71
+ expect(structure.dependencies.fetchContentItemsPathsResource.path).toBe(
72
+ `../../../resources/${RESOURCE_NAME}`
73
+ )
74
+ })
75
+ })
@@ -0,0 +1,158 @@
1
+ import { ComponentStructure, UIDLWorkflows } from '@teleporthq/teleport-types'
2
+ import { createStaticPathsPlugin } from '../src/index'
3
+
4
+ // Regression guard: a page that reads one specific row AND has a same-page
5
+ // workflow writing to that SAME table renders with getServerSideProps (see
6
+ // teleport-plugin-next-static-props), which resolves params per-request.
7
+ // Next.js does not allow getStaticPaths alongside getServerSideProps, so
8
+ // this plugin must be a no-op for those pages — even when the page has no
9
+ // initialPathsData and would otherwise fall back to emitting a stub
10
+ // getStaticPaths/getStaticProps pair. This is decided by table/workflow
11
+ // correlation, not by the project's visual nav layout.
12
+
13
+ const TABLE_NAME = 'press_items'
14
+ const PAGE_ID = 'page-edit-press-item'
15
+
16
+ const makeWorkflows = (tableName: string, scopedToPageId: string | null = PAGE_ID): UIDLWorkflows =>
17
+ ({
18
+ workflows: {
19
+ 'update-press-item': {
20
+ id: 'update-press-item',
21
+ name: 'Update press item',
22
+ trigger: {
23
+ nodeId: 'trigger-1',
24
+ type: 'event-click',
25
+ scope: 'element',
26
+ config: {
27
+ selectedPages: scopedToPageId ? [{ id: scopedToPageId, name: 'Edit Press Item' }] : [],
28
+ },
29
+ },
30
+ nodes: [
31
+ {
32
+ id: 'mutate-1',
33
+ type: 'data-update-item',
34
+ label: 'Update item',
35
+ config: { tableName },
36
+ executionEnv: 'server',
37
+ stepNumber: 1,
38
+ },
39
+ ],
40
+ edges: [],
41
+ usedInNodes: {},
42
+ },
43
+ },
44
+ } as unknown as UIDLWorkflows)
45
+
46
+ const makeStructure = (params: {
47
+ folderPath: string[]
48
+ fileName: string
49
+ tableName?: string
50
+ workflows?: UIDLWorkflows
51
+ }): ComponentStructure => {
52
+ const { folderPath, fileName, tableName, workflows } = params
53
+ return {
54
+ uidl: {
55
+ name: 'EditPressItem',
56
+ node: { type: 'element', content: { elementType: 'container' } },
57
+ outputOptions: {
58
+ pageId: PAGE_ID,
59
+ folderPath,
60
+ fileName,
61
+ ...(tableName && {
62
+ detailsPageInfo: {
63
+ dataSourceId: 'ds-1',
64
+ dataSourceName: 'TeleportHQ database',
65
+ dataSourceType: 'teleport',
66
+ tableName,
67
+ differentiatorColumn: 'id',
68
+ featureIdentifier: 'pressItem',
69
+ },
70
+ }),
71
+ },
72
+ },
73
+ chunks: [{ name: 'jsx-component' }],
74
+ dependencies: {},
75
+ options: { workflows, resources: { items: {}, path: ['utils', 'data-sources'] } },
76
+ } as unknown as ComponentStructure
77
+ }
78
+
79
+ describe('teleport-plugin-next-static-paths: same-table-mutation getServerSideProps skip', () => {
80
+ const plugin = createStaticPathsPlugin()
81
+
82
+ it('emits no getStaticPaths/getStaticProps chunks when the page reads and a same-page workflow writes the same table', async () => {
83
+ const structure = makeStructure({
84
+ folderPath: ['edit-press-item'],
85
+ fileName: '[id]',
86
+ tableName: TABLE_NAME,
87
+ workflows: makeWorkflows(TABLE_NAME),
88
+ })
89
+
90
+ const result = await plugin(structure)
91
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticPaths')).toBeUndefined()
92
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticProps')).toBeUndefined()
93
+ })
94
+
95
+ it('emits no getStaticPaths for a page that reads a money table — it renders per request', async () => {
96
+ const structure = makeStructure({
97
+ folderPath: ['admin', 'vouchers', 'update'],
98
+ fileName: '[id]',
99
+ tableName: 'teleport_vouchers',
100
+ workflows: undefined,
101
+ })
102
+
103
+ const result = await plugin(structure)
104
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticPaths')).toBeUndefined()
105
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticProps')).toBeUndefined()
106
+ })
107
+
108
+ it('still emits a fallback getStaticPaths when detailsPageInfo is present but no mutation workflow targets its table', async () => {
109
+ const structure = makeStructure({
110
+ folderPath: ['view-press-item'],
111
+ fileName: '[id]',
112
+ tableName: TABLE_NAME,
113
+ workflows: undefined,
114
+ })
115
+
116
+ const result = await plugin(structure)
117
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticPaths')).toBeDefined()
118
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticProps')).toBeDefined()
119
+ })
120
+
121
+ it('still emits a fallback getStaticPaths when the matching-table workflow is scoped to a different page', async () => {
122
+ const structure = makeStructure({
123
+ folderPath: ['view-press-item'],
124
+ fileName: '[id]',
125
+ tableName: TABLE_NAME,
126
+ workflows: makeWorkflows(TABLE_NAME, 'some-other-page'),
127
+ })
128
+
129
+ const result = await plugin(structure)
130
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticPaths')).toBeDefined()
131
+ })
132
+
133
+ it('still emits a fallback getStaticPaths for a dynamic page with no detailsPageInfo at all (e.g. public blog-post/[id])', async () => {
134
+ const structure = makeStructure({
135
+ folderPath: ['blog-post'],
136
+ fileName: '[id]',
137
+ tableName: undefined,
138
+ workflows: undefined,
139
+ })
140
+
141
+ const result = await plugin(structure)
142
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticPaths')).toBeDefined()
143
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticProps')).toBeDefined()
144
+ })
145
+
146
+ it('is a no-op for a non-dynamic page regardless of workflows (no route param to worry about)', async () => {
147
+ const structure = makeStructure({
148
+ folderPath: ['add-press-item'],
149
+ fileName: 'index',
150
+ tableName: undefined,
151
+ workflows: makeWorkflows(TABLE_NAME),
152
+ })
153
+
154
+ const result = await plugin(structure)
155
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticPaths')).toBeUndefined()
156
+ expect(result.chunks.find((chunk) => chunk.name === 'getStaticProps')).toBeUndefined()
157
+ })
158
+ })
@@ -0,0 +1,71 @@
1
+ import * as types from '@babel/types'
2
+ import generate from '@babel/generator'
3
+ import { generateInitialPathsAST } from '../src/utils'
4
+ import { UIDLInitialPathsData } from '@teleporthq/teleport-types'
5
+
6
+ const initialPathsData: UIDLInitialPathsData = {
7
+ exposeAs: { name: 'productPaths', valuePath: ['data'], itemValuePath: ['slug'] },
8
+ resource: { id: 'TQ_products' },
9
+ }
10
+
11
+ /**
12
+ * Evaluates the emitted `getStaticPaths` against a canned response, so these
13
+ * assert on the paths it actually produces rather than on generated text.
14
+ */
15
+ const runStaticPaths = async (response: unknown) => {
16
+ const ast = generateInitialPathsAST(
17
+ initialPathsData,
18
+ 'fetchProducts',
19
+ initialPathsData.resource,
20
+ undefined,
21
+ 'slug'
22
+ )
23
+ const { code } = generate(types.program([ast]))
24
+
25
+ const factory = new Function(
26
+ 'fetchProducts',
27
+ `${code.replace('export async function getStaticPaths', 'async function getStaticPaths')}
28
+ return getStaticPaths`
29
+ )
30
+
31
+ return factory(() => Promise.resolve(response))()
32
+ }
33
+
34
+ describe('getStaticPaths item hygiene', () => {
35
+ it('produces one path per record for clean data, in order — unchanged', async () => {
36
+ const result = await runStaticPaths({ data: [{ slug: 'a' }, { slug: 'b' }, { slug: 'c' }] })
37
+
38
+ expect(result.paths).toEqual([
39
+ { params: { slug: 'a' } },
40
+ { params: { slug: 'b' } },
41
+ { params: { slug: 'c' } },
42
+ ])
43
+ expect(result.fallback).toBe('blocking')
44
+ })
45
+
46
+ it('stringifies a numeric differentiator, as before', async () => {
47
+ const result = await runStaticPaths({ data: [{ slug: 1 }, { slug: 2 }] })
48
+ expect(result.paths).toEqual([{ params: { slug: '1' } }, { params: { slug: '2' } }])
49
+ })
50
+
51
+ it('skips records with no differentiator instead of losing every path', async () => {
52
+ const result = await runStaticPaths({
53
+ data: [{ slug: 'a' }, {}, { slug: null }, { slug: '' }, { slug: 'b' }],
54
+ })
55
+
56
+ expect(result.paths).toEqual([{ params: { slug: 'a' } }, { params: { slug: 'b' } }])
57
+ })
58
+
59
+ it('emits one path per distinct differentiator', async () => {
60
+ const result = await runStaticPaths({
61
+ data: [{ slug: 'a' }, { slug: 'b' }, { slug: 'a' }],
62
+ })
63
+
64
+ expect(result.paths).toEqual([{ params: { slug: 'a' } }, { params: { slug: 'b' } }])
65
+ })
66
+
67
+ it('returns no paths, not an error, for an empty or absent collection', async () => {
68
+ expect((await runStaticPaths({ data: [] })).paths).toEqual([])
69
+ expect((await runStaticPaths({})).paths).toEqual([])
70
+ })
71
+ })
@@ -0,0 +1,102 @@
1
+ /* tslint:disable:function-constructor */
2
+ import * as types from '@babel/types'
3
+ import generate from '@babel/generator'
4
+ import { ComponentStructure } from '@teleporthq/teleport-types'
5
+ import { createStaticPathsPlugin } from '../src/index'
6
+
7
+ /**
8
+ * The rows a details page is pre-rendered for are the rows its reader may see:
9
+ * listed as the store, a draft product became a page anyone could open by its
10
+ * slug. A public page lists them as a visitor is served them.
11
+ */
12
+
13
+ const RESOURCE_ID = 'fetch-products-paths'
14
+
15
+ const AUTH = {
16
+ enabled: true,
17
+ roles: ['admin'],
18
+ pageProtection: {
19
+ 'p-admin-products': {
20
+ requiresAuth: true,
21
+ allowedRoles: ['admin'],
22
+ pageName: 'update',
23
+ route: '/admin/products/update',
24
+ },
25
+ },
26
+ folderProtection: {
27
+ 'f-admin': {
28
+ requiresAuth: true,
29
+ allowedRoles: ['admin'],
30
+ folderName: 'admin-panel',
31
+ parentId: 'pages',
32
+ children: { 'p-admin-products': 'page' },
33
+ },
34
+ },
35
+ }
36
+
37
+ const runStaticPaths = async (folderPath: string[], pageId: string) => {
38
+ const structure = {
39
+ uidl: {
40
+ name: 'ProductDetails',
41
+ node: { type: 'element', content: { elementType: 'container' } },
42
+ outputOptions: {
43
+ pageId,
44
+ folderPath,
45
+ fileName: '[slug]',
46
+ dynamicRouteAttribute: 'slug',
47
+ initialPathsData: {
48
+ exposeAs: { name: 'productPaths', valuePath: ['data'], itemValuePath: ['slug'] },
49
+ resource: { id: RESOURCE_ID, params: {} },
50
+ },
51
+ },
52
+ },
53
+ chunks: [{ name: 'jsx-component', type: 'js', fileType: 'js', content: {}, linkAfter: [] }],
54
+ dependencies: {},
55
+ options: {
56
+ auth: AUTH,
57
+ resources: {
58
+ items: {
59
+ [RESOURCE_ID]: {
60
+ id: RESOURCE_ID,
61
+ name: 'fetch-products-paths',
62
+ params: {
63
+ dataSourceId: { type: 'static', content: 'ds-1' },
64
+ dataSourceType: { type: 'static', content: 'teleport' },
65
+ tableName: { type: 'static', content: 'teleport_products' },
66
+ },
67
+ },
68
+ },
69
+ path: ['resources'],
70
+ },
71
+ },
72
+ } as unknown as ComponentStructure
73
+ const result = await createStaticPathsPlugin()(structure)
74
+ const chunk = result.chunks.find((c) => c.name === 'getStaticPaths')
75
+ const { code } = generate(types.program([chunk!.content as types.Statement]))
76
+ const calls: unknown[][] = []
77
+ const getStaticPaths = new Function(
78
+ 'fetchProductsPathsResource',
79
+ `${code.replace('export async function getStaticPaths', 'async function getStaticPaths')}
80
+ return getStaticPaths`
81
+ )((...args: unknown[]) => {
82
+ calls.push(args)
83
+ return Promise.resolve({ data: [{ slug: 'mug' }] })
84
+ })
85
+ const result2 = await getStaticPaths()
86
+ return { calls, paths: result2.paths }
87
+ }
88
+
89
+ describe('teleport-plugin-next-static-paths: whom the listed rows are read for', () => {
90
+ it('lists a public page’s rows as a visitor is served them', async () => {
91
+ const { calls, paths } = await runStaticPaths(['products'], 'p-product')
92
+
93
+ expect(calls).toEqual([[{}, { as: 'visitor' }]])
94
+ expect(paths).toEqual([{ params: { slug: 'mug' } }])
95
+ })
96
+
97
+ it('lists them as the store for an admin page only trusted readers open', async () => {
98
+ const { calls } = await runStaticPaths(['admin', 'products', 'update'], 'p-admin-products')
99
+
100
+ expect(calls).toEqual([[{}]])
101
+ })
102
+ })
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EACf,sBAAsB,EAIvB,MAAM,4BAA4B,CAAA;AAInC,UAAU,uBAAuB;IAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,eAAO,MAAM,uBAAuB,EAAE,sBAAsB,CAAC,uBAAuB,CA0EnF,CAAA;;AAED,wBAAwC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,eAAe,EACf,sBAAsB,EAIvB,MAAM,4BAA4B,CAAA;AAKnC,UAAU,uBAAuB;IAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAUD,eAAO,MAAM,uBAAuB,EAAE,sBAAsB,CAAC,uBAAuB,CAyKnF,CAAA;;AAED,wBAAwC"}
package/dist/cjs/index.js CHANGED
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
26
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
27
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -37,21 +60,81 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
37
60
  };
38
61
  Object.defineProperty(exports, "__esModule", { value: true });
39
62
  exports.createStaticPathsPlugin = void 0;
63
+ var types = __importStar(require("@babel/types"));
40
64
  var teleport_types_1 = require("@teleporthq/teleport-types");
41
65
  var teleport_shared_1 = require("@teleporthq/teleport-shared");
66
+ var teleport_plugin_common_1 = require("@teleporthq/teleport-plugin-common");
42
67
  var utils_1 = require("./utils");
68
+ var isDynamicRoute = teleport_plugin_common_1.RouteUtils.isDynamicRoute, pageDataReadArguments = teleport_plugin_common_1.RouteUtils.pageDataReadArguments, pageHasSameTableMutationWorkflow = teleport_plugin_common_1.RouteUtils.pageHasSameTableMutationWorkflow, pageReadsProtectedTable = teleport_plugin_common_1.RouteUtils.pageReadsProtectedTable, pageSeedsStateFromDataSource = teleport_plugin_common_1.RouteUtils.pageSeedsStateFromDataSource;
43
69
  var createStaticPathsPlugin = function (config) {
44
70
  var _a = (config || {}).componentChunkName, componentChunkName = _a === void 0 ? 'jsx-component' : _a;
45
71
  var staticPathsPlugin = function (structure) { return __awaiter(void 0, void 0, void 0, function () {
46
- var uidl, chunks, options, dependencies, resources, resource, isLocalResource, isExternalResource, resourceImportName, usedResource, importPath, componentChunk, getStaticPathsAST;
47
- var _a, _b;
48
- return __generator(this, function (_c) {
72
+ var uidl, chunks, options, dependencies, resources, fallbackGetStaticPaths, fallbackGetStaticProps, resource, isLocalResource, isExternalResource, resourceImportName, usedResource, componentChunk, getStaticPathsAST;
73
+ var _a, _b, _c;
74
+ return __generator(this, function (_d) {
49
75
  uidl = structure.uidl, chunks = structure.chunks, options = structure.options, dependencies = structure.dependencies;
50
76
  resources = options.resources;
77
+ // Entity-bound dynamic-route pages with a same-page mutation workflow
78
+ // render with getServerSideProps instead (see `createStaticPropsPlugin` /
79
+ // `pageHasSameTableMutationWorkflow`'s doc in
80
+ // `teleport-plugin-common/src/utils/route-utils.ts`), which resolves
81
+ // params per-request — Next.js does not allow (and does not need) a
82
+ // getStaticPaths alongside getServerSideProps on the same page. A page
83
+ // that seeds a state from a data source renders per request too (see
84
+ // `pageSeedsStateFromDataSource`).
85
+ if (isDynamicRoute(uidl) &&
86
+ (pageHasSameTableMutationWorkflow(uidl, options.workflows) ||
87
+ pageReadsProtectedTable(uidl) ||
88
+ pageSeedsStateFromDataSource(uidl, options.dataSources))) {
89
+ return [2 /*return*/, structure];
90
+ }
51
91
  if (!((_a = uidl.outputOptions) === null || _a === void 0 ? void 0 : _a.initialPathsData)) {
92
+ // For dynamic routes without initialPathsData,
93
+ // generate a fallback getStaticPaths with empty paths and fallback: 'blocking'.
94
+ // This is needed because Next.js requires getStaticPaths for any dynamic route
95
+ // that uses getStaticProps (which may be added later by the i18n or data source plugins).
96
+ if (isDynamicRoute(uidl)) {
97
+ fallbackGetStaticPaths = types.exportNamedDeclaration((function () {
98
+ var node = types.functionDeclaration(types.identifier('getStaticPaths'), [], types.blockStatement([
99
+ types.returnStatement(types.objectExpression([
100
+ types.objectProperty(types.identifier('paths'), types.arrayExpression([])),
101
+ types.objectProperty(types.identifier('fallback'), types.stringLiteral('blocking')),
102
+ ])),
103
+ ]), false, true);
104
+ node.async = true;
105
+ return node;
106
+ })());
107
+ chunks.push({
108
+ name: 'getStaticPaths',
109
+ type: teleport_types_1.ChunkType.AST,
110
+ fileType: teleport_types_1.FileType.JS,
111
+ content: fallbackGetStaticPaths,
112
+ linkAfter: [componentChunkName],
113
+ });
114
+ // Next.js requires getStaticProps when getStaticPaths is present.
115
+ // Generate a minimal getStaticProps if no initialPropsData will provide one.
116
+ if (!((_b = uidl.outputOptions) === null || _b === void 0 ? void 0 : _b.initialPropsData)) {
117
+ fallbackGetStaticProps = types.exportNamedDeclaration((function () {
118
+ var node = types.functionDeclaration(types.identifier('getStaticProps'), [types.identifier('context')], types.blockStatement([
119
+ types.returnStatement(types.objectExpression([
120
+ types.objectProperty(types.identifier('props'), types.objectExpression([])),
121
+ ])),
122
+ ]), false, true);
123
+ node.async = true;
124
+ return node;
125
+ })());
126
+ chunks.push({
127
+ name: 'getStaticProps',
128
+ type: teleport_types_1.ChunkType.AST,
129
+ fileType: teleport_types_1.FileType.JS,
130
+ content: fallbackGetStaticProps,
131
+ linkAfter: ['getStaticPaths'],
132
+ });
133
+ }
134
+ }
52
135
  return [2 /*return*/, structure];
53
136
  }
54
- resource = ((_b = uidl === null || uidl === void 0 ? void 0 : uidl.outputOptions) === null || _b === void 0 ? void 0 : _b.initialPathsData).resource;
137
+ resource = ((_c = uidl === null || uidl === void 0 ? void 0 : uidl.outputOptions) === null || _c === void 0 ? void 0 : _c.initialPathsData).resource;
55
138
  isLocalResource = 'id' in resource;
56
139
  isExternalResource = 'name' in resource;
57
140
  if (isLocalResource) {
@@ -60,10 +143,13 @@ var createStaticPathsPlugin = function (config) {
60
143
  throw new teleport_types_1.TeleportError("Resource ".concat(resource.id, " is being used, but missing from the project ressources"));
61
144
  }
62
145
  resourceImportName = teleport_shared_1.StringUtils.dashCaseToCamelCase(teleport_shared_1.StringUtils.camelCaseToDashCase("".concat(usedResource.name, "-resource")));
63
- importPath = "".concat(resources.path).concat(teleport_shared_1.StringUtils.camelCaseToDashCase(usedResource.name));
64
146
  dependencies[resourceImportName] = {
65
147
  type: 'local',
66
- path: importPath,
148
+ path: "".concat(teleport_shared_1.GenericUtils.generatePageDependenciesPrefix({
149
+ toPath: resources.path,
150
+ folderPath: uidl.outputOptions.folderPath,
151
+ pagesPath: options.pagesPath,
152
+ })).concat(teleport_shared_1.StringUtils.camelCaseToDashCase(usedResource.name)),
67
153
  };
68
154
  }
69
155
  if (isExternalResource) {
@@ -74,7 +160,10 @@ var createStaticPathsPlugin = function (config) {
74
160
  if (!componentChunk) {
75
161
  return [2 /*return*/, structure];
76
162
  }
77
- getStaticPathsAST = (0, utils_1.generateInitialPathsAST)(uidl.outputOptions.initialPathsData, resourceImportName, resource, uidl.outputOptions.pagination);
163
+ getStaticPathsAST = (0, utils_1.generateInitialPathsAST)(uidl.outputOptions.initialPathsData, resourceImportName, resource, uidl.outputOptions.pagination, uidl.outputOptions.dynamicRouteAttribute,
164
+ // A resource the project generated forwards it to the data-source module;
165
+ // another package's function takes its own arguments.
166
+ isLocalResource ? pageDataReadArguments(uidl, options.auth) : []);
78
167
  chunks.push({
79
168
  name: 'getStaticPaths',
80
169
  type: teleport_types_1.ChunkType.AST,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6DAOmC;AACnC,+DAAyD;AACzD,iCAAiD;AAM1C,IAAM,uBAAuB,GAAoD,UACtF,MAAM;IAEE,IAAA,KAAyC,CAAA,MAAM,IAAI,EAAE,CAAA,mBAAjB,EAApC,kBAAkB,mBAAG,eAAe,KAAA,CAAiB;IAE7D,IAAM,iBAAiB,GAAoB,UAAO,SAAS;;;;YACjD,IAAI,GAAoC,SAAS,KAA7C,EAAE,MAAM,GAA4B,SAAS,OAArC,EAAE,OAAO,GAAmB,SAAS,QAA5B,EAAE,YAAY,GAAK,SAAS,aAAd,CAAc;YACjD,SAAS,GAAK,OAAO,UAAZ,CAAY;YAE7B,IAAI,CAAC,CAAA,MAAA,IAAI,CAAC,aAAa,0CAAE,gBAAgB,CAAA,EAAE;gBACzC,sBAAO,SAAS,EAAA;aACjB;YAEO,QAAQ,GAAK,CAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,aAAa,0CAAE,gBAAgB,CAAA,SAA1C,CAA0C;YAEpD,eAAe,GAAG,IAAI,IAAI,QAAQ,CAAA;YAClC,kBAAkB,GAAG,MAAM,IAAI,QAAQ,CAAA;YAM7C,IAAI,eAAe,EAAE;gBACb,YAAY,GAAG,SAAS,CAAC,KAAK,CAAE,QAA8B,CAAC,EAAE,CAAC,CAAA;gBAExE,IAAI,CAAC,YAAY,EAAE;oBACjB,MAAM,IAAI,8BAAa,CACrB,mBACG,QAA8B,CAAC,EAAE,4DACqB,CAC1D,CAAA;iBACF;gBAED,kBAAkB,GAAG,6BAAW,CAAC,mBAAmB,CAClD,6BAAW,CAAC,mBAAmB,CAAC,UAAG,YAAY,CAAC,IAAI,cAAW,CAAC,CACjE,CAAA;gBAEK,UAAU,GAAG,UAAG,SAAS,CAAC,IAAI,SAAG,6BAAW,CAAC,mBAAmB,CAAC,YAAY,CAAC,IAAI,CAAC,CAAE,CAAA;gBAE3F,YAAY,CAAC,kBAAkB,CAAC,GAAG;oBACjC,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,UAAU;iBACjB,CAAA;aACF;YAED,IAAI,kBAAkB,EAAE;gBACtB,kBAAkB,GAAG,QAAQ,CAAC,IAAI,CAAA;gBAClC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAA;aAClD;YAEK,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,UAAC,KAAK,IAAK,OAAA,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAjC,CAAiC,CAAC,CAAA;YAChF,IAAI,CAAC,cAAc,EAAE;gBACnB,sBAAO,SAAS,EAAA;aACjB;YAEK,iBAAiB,GAAG,IAAA,+BAAuB,EAC/C,IAAI,CAAC,aAAa,CAAC,gBAAgB,EACnC,kBAAkB,EAClB,QAAQ,EACR,IAAI,CAAC,aAAa,CAAC,UAAU,CAC9B,CAAA;YAED,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,gBAAgB;gBACtB,IAAI,EAAE,0BAAS,CAAC,GAAG;gBACnB,QAAQ,EAAE,yBAAQ,CAAC,EAAE;gBACrB,OAAO,EAAE,iBAAiB;gBAC1B,SAAS,EAAE,CAAC,kBAAkB,CAAC;aAChC,CAAC,CAAA;YAEF,sBAAO,SAAS,EAAA;;SACjB,CAAA;IAED,OAAO,iBAAiB,CAAA;AAC1B,CAAC,CAAA;AA1EY,QAAA,uBAAuB,2BA0EnC;AAED,kBAAe,IAAA,+BAAuB,GAAE,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}