handoff-app 2.0.0-3 → 2.0.0-5
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/AGENTS.md +7 -0
- package/CLAUDE.md +7 -0
- package/README.md +302 -378
- package/dist/app-builder/build.js +2 -2
- package/dist/app-builder/nav-shell.js +8 -15
- package/dist/app-builder/vercel-output.js +4 -4
- package/dist/cli/make.js +2 -2
- package/dist/cli.js +39 -7
- package/dist/commands/build/app.js +1 -5
- package/dist/commands/build/components.js +1 -5
- package/dist/commands/build/index.js +1 -5
- package/dist/commands/checkout/index.d.ts +15 -12
- package/dist/commands/checkout/index.js +15 -54
- package/dist/commands/compat/deprecations.d.ts +46 -0
- package/dist/commands/compat/deprecations.js +62 -0
- package/dist/commands/compat/push-args.d.ts +48 -0
- package/dist/commands/compat/push-args.js +73 -0
- package/dist/commands/db/migrate.js +1 -5
- package/dist/commands/dev/index.js +1 -5
- package/dist/commands/eject/config.js +1 -5
- package/dist/commands/eject/pages.js +1 -5
- package/dist/commands/eject/theme.js +1 -5
- package/dist/commands/fetch/index.js +1 -5
- package/dist/commands/index.js +4 -0
- package/dist/commands/login/index.js +1 -5
- package/dist/commands/logout/index.js +1 -5
- package/dist/commands/make/component.js +1 -5
- package/dist/commands/make/page.js +3 -7
- package/dist/commands/make/template.js +1 -5
- package/dist/commands/publish/index.d.ts +18 -12
- package/dist/commands/publish/index.js +18 -54
- package/dist/commands/pull/index.d.ts +13 -0
- package/dist/commands/pull/index.js +20 -0
- package/dist/commands/push/index.d.ts +23 -0
- package/dist/commands/push/index.js +58 -0
- package/dist/commands/scaffold/index.js +1 -5
- package/dist/commands/start/index.js +1 -5
- package/dist/commands/types.d.ts +10 -0
- package/dist/commands/utils.d.ts +74 -6
- package/dist/commands/utils.js +89 -10
- package/dist/commands/validate/components.js +1 -5
- package/dist/config/index.d.ts +2 -1
- package/dist/config/index.js +2 -1
- package/dist/config/loader.d.ts +19 -6
- package/dist/config/loader.js +43 -13
- package/dist/config/normalizers/page.d.ts +4 -4
- package/dist/config/normalizers/page.js +2 -2
- package/dist/config/runtime.js +9 -25
- package/dist/index.d.ts +69 -22
- package/dist/index.js +148 -35
- package/dist/nav/resolver.js +3 -1
- package/dist/nav/workspace.js +2 -2
- package/dist/registry/auth/access-tokens.d.ts +11 -3
- package/dist/registry/auth/access-tokens.js +29 -3
- package/dist/registry/auth/index.d.ts +4 -3
- package/dist/registry/auth/index.js +10 -2
- package/dist/registry/auth/sync-secret.d.ts +27 -0
- package/dist/registry/auth/sync-secret.js +65 -0
- package/dist/registry/auth/types.d.ts +20 -1
- package/dist/registry/auth/types.js +3 -1
- package/dist/registry/auth/validation.d.ts +11 -0
- package/dist/registry/auth/validation.js +18 -1
- package/dist/registry/checkout/assets.d.ts +1 -1
- package/dist/registry/checkout/assets.js +21 -6
- package/dist/registry/checkout/index.d.ts +8 -1
- package/dist/registry/checkout/index.js +39 -6
- package/dist/registry/checkout/tokens.d.ts +1 -1
- package/dist/registry/checkout/tokens.js +12 -5
- package/dist/registry/connection.d.ts +10 -0
- package/dist/registry/connection.js +52 -7
- package/dist/registry/content-kinds.d.ts +27 -0
- package/dist/registry/content-kinds.js +33 -0
- package/dist/registry/db/client.d.ts +6 -1
- package/dist/registry/db/client.js +16 -3
- package/dist/registry/db/schema.d.ts +37 -3
- package/dist/registry/db/schema.js +9 -7
- package/dist/registry/publish/assets.d.ts +2 -2
- package/dist/registry/publish/assets.js +46 -35
- package/dist/registry/publish/index.d.ts +29 -5
- package/dist/registry/publish/index.js +87 -34
- package/dist/registry/publish/tokens.d.ts +2 -2
- package/dist/registry/publish/tokens.js +30 -24
- package/dist/registry/selection.d.ts +12 -0
- package/dist/registry/selection.js +22 -0
- package/dist/store/registry.d.ts +48 -0
- package/dist/store/registry.js +75 -12
- package/dist/transformers/preview/types.d.ts +2 -2
- package/dist/utils/markdown.d.ts +10 -0
- package/dist/utils/markdown.js +17 -0
- package/dist/utils/menu-shell.js +14 -7
- package/dist/utils/pages.d.ts +22 -0
- package/dist/utils/pages.js +73 -0
- package/dist/utils/path.d.ts +5 -0
- package/dist/utils/path.js +9 -0
- package/docs/api.md +1 -3
- package/docs/cli.md +1 -1
- package/drizzle/0002_add_pages.sql +5 -3
- package/drizzle/meta/0002_snapshot.json +17 -8
- package/drizzle/meta/0003_snapshot.json +17 -8
- package/drizzle/meta/0004_snapshot.json +17 -8
- package/drizzle/meta/0005_snapshot.json +17 -8
- package/package.json +1 -1
- package/src/app/components/util/index.ts +5 -23
- package/src/app/lib/docs-api/backend.ts +11 -0
- package/src/app/lib/docs-api/errors.ts +8 -7
- package/src/app/lib/docs-api/handler.ts +2 -3
- package/src/app/lib/docs-api/index.ts +2 -0
- package/src/app/lib/docs-api/page-discovery.ts +126 -0
- package/src/app/lib/docs-api/page-rendering.ts +17 -0
- package/src/app/lib/docs-api/page-search.ts +191 -0
- package/src/app/lib/docs-api/records.ts +11 -19
- package/src/app/lib/docs-api/registry.ts +90 -11
- package/src/app/lib/docs-api/search.ts +115 -0
- package/src/app/lib/registry-api/allowlist.ts +7 -5
- package/src/app/lib/registry-api/asset-transfer.ts +58 -31
- package/src/app/lib/registry-api/auth.ts +89 -9
- package/src/app/lib/registry-api/entity-routes.ts +17 -7
- package/src/app/lib/registry-api/errors.ts +10 -4
- package/src/app/lib/registry-api/handler.ts +13 -15
- package/src/app/lib/registry-api/meta.ts +4 -0
- package/src/app/lib/registry-api/revalidate.ts +31 -12
- package/src/app/lib/registry-api/store.ts +89 -26
- package/src/app/lib/registry-api/sync-compat.ts +166 -0
- package/src/app/lib/registry-api/token-transfer.ts +44 -12
- package/src/app/lib/registry-api/transfer-batch.ts +116 -0
- package/src/app/lib/registry-api/transfer.ts +62 -35
- package/src/app/lib/registry-api/validation.ts +33 -1
- package/src/app/lib/registry-connection.ts +1 -1
- package/src/app/next.config.mjs +6 -0
- package/src/app/pages/[...slug]/index.tsx +37 -22
- package/src/app/pages/api/account/tokens/index.ts +4 -13
- package/src/app/pages/api/docs/search/pages.json.ts +25 -0
- package/src/app/pages/api/oauth/revoke.ts +14 -7
- package/src/app/pages/api/registry/components/[id]/files/[...filePath].ts +1 -1
- package/src/app/pages/api/registry/components/[id].ts +2 -2
- package/src/app/pages/api/registry/components/index.ts +1 -1
- package/src/app/pages/api/registry/pages/[...id].ts +20 -0
- package/src/app/pages/api/registry/pages/index.ts +19 -0
- package/src/app/pages/api/registry/patterns/[id]/files/[...filePath].ts +1 -1
- package/src/app/pages/api/registry/patterns/[id].ts +2 -2
- package/src/app/pages/api/registry/patterns/index.ts +1 -1
- package/src/app/pages/api/registry/transfer/assets/blobs/have.ts +2 -2
- package/src/app/pages/api/sync/upload.ts +21 -0
- package/src/app/pages/index/index.tsx +14 -0
- package/src/app/pages/index.tsx +30 -5
- package/src/app-builder/build.ts +2 -2
- package/src/app-builder/nav-shell.ts +8 -13
- package/src/app-builder/vercel-output.ts +4 -4
- package/src/cli/make.ts +2 -2
- package/src/cli.ts +31 -7
- package/src/commands/build/app.ts +2 -3
- package/src/commands/build/components.ts +2 -3
- package/src/commands/build/index.ts +2 -3
- package/src/commands/checkout/index.ts +18 -44
- package/src/commands/compat/deprecations.ts +79 -0
- package/src/commands/compat/push-args.ts +106 -0
- package/src/commands/db/migrate.ts +2 -3
- package/src/commands/dev/index.ts +2 -3
- package/src/commands/eject/config.ts +2 -3
- package/src/commands/eject/pages.ts +2 -3
- package/src/commands/eject/theme.ts +2 -3
- package/src/commands/fetch/index.ts +2 -3
- package/src/commands/index.ts +4 -0
- package/src/commands/login/index.ts +2 -3
- package/src/commands/logout/index.ts +2 -3
- package/src/commands/make/component.ts +2 -3
- package/src/commands/make/page.ts +4 -5
- package/src/commands/make/template.ts +2 -3
- package/src/commands/publish/index.ts +21 -44
- package/src/commands/pull/index.ts +32 -0
- package/src/commands/push/index.ts +115 -0
- package/src/commands/scaffold/index.ts +2 -3
- package/src/commands/start/index.ts +2 -3
- package/src/commands/types.ts +11 -1
- package/src/commands/utils.ts +80 -11
- package/src/commands/validate/components.ts +2 -3
- package/src/config/index.ts +2 -1
- package/src/config/loader.ts +57 -12
- package/src/config/normalizers/page.ts +4 -4
- package/src/config/runtime.ts +9 -24
- package/src/index.ts +183 -42
- package/src/nav/resolver.ts +3 -1
- package/src/nav/workspace.ts +2 -2
- package/src/registry/auth/access-tokens.ts +29 -5
- package/src/registry/auth/index.ts +7 -1
- package/src/registry/auth/sync-secret.ts +67 -0
- package/src/registry/auth/types.ts +24 -1
- package/src/registry/auth/validation.ts +18 -0
- package/src/registry/checkout/assets.ts +24 -7
- package/src/registry/checkout/index.ts +41 -5
- package/src/registry/checkout/tokens.ts +12 -6
- package/src/registry/connection.ts +53 -5
- package/src/registry/content-kinds.ts +39 -0
- package/src/registry/db/client.ts +22 -2
- package/src/registry/db/schema.ts +9 -7
- package/src/registry/publish/assets.ts +47 -37
- package/src/registry/publish/index.ts +102 -38
- package/src/registry/publish/tokens.ts +35 -26
- package/src/registry/selection.ts +19 -0
- package/src/store/registry.ts +118 -13
- package/src/transformers/preview/types.ts +2 -2
- package/src/utils/README.md +1 -0
- package/src/utils/markdown.ts +11 -0
- package/src/utils/menu-shell.ts +14 -7
- package/src/utils/pages.ts +52 -0
- package/src/utils/path.ts +15 -6
- package/templates/default/package.json.tpl +4 -0
- package/config/docs/foundations/logos.md +0 -7
- package/src/app/lib/api/redact.ts +0 -46
package/dist/store/registry.js
CHANGED
|
@@ -31,7 +31,7 @@ var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
|
31
31
|
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
32
32
|
};
|
|
33
33
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
-
exports.createRegistryStore = exports.RegistryAssetStore = exports.RegistryTokenStore = exports.RegistryPageStore = exports.RegistryPatternStore = exports.RegistryComponentStore = void 0;
|
|
34
|
+
exports.createRegistryStore = exports.RegistryAssetStore = exports.RegistryTokenStore = exports.filterPublishedPageIds = exports.searchPageCandidates = exports.RegistryPageStore = exports.RegistryPatternStore = exports.RegistryComponentStore = void 0;
|
|
35
35
|
const drizzle_orm_1 = require("drizzle-orm");
|
|
36
36
|
const schema_1 = require("../registry/db/schema");
|
|
37
37
|
/**
|
|
@@ -65,11 +65,7 @@ class RegistryComponentStore {
|
|
|
65
65
|
get(id) {
|
|
66
66
|
return __awaiter(this, void 0, void 0, function* () {
|
|
67
67
|
var _a, _b;
|
|
68
|
-
const rows = yield this.context.db
|
|
69
|
-
.select({ record: schema_1.components.record })
|
|
70
|
-
.from(schema_1.components)
|
|
71
|
-
.where((0, drizzle_orm_1.eq)(schema_1.components.id, id))
|
|
72
|
-
.limit(1);
|
|
68
|
+
const rows = yield this.context.db.select({ record: schema_1.components.record }).from(schema_1.components).where((0, drizzle_orm_1.eq)(schema_1.components.id, id)).limit(1);
|
|
73
69
|
return (_b = (_a = rows[0]) === null || _a === void 0 ? void 0 : _a.record) !== null && _b !== void 0 ? _b : null;
|
|
74
70
|
});
|
|
75
71
|
}
|
|
@@ -112,11 +108,7 @@ class RegistryPatternStore {
|
|
|
112
108
|
get(id) {
|
|
113
109
|
return __awaiter(this, void 0, void 0, function* () {
|
|
114
110
|
var _a, _b;
|
|
115
|
-
const rows = yield this.context.db
|
|
116
|
-
.select({ record: schema_1.patterns.record })
|
|
117
|
-
.from(schema_1.patterns)
|
|
118
|
-
.where((0, drizzle_orm_1.eq)(schema_1.patterns.id, id))
|
|
119
|
-
.limit(1);
|
|
111
|
+
const rows = yield this.context.db.select({ record: schema_1.patterns.record }).from(schema_1.patterns).where((0, drizzle_orm_1.eq)(schema_1.patterns.id, id)).limit(1);
|
|
120
112
|
return (_b = (_a = rows[0]) === null || _a === void 0 ? void 0 : _a.record) !== null && _b !== void 0 ? _b : null;
|
|
121
113
|
});
|
|
122
114
|
}
|
|
@@ -179,6 +171,72 @@ class RegistryPageStore {
|
|
|
179
171
|
}
|
|
180
172
|
}
|
|
181
173
|
exports.RegistryPageStore = RegistryPageStore;
|
|
174
|
+
/** Escape the wildcards Postgres reads in an `ILIKE` pattern, so a term cannot widen its own match. */
|
|
175
|
+
const likePattern = (term) => `%${term.replace(/[\\%_]/g, (char) => `\\${char}`)}%`;
|
|
176
|
+
/**
|
|
177
|
+
* Candidate pages for a search, filtered and capped in SQL.
|
|
178
|
+
*
|
|
179
|
+
* `enabled` and `menuTitle` are fields in the `record` JSON, so the query uses JSON operators. An
|
|
180
|
+
* absent `enabled` field means enabled. The body filter excludes frontmatter, so an excluded field
|
|
181
|
+
* such as `metaTitle` cannot consume a candidate slot.
|
|
182
|
+
*
|
|
183
|
+
* The filter and the projection share one body expression, so every term SQL matched is inside the text that the
|
|
184
|
+
* server ranks.
|
|
185
|
+
*
|
|
186
|
+
* The body expression is empty for an external-link page. Search reads such a page by title, menu title, and
|
|
187
|
+
* description only. The exclusion must happen in SQL. An external body otherwise satisfies the filter and takes one
|
|
188
|
+
* of the `limit` rows. It pushes a real candidate past the cap before the server can drop it.
|
|
189
|
+
*
|
|
190
|
+
* `C` collation orders IDs by code point, as the merge in registry search does. Both orders must
|
|
191
|
+
* agree, or the cap can keep different pages in each runtime mode.
|
|
192
|
+
*/
|
|
193
|
+
const searchPageCandidates = (db, query) => __awaiter(void 0, void 0, void 0, function* () {
|
|
194
|
+
// No term means no candidate, and an empty list would build `array[]`, which Postgres cannot type.
|
|
195
|
+
if (query.terms.length === 0) {
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
const patterns = drizzle_orm_1.sql.join(query.terms.map((term) => (0, drizzle_orm_1.sql) `${likePattern(term)}`), (0, drizzle_orm_1.sql) `, `);
|
|
199
|
+
const matchesAnyTerm = (text) => (0, drizzle_orm_1.sql) `${text} ilike any (array[${patterns}])`;
|
|
200
|
+
// This mirrors `record.external ? '' : markdown` in `toSearchablePage`. The transfer endpoint stores a published
|
|
201
|
+
// record verbatim, so `external` can hold any JSON. The list holds every value that JS reads as falsy, and
|
|
202
|
+
// `coalesce` prevents a NULL result for an absent key. The case blanks the external side, so an unrecognized
|
|
203
|
+
// value keeps its body.
|
|
204
|
+
const isExternal = (0, drizzle_orm_1.sql) `
|
|
205
|
+
coalesce(${schema_1.pages.record}->'external', 'false'::jsonb) not in (
|
|
206
|
+
'null'::jsonb, 'false'::jsonb, '""'::jsonb, '0'::jsonb
|
|
207
|
+
)
|
|
208
|
+
`;
|
|
209
|
+
const storedBody = (0, drizzle_orm_1.sql) `left(coalesce(${schema_1.pageFiles.body}, ''), ${query.bodyLength})`;
|
|
210
|
+
const searchableBody = (0, drizzle_orm_1.sql) `
|
|
211
|
+
case
|
|
212
|
+
when ${isExternal} then ''
|
|
213
|
+
else ${storedBody}
|
|
214
|
+
end
|
|
215
|
+
`;
|
|
216
|
+
return db
|
|
217
|
+
.select({ record: schema_1.pages.record, body: searchableBody })
|
|
218
|
+
.from(schema_1.pages)
|
|
219
|
+
.leftJoin(schema_1.pageFiles, (0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(schema_1.pageFiles.pageId, schema_1.pages.id), (0, drizzle_orm_1.eq)(schema_1.pageFiles.kind, 'markdown')))
|
|
220
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.sql) `${schema_1.pages.record}->>'enabled' is distinct from 'false'`, query.group ? (0, drizzle_orm_1.sql) `lower(${schema_1.pages.group}) = lower(${query.group})` : undefined, (0, drizzle_orm_1.or)(matchesAnyTerm(schema_1.pages.title), matchesAnyTerm(schema_1.pages.description), matchesAnyTerm((0, drizzle_orm_1.sql) `${schema_1.pages.record}->>'menuTitle'`), matchesAnyTerm(searchableBody))))
|
|
221
|
+
.orderBy((0, drizzle_orm_1.sql) `${schema_1.pages.id} collate "C"`)
|
|
222
|
+
.limit(query.limit);
|
|
223
|
+
});
|
|
224
|
+
exports.searchPageCandidates = searchPageCandidates;
|
|
225
|
+
/**
|
|
226
|
+
* The candidate IDs that have a published page. Search asks only about packaged default IDs, because
|
|
227
|
+
* no other ID can replace a default. This keeps the query bounded as the registry grows.
|
|
228
|
+
*
|
|
229
|
+
* A published page replaces the default with the same ID even when it does not match the search
|
|
230
|
+
* terms, so this query ignores the term filter.
|
|
231
|
+
*/
|
|
232
|
+
const filterPublishedPageIds = (db, candidateIds) => __awaiter(void 0, void 0, void 0, function* () {
|
|
233
|
+
if (candidateIds.length === 0) {
|
|
234
|
+
return [];
|
|
235
|
+
}
|
|
236
|
+
const rows = yield db.select({ id: schema_1.pages.id }).from(schema_1.pages).where((0, drizzle_orm_1.inArray)(schema_1.pages.id, candidateIds));
|
|
237
|
+
return rows.map((row) => row.id);
|
|
238
|
+
});
|
|
239
|
+
exports.filterPublishedPageIds = filterPublishedPageIds;
|
|
182
240
|
class RegistryTokenStore {
|
|
183
241
|
constructor(context) {
|
|
184
242
|
this.context = context;
|
|
@@ -203,7 +261,12 @@ class RegistryTokenStore {
|
|
|
203
261
|
getArtifacts(id) {
|
|
204
262
|
return __awaiter(this, void 0, void 0, function* () {
|
|
205
263
|
const rows = yield this.context.db
|
|
206
|
-
.select({
|
|
264
|
+
.select({
|
|
265
|
+
path: schema_1.tokenArtifacts.path,
|
|
266
|
+
format: schema_1.tokenArtifacts.format,
|
|
267
|
+
content: schema_1.tokenArtifacts.content,
|
|
268
|
+
contentType: schema_1.tokenArtifacts.contentType,
|
|
269
|
+
})
|
|
207
270
|
.from(schema_1.tokenArtifacts)
|
|
208
271
|
.where((0, drizzle_orm_1.eq)(schema_1.tokenArtifacts.tokenSetId, id));
|
|
209
272
|
return rows
|
|
@@ -254,9 +254,9 @@ export type PageObject = {
|
|
|
254
254
|
};
|
|
255
255
|
};
|
|
256
256
|
export type PageListObject = {
|
|
257
|
-
/** Stable page id
|
|
257
|
+
/** Stable page id derived from the file location; `index` identifies the root home page. */
|
|
258
258
|
id: string;
|
|
259
|
-
/** Logical route the page is served at (e.g. `/guides/setup`). */
|
|
259
|
+
/** Logical route the page is served at (e.g. `/guides/setup`, or `/` for `index`). */
|
|
260
260
|
path: string;
|
|
261
261
|
/**
|
|
262
262
|
* Absolute filesystem path of the source `.md` (workspace store only). Workspace-only and stripped
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import matter from 'gray-matter';
|
|
2
|
+
/**
|
|
3
|
+
* Parse markdown frontmatter without the process-lifetime cache in gray-matter.
|
|
4
|
+
*
|
|
5
|
+
* `matter(text)` caches every document it parses, keyed by the whole input string, and only when the call passes no
|
|
6
|
+
* options. Nothing clears that cache, so a long-running server keeps a copy of every distinct document it parsed.
|
|
7
|
+
* Passing `{}` skips the cache and matches the defaults of the parser, so the result does not change. Use this
|
|
8
|
+
* wherever a request, a regeneration, or a watch can parse markdown again.
|
|
9
|
+
*/
|
|
10
|
+
export declare const parseMarkdown: (text: string) => matter.GrayMatterFile<string>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseMarkdown = void 0;
|
|
7
|
+
const gray_matter_1 = __importDefault(require("gray-matter"));
|
|
8
|
+
/**
|
|
9
|
+
* Parse markdown frontmatter without the process-lifetime cache in gray-matter.
|
|
10
|
+
*
|
|
11
|
+
* `matter(text)` caches every document it parses, keyed by the whole input string, and only when the call passes no
|
|
12
|
+
* options. Nothing clears that cache, so a long-running server keeps a copy of every distinct document it parsed.
|
|
13
|
+
* Passing `{}` skips the cache and matches the defaults of the parser, so the result does not change. Use this
|
|
14
|
+
* wherever a request, a regeneration, or a watch can parse markdown again.
|
|
15
|
+
*/
|
|
16
|
+
const parseMarkdown = (text) => (0, gray_matter_1.default)(text, {});
|
|
17
|
+
exports.parseMarkdown = parseMarkdown;
|
package/dist/utils/menu-shell.js
CHANGED
|
@@ -28,25 +28,32 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.buildMenuShell = exports.buildMenuFromDirectory = exports.buildTokensFoundationsMenu = exports.KNOWN_PATHS = void 0;
|
|
30
30
|
const fs = __importStar(require("fs"));
|
|
31
|
-
const gray_matter_1 = __importDefault(require("gray-matter"));
|
|
32
31
|
const lodash_1 = require("lodash");
|
|
33
32
|
const path_1 = __importDefault(require("path"));
|
|
33
|
+
const markdown_1 = require("./markdown");
|
|
34
|
+
const pages_1 = require("./pages");
|
|
34
35
|
/**
|
|
35
36
|
* Paths that have dedicated route files and are therefore excluded from auto-scanned submenus.
|
|
36
37
|
* Single source of truth — the docs app imports this (re-exported there as `knownPaths`).
|
|
37
38
|
*/
|
|
38
39
|
exports.KNOWN_PATHS = [
|
|
40
|
+
'account',
|
|
41
|
+
'account/tokens',
|
|
42
|
+
'account/users',
|
|
39
43
|
'assets',
|
|
40
44
|
'assets/fonts',
|
|
41
45
|
'assets/icons',
|
|
42
46
|
'assets/logos',
|
|
47
|
+
'cli/device',
|
|
43
48
|
'foundations',
|
|
44
49
|
'foundations/colors',
|
|
45
50
|
'foundations/icons',
|
|
46
51
|
'foundations/effects',
|
|
47
|
-
'foundations/logos',
|
|
48
52
|
'foundations/logo',
|
|
49
53
|
'foundations/typography',
|
|
54
|
+
'install',
|
|
55
|
+
'login',
|
|
56
|
+
'reset-password',
|
|
50
57
|
'system',
|
|
51
58
|
'system/component',
|
|
52
59
|
'system/tokens',
|
|
@@ -101,12 +108,12 @@ const buildMenuFromDirectory = (dirPath, urlPrefix) => {
|
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
110
|
else if (entry.endsWith('.md') && entry !== 'index.md') {
|
|
104
|
-
const slug =
|
|
111
|
+
const slug = (0, pages_1.stripMarkdownExtension)(entry);
|
|
105
112
|
const fullSlugPath = `${urlPrefix}/${slug}`.replace(/^\/+/, '');
|
|
106
113
|
if (exports.KNOWN_PATHS.indexOf(fullSlugPath) >= 0)
|
|
107
114
|
continue;
|
|
108
115
|
const contents = fs.readFileSync(fullPath, 'utf-8');
|
|
109
|
-
const { data: metadata } = (0,
|
|
116
|
+
const { data: metadata } = (0, markdown_1.parseMarkdown)(contents);
|
|
110
117
|
if (metadata.enabled === false)
|
|
111
118
|
continue;
|
|
112
119
|
items.push({
|
|
@@ -151,11 +158,11 @@ const buildMenuShell = (options) => {
|
|
|
151
158
|
continue;
|
|
152
159
|
}
|
|
153
160
|
const contents = fs.readFileSync(search, 'utf-8');
|
|
154
|
-
const { data: metadata } = (0,
|
|
161
|
+
const { data: metadata } = (0, markdown_1.parseMarkdown)(contents);
|
|
155
162
|
if (metadata.enabled === false) {
|
|
156
163
|
continue;
|
|
157
164
|
}
|
|
158
|
-
const filepath = `/${
|
|
165
|
+
const filepath = `/${(0, pages_1.stripMarkdownExtension)(fileName)}`;
|
|
159
166
|
const subSections = [];
|
|
160
167
|
if (metadata.menu) {
|
|
161
168
|
for (const key of Object.keys(metadata.menu)) {
|
|
@@ -183,7 +190,7 @@ const buildMenuShell = (options) => {
|
|
|
183
190
|
}
|
|
184
191
|
else {
|
|
185
192
|
// No frontmatter menu: auto-scan the matching directory (working pages win over docs).
|
|
186
|
-
const dirName =
|
|
193
|
+
const dirName = (0, pages_1.stripMarkdownExtension)(fileName);
|
|
187
194
|
const nestedFromDocs = (0, exports.buildMenuFromDirectory)(path_1.default.resolve(docRoot, dirName), `/${dirName}`);
|
|
188
195
|
const nestedFromPages = workingPagesDir
|
|
189
196
|
? (0, exports.buildMenuFromDirectory)(path_1.default.resolve(workingPagesDir, dirName), `/${dirName}`)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip a single trailing `.md` extension.
|
|
3
|
+
*
|
|
4
|
+
* Anchored to the end on purpose: an unanchored `replace('.md', '')` removes the FIRST `.md`
|
|
5
|
+
* substring, so a compound name like `notes.mdx.md` becomes `notesx.md` instead of `notes.mdx`.
|
|
6
|
+
* The route, nav link, and discovered id must all agree, so every subsystem strips the extension
|
|
7
|
+
* through this one function.
|
|
8
|
+
*/
|
|
9
|
+
export declare const stripMarkdownExtension: (fileName: string) => string;
|
|
10
|
+
export interface CollectPageSlugsOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Keep the root-level `index.md` (the home page entity, id `index`). Nested `index.md` files are
|
|
13
|
+
* always skipped because section indexes are owned by dedicated routes. Defaults to `false`.
|
|
14
|
+
*/
|
|
15
|
+
includeRootIndex?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Recursively collect page slug segments (path relative to `root`, minus the trailing `.md`) for
|
|
19
|
+
* every markdown page under `root`. Shared by page discovery, the routing catch-all, and the nav
|
|
20
|
+
* shell so all three derive identical ids from the same files.
|
|
21
|
+
*/
|
|
22
|
+
export declare const collectPageSlugSegments: (root: string, options?: CollectPageSlugsOptions, relativeParts?: string[]) => string[][];
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.collectPageSlugSegments = exports.stripMarkdownExtension = void 0;
|
|
30
|
+
const fs = __importStar(require("fs"));
|
|
31
|
+
const path_1 = __importDefault(require("path"));
|
|
32
|
+
const content_kinds_1 = require("../registry/content-kinds");
|
|
33
|
+
/**
|
|
34
|
+
* Strip a single trailing `.md` extension.
|
|
35
|
+
*
|
|
36
|
+
* Anchored to the end on purpose: an unanchored `replace('.md', '')` removes the FIRST `.md`
|
|
37
|
+
* substring, so a compound name like `notes.mdx.md` becomes `notesx.md` instead of `notes.mdx`.
|
|
38
|
+
* The route, nav link, and discovered id must all agree, so every subsystem strips the extension
|
|
39
|
+
* through this one function.
|
|
40
|
+
*/
|
|
41
|
+
const stripMarkdownExtension = (fileName) => fileName.replace(/\.md$/, '');
|
|
42
|
+
exports.stripMarkdownExtension = stripMarkdownExtension;
|
|
43
|
+
/** True for a page `.md` file; an `index.md` counts only as the root home page when `includeRootIndex` is set. */
|
|
44
|
+
const isCollectablePage = (entry, isRoot, includeRootIndex) => {
|
|
45
|
+
if (!entry.endsWith('.md'))
|
|
46
|
+
return false;
|
|
47
|
+
if (entry === `${content_kinds_1.HOME_PAGE_ID}.md`)
|
|
48
|
+
return isRoot && includeRootIndex;
|
|
49
|
+
return true;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Recursively collect page slug segments (path relative to `root`, minus the trailing `.md`) for
|
|
53
|
+
* every markdown page under `root`. Shared by page discovery, the routing catch-all, and the nav
|
|
54
|
+
* shell so all three derive identical ids from the same files.
|
|
55
|
+
*/
|
|
56
|
+
const collectPageSlugSegments = (root, options = {}, relativeParts = []) => {
|
|
57
|
+
var _a;
|
|
58
|
+
if (!fs.existsSync(root))
|
|
59
|
+
return [];
|
|
60
|
+
const includeRootIndex = (_a = options.includeRootIndex) !== null && _a !== void 0 ? _a : false;
|
|
61
|
+
const results = [];
|
|
62
|
+
for (const entry of fs.readdirSync(root)) {
|
|
63
|
+
const fullPath = path_1.default.join(root, entry);
|
|
64
|
+
if (fs.lstatSync(fullPath).isDirectory()) {
|
|
65
|
+
results.push(...(0, exports.collectPageSlugSegments)(fullPath, options, [...relativeParts, entry]));
|
|
66
|
+
}
|
|
67
|
+
else if (isCollectablePage(entry, relativeParts.length === 0, includeRootIndex)) {
|
|
68
|
+
results.push([...relativeParts, (0, exports.stripMarkdownExtension)(entry)]);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return results;
|
|
72
|
+
};
|
|
73
|
+
exports.collectPageSlugSegments = collectPageSlugSegments;
|
package/dist/utils/path.d.ts
CHANGED
|
@@ -15,6 +15,11 @@ export declare function normalizePathForCompare(inputPath: string): string;
|
|
|
15
15
|
* True when both paths resolve to the same normalized filesystem path.
|
|
16
16
|
*/
|
|
17
17
|
export declare function arePathsEqual(pathA: string, pathB: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* The directory handoff commands run against - `HANDOFF_WORKING_PATH` when set, otherwise the
|
|
20
|
+
* process working directory. Relative paths passed on the command line (e.g. `-c`) resolve from here.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveWorkingPath(): string;
|
|
18
23
|
/**
|
|
19
24
|
* True when childPath is equal to or within parentPath.
|
|
20
25
|
*/
|
package/dist/utils/path.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.generateFilesystemSafeId = generateFilesystemSafeId;
|
|
7
7
|
exports.normalizePathForCompare = normalizePathForCompare;
|
|
8
8
|
exports.arePathsEqual = arePathsEqual;
|
|
9
|
+
exports.resolveWorkingPath = resolveWorkingPath;
|
|
9
10
|
exports.isPathInside = isPathInside;
|
|
10
11
|
const path_1 = __importDefault(require("path"));
|
|
11
12
|
/**
|
|
@@ -49,6 +50,14 @@ function normalizePathForCompare(inputPath) {
|
|
|
49
50
|
function arePathsEqual(pathA, pathB) {
|
|
50
51
|
return normalizePathForCompare(pathA) === normalizePathForCompare(pathB);
|
|
51
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* The directory handoff commands run against - `HANDOFF_WORKING_PATH` when set, otherwise the
|
|
55
|
+
* process working directory. Relative paths passed on the command line (e.g. `-c`) resolve from here.
|
|
56
|
+
*/
|
|
57
|
+
function resolveWorkingPath() {
|
|
58
|
+
const configured = process.env.HANDOFF_WORKING_PATH;
|
|
59
|
+
return configured ? path_1.default.resolve(configured) : process.cwd();
|
|
60
|
+
}
|
|
52
61
|
/**
|
|
53
62
|
* True when childPath is equal to or within parentPath.
|
|
54
63
|
*/
|
package/docs/api.md
CHANGED
package/docs/cli.md
CHANGED
|
@@ -16,7 +16,7 @@ but the various kinds of configurations can be tailored or extended.
|
|
|
16
16
|
|
|
17
17
|
Handoff has 4 configuration areas -
|
|
18
18
|
|
|
19
|
-
`handoff.config.*` - Defines the general handoff configuration. Supported files are `handoff.config.ts`, `handoff.config.js`, `handoff.config.cjs`, and `handoff.config.json` (resolved in that precedence order).
|
|
19
|
+
`handoff.config.*` - Defines the general handoff configuration. Supported files are `handoff.config.ts`, `handoff.config.js`, `handoff.config.cjs`, and `handoff.config.json` (resolved in that precedence order). Pass `-c, --config <file>` to load one specific file instead, resolved from the working directory (`HANDOFF_WORKING_PATH`, or the directory the command runs in).
|
|
20
20
|
`pages` - Markdown files that will create or customize pages in the documentation
|
|
21
21
|
app
|
|
22
22
|
`exportables` - JSON schemas for each component in your figma file that you
|
|
@@ -3,12 +3,14 @@ CREATE TABLE "page_files" (
|
|
|
3
3
|
"path" text NOT NULL,
|
|
4
4
|
"kind" text NOT NULL,
|
|
5
5
|
"content" text,
|
|
6
|
+
"body" text NOT NULL,
|
|
6
7
|
"storage_ref" text,
|
|
7
8
|
"content_type" text NOT NULL,
|
|
8
9
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
9
10
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
10
|
-
CONSTRAINT "
|
|
11
|
-
CONSTRAINT "
|
|
11
|
+
CONSTRAINT "page_files_page_id_pk" PRIMARY KEY("page_id"),
|
|
12
|
+
CONSTRAINT "page_files_kind_markdown" CHECK ("page_files"."kind" = 'markdown'),
|
|
13
|
+
CONSTRAINT "page_files_canonical_path" CHECK ("page_files"."path" = "page_files"."page_id" || '.md')
|
|
12
14
|
);
|
|
13
15
|
--> statement-breakpoint
|
|
14
16
|
CREATE TABLE "pages" (
|
|
@@ -25,4 +27,4 @@ CREATE TABLE "pages" (
|
|
|
25
27
|
);
|
|
26
28
|
--> statement-breakpoint
|
|
27
29
|
ALTER TABLE "page_files" ADD CONSTRAINT "page_files_page_id_pages_id_fk" FOREIGN KEY ("page_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
28
|
-
CREATE INDEX "pages_group_idx" ON "pages" USING btree ("group");
|
|
30
|
+
CREATE INDEX "pages_group_idx" ON "pages" USING btree ("group");
|
|
@@ -480,6 +480,12 @@
|
|
|
480
480
|
"primaryKey": false,
|
|
481
481
|
"notNull": false
|
|
482
482
|
},
|
|
483
|
+
"body": {
|
|
484
|
+
"name": "body",
|
|
485
|
+
"type": "text",
|
|
486
|
+
"primaryKey": false,
|
|
487
|
+
"notNull": true
|
|
488
|
+
},
|
|
483
489
|
"storage_ref": {
|
|
484
490
|
"name": "storage_ref",
|
|
485
491
|
"type": "text",
|
|
@@ -524,20 +530,23 @@
|
|
|
524
530
|
}
|
|
525
531
|
},
|
|
526
532
|
"compositePrimaryKeys": {
|
|
527
|
-
"
|
|
528
|
-
"name": "
|
|
533
|
+
"page_files_page_id_pk": {
|
|
534
|
+
"name": "page_files_page_id_pk",
|
|
529
535
|
"columns": [
|
|
530
|
-
"page_id"
|
|
531
|
-
"path"
|
|
536
|
+
"page_id"
|
|
532
537
|
]
|
|
533
538
|
}
|
|
534
539
|
},
|
|
535
540
|
"uniqueConstraints": {},
|
|
536
541
|
"policies": {},
|
|
537
542
|
"checkConstraints": {
|
|
538
|
-
"
|
|
539
|
-
"name": "
|
|
540
|
-
"value": "\"page_files\".\"kind\"
|
|
543
|
+
"page_files_kind_markdown": {
|
|
544
|
+
"name": "page_files_kind_markdown",
|
|
545
|
+
"value": "\"page_files\".\"kind\" = 'markdown'"
|
|
546
|
+
},
|
|
547
|
+
"page_files_canonical_path": {
|
|
548
|
+
"name": "page_files_canonical_path",
|
|
549
|
+
"value": "\"page_files\".\"path\" = \"page_files\".\"page_id\" || '.md'"
|
|
541
550
|
}
|
|
542
551
|
},
|
|
543
552
|
"isRLSEnabled": false
|
|
@@ -832,4 +841,4 @@
|
|
|
832
841
|
"schemas": {},
|
|
833
842
|
"tables": {}
|
|
834
843
|
}
|
|
835
|
-
}
|
|
844
|
+
}
|
|
@@ -480,6 +480,12 @@
|
|
|
480
480
|
"primaryKey": false,
|
|
481
481
|
"notNull": false
|
|
482
482
|
},
|
|
483
|
+
"body": {
|
|
484
|
+
"name": "body",
|
|
485
|
+
"type": "text",
|
|
486
|
+
"primaryKey": false,
|
|
487
|
+
"notNull": true
|
|
488
|
+
},
|
|
483
489
|
"storage_ref": {
|
|
484
490
|
"name": "storage_ref",
|
|
485
491
|
"type": "text",
|
|
@@ -524,20 +530,23 @@
|
|
|
524
530
|
}
|
|
525
531
|
},
|
|
526
532
|
"compositePrimaryKeys": {
|
|
527
|
-
"
|
|
528
|
-
"name": "
|
|
533
|
+
"page_files_page_id_pk": {
|
|
534
|
+
"name": "page_files_page_id_pk",
|
|
529
535
|
"columns": [
|
|
530
|
-
"page_id"
|
|
531
|
-
"path"
|
|
536
|
+
"page_id"
|
|
532
537
|
]
|
|
533
538
|
}
|
|
534
539
|
},
|
|
535
540
|
"uniqueConstraints": {},
|
|
536
541
|
"policies": {},
|
|
537
542
|
"checkConstraints": {
|
|
538
|
-
"
|
|
539
|
-
"name": "
|
|
540
|
-
"value": "\"page_files\".\"kind\"
|
|
543
|
+
"page_files_kind_markdown": {
|
|
544
|
+
"name": "page_files_kind_markdown",
|
|
545
|
+
"value": "\"page_files\".\"kind\" = 'markdown'"
|
|
546
|
+
},
|
|
547
|
+
"page_files_canonical_path": {
|
|
548
|
+
"name": "page_files_canonical_path",
|
|
549
|
+
"value": "\"page_files\".\"path\" = \"page_files\".\"page_id\" || '.md'"
|
|
541
550
|
}
|
|
542
551
|
},
|
|
543
552
|
"isRLSEnabled": false
|
|
@@ -1020,4 +1029,4 @@
|
|
|
1020
1029
|
"schemas": {},
|
|
1021
1030
|
"tables": {}
|
|
1022
1031
|
}
|
|
1023
|
-
}
|
|
1032
|
+
}
|
|
@@ -709,6 +709,12 @@
|
|
|
709
709
|
"primaryKey": false,
|
|
710
710
|
"notNull": false
|
|
711
711
|
},
|
|
712
|
+
"body": {
|
|
713
|
+
"name": "body",
|
|
714
|
+
"type": "text",
|
|
715
|
+
"primaryKey": false,
|
|
716
|
+
"notNull": true
|
|
717
|
+
},
|
|
712
718
|
"storage_ref": {
|
|
713
719
|
"name": "storage_ref",
|
|
714
720
|
"type": "text",
|
|
@@ -753,20 +759,23 @@
|
|
|
753
759
|
}
|
|
754
760
|
},
|
|
755
761
|
"compositePrimaryKeys": {
|
|
756
|
-
"
|
|
757
|
-
"name": "
|
|
762
|
+
"page_files_page_id_pk": {
|
|
763
|
+
"name": "page_files_page_id_pk",
|
|
758
764
|
"columns": [
|
|
759
|
-
"page_id"
|
|
760
|
-
"path"
|
|
765
|
+
"page_id"
|
|
761
766
|
]
|
|
762
767
|
}
|
|
763
768
|
},
|
|
764
769
|
"uniqueConstraints": {},
|
|
765
770
|
"policies": {},
|
|
766
771
|
"checkConstraints": {
|
|
767
|
-
"
|
|
768
|
-
"name": "
|
|
769
|
-
"value": "\"page_files\".\"kind\"
|
|
772
|
+
"page_files_kind_markdown": {
|
|
773
|
+
"name": "page_files_kind_markdown",
|
|
774
|
+
"value": "\"page_files\".\"kind\" = 'markdown'"
|
|
775
|
+
},
|
|
776
|
+
"page_files_canonical_path": {
|
|
777
|
+
"name": "page_files_canonical_path",
|
|
778
|
+
"value": "\"page_files\".\"path\" = \"page_files\".\"page_id\" || '.md'"
|
|
770
779
|
}
|
|
771
780
|
},
|
|
772
781
|
"isRLSEnabled": false
|
|
@@ -1249,4 +1258,4 @@
|
|
|
1249
1258
|
"schemas": {},
|
|
1250
1259
|
"tables": {}
|
|
1251
1260
|
}
|
|
1252
|
-
}
|
|
1261
|
+
}
|
|
@@ -709,6 +709,12 @@
|
|
|
709
709
|
"primaryKey": false,
|
|
710
710
|
"notNull": false
|
|
711
711
|
},
|
|
712
|
+
"body": {
|
|
713
|
+
"name": "body",
|
|
714
|
+
"type": "text",
|
|
715
|
+
"primaryKey": false,
|
|
716
|
+
"notNull": true
|
|
717
|
+
},
|
|
712
718
|
"storage_ref": {
|
|
713
719
|
"name": "storage_ref",
|
|
714
720
|
"type": "text",
|
|
@@ -753,20 +759,23 @@
|
|
|
753
759
|
}
|
|
754
760
|
},
|
|
755
761
|
"compositePrimaryKeys": {
|
|
756
|
-
"
|
|
757
|
-
"name": "
|
|
762
|
+
"page_files_page_id_pk": {
|
|
763
|
+
"name": "page_files_page_id_pk",
|
|
758
764
|
"columns": [
|
|
759
|
-
"page_id"
|
|
760
|
-
"path"
|
|
765
|
+
"page_id"
|
|
761
766
|
]
|
|
762
767
|
}
|
|
763
768
|
},
|
|
764
769
|
"uniqueConstraints": {},
|
|
765
770
|
"policies": {},
|
|
766
771
|
"checkConstraints": {
|
|
767
|
-
"
|
|
768
|
-
"name": "
|
|
769
|
-
"value": "\"page_files\".\"kind\"
|
|
772
|
+
"page_files_kind_markdown": {
|
|
773
|
+
"name": "page_files_kind_markdown",
|
|
774
|
+
"value": "\"page_files\".\"kind\" = 'markdown'"
|
|
775
|
+
},
|
|
776
|
+
"page_files_canonical_path": {
|
|
777
|
+
"name": "page_files_canonical_path",
|
|
778
|
+
"value": "\"page_files\".\"path\" = \"page_files\".\"page_id\" || '.md'"
|
|
770
779
|
}
|
|
771
780
|
},
|
|
772
781
|
"isRLSEnabled": false
|
|
@@ -1923,4 +1932,4 @@
|
|
|
1923
1932
|
"schemas": {},
|
|
1924
1933
|
"tables": {}
|
|
1925
1934
|
}
|
|
1926
|
-
}
|
|
1935
|
+
}
|