@crowi/api 2.0.0-alpha.1 → 2.0.0-alpha.2
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/dist/hono/handlers/activation.d.ts +3 -3
- package/dist/hono/handlers/admin/users.d.ts +118 -0
- package/dist/hono/handlers/admin/users.js +28 -0
- package/dist/hono/handlers/admin/users.js.map +1 -1
- package/dist/hono/handlers/app.d.ts +1 -0
- package/dist/hono/handlers/app.js +11 -0
- package/dist/hono/handlers/app.js.map +1 -1
- package/dist/hono/handlers/attachment-stream.js +23 -0
- package/dist/hono/handlers/attachment-stream.js.map +1 -1
- package/dist/hono/handlers/draft.js +10 -0
- package/dist/hono/handlers/draft.js.map +1 -1
- package/dist/hono/handlers/emailChange.d.ts +4 -4
- package/dist/hono/handlers/inviteAccept.d.ts +6 -6
- package/dist/hono/handlers/page.d.ts +251 -0
- package/dist/hono/handlers/page.js +123 -6
- package/dist/hono/handlers/page.js.map +1 -1
- package/dist/hono/handlers/passwordReset.d.ts +5 -5
- package/dist/hono/handlers/tokenAuth.d.ts +7 -7
- package/dist/mcp/result.d.ts +42 -16
- package/dist/mcp/result.js +56 -10
- package/dist/mcp/result.js.map +1 -1
- package/dist/mcp/tools/page.js +21 -1
- package/dist/mcp/tools/page.js.map +1 -1
- package/dist/mcp/tools/search.d.ts +12 -0
- package/dist/mcp/tools/search.js +21 -5
- package/dist/mcp/tools/search.js.map +1 -1
- package/dist/migration/helpers.d.ts +13 -0
- package/dist/migration/helpers.js +29 -0
- package/dist/migration/helpers.js.map +1 -0
- package/dist/migration/migrations/files-url-to-attachments.d.ts +35 -0
- package/dist/migration/migrations/files-url-to-attachments.js +291 -0
- package/dist/migration/migrations/files-url-to-attachments.js.map +1 -0
- package/dist/migration/migrations/index.js +4 -0
- package/dist/migration/migrations/index.js.map +1 -1
- package/dist/migration/migrations/published-current-revision.d.ts +47 -0
- package/dist/migration/migrations/published-current-revision.js +90 -0
- package/dist/migration/migrations/published-current-revision.js.map +1 -0
- package/dist/migration/migrations/wikilink-format.d.ts +0 -11
- package/dist/migration/migrations/wikilink-format.js +5 -156
- package/dist/migration/migrations/wikilink-format.js.map +1 -1
- package/dist/migration/migrations/wikilink-html-recover.d.ts +116 -0
- package/dist/migration/migrations/wikilink-html-recover.js +314 -0
- package/dist/migration/migrations/wikilink-html-recover.js.map +1 -0
- package/dist/models/page.d.ts +3 -0
- package/dist/models/page.js +31 -0
- package/dist/models/page.js.map +1 -1
- package/dist/models/user.d.ts +1 -0
- package/dist/models/user.js +40 -21
- package/dist/models/user.js.map +1 -1
- package/dist/renderer/core/headings.d.ts +12 -1
- package/dist/renderer/core/headings.js +48 -8
- package/dist/renderer/core/headings.js.map +1 -1
- package/dist/renderer/pipeline.d.ts +6 -0
- package/dist/renderer/pipeline.js.map +1 -1
- package/dist/util/page-response.js +19 -2
- package/dist/util/page-response.js.map +1 -1
- package/package.json +12 -6
- package/views/mail/layout.mjml +7 -5
- package/dist/common/functions/path2name.d.ts +0 -1
- package/dist/common/functions/path2name.js +0 -22
- package/dist/common/functions/path2name.js.map +0 -1
- package/dist/common/functions/renderIcon.d.ts +0 -1
- package/dist/common/functions/renderIcon.js +0 -9
- package/dist/common/functions/renderIcon.js.map +0 -1
- package/dist/controllers/admin.d.ts +0 -3
- package/dist/controllers/admin.js +0 -474
- package/dist/controllers/admin.js.map +0 -1
- package/dist/controllers/attachment.d.ts +0 -4
- package/dist/controllers/attachment.js +0 -200
- package/dist/controllers/attachment.js.map +0 -1
- package/dist/controllers/backlink.d.ts +0 -3
- package/dist/controllers/backlink.js +0 -42
- package/dist/controllers/backlink.js.map +0 -1
- package/dist/controllers/bookmark.d.ts +0 -3
- package/dist/controllers/bookmark.js +0 -100
- package/dist/controllers/bookmark.js.map +0 -1
- package/dist/controllers/comment.d.ts +0 -3
- package/dist/controllers/comment.js +0 -111
- package/dist/controllers/comment.js.map +0 -1
- package/dist/controllers/index.d.ts +0 -25
- package/dist/controllers/index.js +0 -44
- package/dist/controllers/index.js.map +0 -1
- package/dist/controllers/installer.d.ts +0 -3
- package/dist/controllers/installer.js +0 -48
- package/dist/controllers/installer.js.map +0 -1
- package/dist/controllers/login.d.ts +0 -4
- package/dist/controllers/login.js +0 -438
- package/dist/controllers/login.js.map +0 -1
- package/dist/controllers/logout.d.ts +0 -5
- package/dist/controllers/logout.js +0 -11
- package/dist/controllers/logout.js.map +0 -1
- package/dist/controllers/me.d.ts +0 -4
- package/dist/controllers/me.js +0 -369
- package/dist/controllers/me.js.map +0 -1
- package/dist/controllers/notification.d.ts +0 -3
- package/dist/controllers/notification.js +0 -88
- package/dist/controllers/notification.js.map +0 -1
- package/dist/controllers/page.d.ts +0 -3
- package/dist/controllers/page.js +0 -881
- package/dist/controllers/page.js.map +0 -1
- package/dist/controllers/revision.d.ts +0 -3
- package/dist/controllers/revision.js +0 -91
- package/dist/controllers/revision.js.map +0 -1
- package/dist/controllers/search.d.ts +0 -3
- package/dist/controllers/search.js +0 -93
- package/dist/controllers/search.js.map +0 -1
- package/dist/controllers/share.d.ts +0 -3
- package/dist/controllers/share.js +0 -207
- package/dist/controllers/share.js.map +0 -1
- package/dist/controllers/shareAccess.d.ts +0 -3
- package/dist/controllers/shareAccess.js +0 -28
- package/dist/controllers/shareAccess.js.map +0 -1
- package/dist/controllers/slack.d.ts +0 -3
- package/dist/controllers/slack.js +0 -87
- package/dist/controllers/slack.js.map +0 -1
- package/dist/controllers/tokenAuth.d.ts +0 -10
- package/dist/controllers/tokenAuth.js +0 -292
- package/dist/controllers/tokenAuth.js.map +0 -1
- package/dist/controllers/user.d.ts +0 -3
- package/dist/controllers/user.js +0 -67
- package/dist/controllers/user.js.map +0 -1
- package/dist/controllers/version.d.ts +0 -4
- package/dist/controllers/version.js +0 -19
- package/dist/controllers/version.js.map +0 -1
- package/dist/crowi/express-init.d.ts +0 -4
- package/dist/crowi/express-init.js +0 -101
- package/dist/crowi/express-init.js.map +0 -1
- package/dist/form/admin/app.d.ts +0 -2
- package/dist/form/admin/app.js +0 -9
- package/dist/form/admin/app.js.map +0 -1
- package/dist/form/admin/auth.d.ts +0 -2
- package/dist/form/admin/auth.js +0 -9
- package/dist/form/admin/auth.js.map +0 -1
- package/dist/form/admin/aws.d.ts +0 -2
- package/dist/form/admin/aws.js +0 -13
- package/dist/form/admin/aws.js.map +0 -1
- package/dist/form/admin/github.d.ts +0 -2
- package/dist/form/admin/github.js +0 -15
- package/dist/form/admin/github.js.map +0 -1
- package/dist/form/admin/google.d.ts +0 -2
- package/dist/form/admin/google.js +0 -13
- package/dist/form/admin/google.js.map +0 -1
- package/dist/form/admin/mail.d.ts +0 -2
- package/dist/form/admin/mail.js +0 -13
- package/dist/form/admin/mail.js.map +0 -1
- package/dist/form/admin/sec.d.ts +0 -2
- package/dist/form/admin/sec.js +0 -10
- package/dist/form/admin/sec.js.map +0 -1
- package/dist/form/admin/slackSetting.d.ts +0 -2
- package/dist/form/admin/slackSetting.js +0 -13
- package/dist/form/admin/slackSetting.js.map +0 -1
- package/dist/form/admin/userEdit.d.ts +0 -2
- package/dist/form/admin/userEdit.js +0 -9
- package/dist/form/admin/userEdit.js.map +0 -1
- package/dist/form/admin/userInvite.d.ts +0 -2
- package/dist/form/admin/userInvite.js +0 -9
- package/dist/form/admin/userInvite.js.map +0 -1
- package/dist/form/comment.d.ts +0 -2
- package/dist/form/comment.js +0 -9
- package/dist/form/comment.js.map +0 -1
- package/dist/form/index.d.ts +0 -25
- package/dist/form/index.js +0 -48
- package/dist/form/index.js.map +0 -1
- package/dist/form/invited.d.ts +0 -2
- package/dist/form/invited.js +0 -13
- package/dist/form/invited.js.map +0 -1
- package/dist/form/login.d.ts +0 -2
- package/dist/form/login.js +0 -11
- package/dist/form/login.js.map +0 -1
- package/dist/form/me/apiToken.d.ts +0 -2
- package/dist/form/me/apiToken.js +0 -9
- package/dist/form/me/apiToken.js.map +0 -1
- package/dist/form/me/password.d.ts +0 -2
- package/dist/form/me/password.js +0 -11
- package/dist/form/me/password.js.map +0 -1
- package/dist/form/me/user.d.ts +0 -2
- package/dist/form/me/user.js +0 -9
- package/dist/form/me/user.js.map +0 -1
- package/dist/form/register.d.ts +0 -2
- package/dist/form/register.js +0 -13
- package/dist/form/register.js.map +0 -1
- package/dist/form/revision.d.ts +0 -2
- package/dist/form/revision.js +0 -13
- package/dist/form/revision.js.map +0 -1
- package/dist/hono/handlers/admin/share.d.ts +0 -106
- package/dist/hono/handlers/admin/share.js +0 -55
- package/dist/hono/handlers/admin/share.js.map +0 -1
- package/dist/middlewares/accessTokenParser.d.ts +0 -4
- package/dist/middlewares/accessTokenParser.js +0 -29
- package/dist/middlewares/accessTokenParser.js.map +0 -1
- package/dist/middlewares/adminRequired.d.ts +0 -10
- package/dist/middlewares/adminRequired.js +0 -35
- package/dist/middlewares/adminRequired.js.map +0 -1
- package/dist/middlewares/applicationInstalled.d.ts +0 -3
- package/dist/middlewares/applicationInstalled.js +0 -20
- package/dist/middlewares/applicationInstalled.js.map +0 -1
- package/dist/middlewares/applicationNotInstalled.d.ts +0 -3
- package/dist/middlewares/applicationNotInstalled.js +0 -13
- package/dist/middlewares/applicationNotInstalled.js.map +0 -1
- package/dist/middlewares/basicAuth.d.ts +0 -4
- package/dist/middlewares/basicAuth.js +0 -23
- package/dist/middlewares/basicAuth.js.map +0 -1
- package/dist/middlewares/csrfVerify.d.ts +0 -4
- package/dist/middlewares/csrfVerify.js +0 -24
- package/dist/middlewares/csrfVerify.js.map +0 -1
- package/dist/middlewares/encodeSpace.d.ts +0 -3
- package/dist/middlewares/encodeSpace.js +0 -14
- package/dist/middlewares/encodeSpace.js.map +0 -1
- package/dist/middlewares/fileAccessRightOrLoginRequired.d.ts +0 -4
- package/dist/middlewares/fileAccessRightOrLoginRequired.js +0 -29
- package/dist/middlewares/fileAccessRightOrLoginRequired.js.map +0 -1
- package/dist/middlewares/index.d.ts +0 -16
- package/dist/middlewares/index.js +0 -30
- package/dist/middlewares/index.js.map +0 -1
- package/dist/middlewares/jwtAdminRequired.d.ts +0 -8
- package/dist/middlewares/jwtAdminRequired.js +0 -35
- package/dist/middlewares/jwtAdminRequired.js.map +0 -1
- package/dist/middlewares/jwtAuth.d.ts +0 -4
- package/dist/middlewares/jwtAuth.js +0 -104
- package/dist/middlewares/jwtAuth.js.map +0 -1
- package/dist/middlewares/loginChecker.d.ts +0 -4
- package/dist/middlewares/loginChecker.js +0 -32
- package/dist/middlewares/loginChecker.js.map +0 -1
- package/dist/middlewares/loginRequired.d.ts +0 -4
- package/dist/middlewares/loginRequired.js +0 -88
- package/dist/middlewares/loginRequired.js.map +0 -1
- package/dist/routes/admin.d.ts +0 -4
- package/dist/routes/admin.js +0 -17
- package/dist/routes/admin.js.map +0 -1
- package/dist/routes/api/admin.d.ts +0 -4
- package/dist/routes/api/admin.js +0 -37
- package/dist/routes/api/admin.js.map +0 -1
- package/dist/routes/api/attachment.d.ts +0 -4
- package/dist/routes/api/attachment.js +0 -19
- package/dist/routes/api/attachment.js.map +0 -1
- package/dist/routes/api/bookmark.d.ts +0 -4
- package/dist/routes/api/bookmark.js +0 -15
- package/dist/routes/api/bookmark.js.map +0 -1
- package/dist/routes/api/comment.d.ts +0 -4
- package/dist/routes/api/comment.js +0 -14
- package/dist/routes/api/comment.js.map +0 -1
- package/dist/routes/api/index.d.ts +0 -4
- package/dist/routes/api/index.js +0 -36
- package/dist/routes/api/index.js.map +0 -1
- package/dist/routes/api/like.d.ts +0 -4
- package/dist/routes/api/like.js +0 -13
- package/dist/routes/api/like.js.map +0 -1
- package/dist/routes/api/notification.d.ts +0 -4
- package/dist/routes/api/notification.js +0 -15
- package/dist/routes/api/notification.js.map +0 -1
- package/dist/routes/api/page.d.ts +0 -4
- package/dist/routes/api/page.js +0 -24
- package/dist/routes/api/page.js.map +0 -1
- package/dist/routes/api/revision.d.ts +0 -4
- package/dist/routes/api/revision.js +0 -14
- package/dist/routes/api/revision.js.map +0 -1
- package/dist/routes/api/share.d.ts +0 -4
- package/dist/routes/api/share.js +0 -16
- package/dist/routes/api/share.js.map +0 -1
- package/dist/routes/api/version.d.ts +0 -4
- package/dist/routes/api/version.js +0 -10
- package/dist/routes/api/version.js.map +0 -1
- package/dist/routes/index.d.ts +0 -4
- package/dist/routes/index.js +0 -71
- package/dist/routes/index.js.map +0 -1
- package/dist/routes/login.d.ts +0 -4
- package/dist/routes/login.js +0 -18
- package/dist/routes/login.js.map +0 -1
- package/dist/routes/me.d.ts +0 -4
- package/dist/routes/me.js +0 -24
- package/dist/routes/me.js.map +0 -1
- package/dist/routes/ts-rest/admin/app.d.ts +0 -4
- package/dist/routes/ts-rest/admin/app.js +0 -67
- package/dist/routes/ts-rest/admin/app.js.map +0 -1
- package/dist/routes/ts-rest/admin/auth.d.ts +0 -4
- package/dist/routes/ts-rest/admin/auth.js +0 -95
- package/dist/routes/ts-rest/admin/auth.js.map +0 -1
- package/dist/routes/ts-rest/admin/index.d.ts +0 -10
- package/dist/routes/ts-rest/admin/index.js +0 -35
- package/dist/routes/ts-rest/admin/index.js.map +0 -1
- package/dist/routes/ts-rest/admin/mail.d.ts +0 -4
- package/dist/routes/ts-rest/admin/mail.js +0 -156
- package/dist/routes/ts-rest/admin/mail.js.map +0 -1
- package/dist/routes/ts-rest/admin/plugins.d.ts +0 -4
- package/dist/routes/ts-rest/admin/plugins.js +0 -317
- package/dist/routes/ts-rest/admin/plugins.js.map +0 -1
- package/dist/routes/ts-rest/admin/search.d.ts +0 -4
- package/dist/routes/ts-rest/admin/search.js +0 -67
- package/dist/routes/ts-rest/admin/search.js.map +0 -1
- package/dist/routes/ts-rest/admin/security.d.ts +0 -4
- package/dist/routes/ts-rest/admin/security.js +0 -114
- package/dist/routes/ts-rest/admin/security.js.map +0 -1
- package/dist/routes/ts-rest/admin/share.d.ts +0 -4
- package/dist/routes/ts-rest/admin/share.js +0 -69
- package/dist/routes/ts-rest/admin/share.js.map +0 -1
- package/dist/routes/ts-rest/admin/storage.d.ts +0 -4
- package/dist/routes/ts-rest/admin/storage.js +0 -59
- package/dist/routes/ts-rest/admin/storage.js.map +0 -1
- package/dist/routes/ts-rest/admin/users.d.ts +0 -4
- package/dist/routes/ts-rest/admin/users.js +0 -215
- package/dist/routes/ts-rest/admin/users.js.map +0 -1
- package/dist/routes/ts-rest/adminCrypto.d.ts +0 -4
- package/dist/routes/ts-rest/adminCrypto.js +0 -111
- package/dist/routes/ts-rest/adminCrypto.js.map +0 -1
- package/dist/routes/ts-rest/app.d.ts +0 -4
- package/dist/routes/ts-rest/app.js +0 -23
- package/dist/routes/ts-rest/app.js.map +0 -1
- package/dist/routes/ts-rest/attachment.d.ts +0 -4
- package/dist/routes/ts-rest/attachment.js +0 -830
- package/dist/routes/ts-rest/attachment.js.map +0 -1
- package/dist/routes/ts-rest/auth.d.ts +0 -4
- package/dist/routes/ts-rest/auth.js +0 -70
- package/dist/routes/ts-rest/auth.js.map +0 -1
- package/dist/routes/ts-rest/autocomplete.d.ts +0 -30
- package/dist/routes/ts-rest/autocomplete.js +0 -189
- package/dist/routes/ts-rest/autocomplete.js.map +0 -1
- package/dist/routes/ts-rest/backlink.d.ts +0 -4
- package/dist/routes/ts-rest/backlink.js +0 -106
- package/dist/routes/ts-rest/backlink.js.map +0 -1
- package/dist/routes/ts-rest/bookmark.d.ts +0 -4
- package/dist/routes/ts-rest/bookmark.js +0 -189
- package/dist/routes/ts-rest/bookmark.js.map +0 -1
- package/dist/routes/ts-rest/comment.d.ts +0 -4
- package/dist/routes/ts-rest/comment.js +0 -217
- package/dist/routes/ts-rest/comment.js.map +0 -1
- package/dist/routes/ts-rest/draft.d.ts +0 -22
- package/dist/routes/ts-rest/draft.js +0 -200
- package/dist/routes/ts-rest/draft.js.map +0 -1
- package/dist/routes/ts-rest/index.d.ts +0 -4
- package/dist/routes/ts-rest/index.js +0 -103
- package/dist/routes/ts-rest/index.js.map +0 -1
- package/dist/routes/ts-rest/installer.d.ts +0 -4
- package/dist/routes/ts-rest/installer.js +0 -77
- package/dist/routes/ts-rest/installer.js.map +0 -1
- package/dist/routes/ts-rest/me.d.ts +0 -4
- package/dist/routes/ts-rest/me.js +0 -410
- package/dist/routes/ts-rest/me.js.map +0 -1
- package/dist/routes/ts-rest/notification.d.ts +0 -4
- package/dist/routes/ts-rest/notification.js +0 -241
- package/dist/routes/ts-rest/notification.js.map +0 -1
- package/dist/routes/ts-rest/page-collab.d.ts +0 -29
- package/dist/routes/ts-rest/page-collab.js +0 -90
- package/dist/routes/ts-rest/page-collab.js.map +0 -1
- package/dist/routes/ts-rest/page-preview.d.ts +0 -26
- package/dist/routes/ts-rest/page-preview.js +0 -80
- package/dist/routes/ts-rest/page-preview.js.map +0 -1
- package/dist/routes/ts-rest/page.d.ts +0 -4
- package/dist/routes/ts-rest/page.js +0 -676
- package/dist/routes/ts-rest/page.js.map +0 -1
- package/dist/routes/ts-rest/presence.d.ts +0 -30
- package/dist/routes/ts-rest/presence.js +0 -155
- package/dist/routes/ts-rest/presence.js.map +0 -1
- package/dist/routes/ts-rest/revision.d.ts +0 -4
- package/dist/routes/ts-rest/revision.js +0 -240
- package/dist/routes/ts-rest/revision.js.map +0 -1
- package/dist/routes/ts-rest/search.d.ts +0 -4
- package/dist/routes/ts-rest/search.js +0 -121
- package/dist/routes/ts-rest/search.js.map +0 -1
- package/dist/routes/ts-rest/tokenAuth.d.ts +0 -4
- package/dist/routes/ts-rest/tokenAuth.js +0 -94
- package/dist/routes/ts-rest/tokenAuth.js.map +0 -1
- package/dist/routes/ts-rest/user.d.ts +0 -4
- package/dist/routes/ts-rest/user.js +0 -307
- package/dist/routes/ts-rest/user.js.map +0 -1
- package/dist/types/express.d.ts +0 -34
- package/dist/types/express.js +0 -50
- package/dist/types/express.js.map +0 -1
- package/dist/util/accessTokenParser.d.ts +0 -1
- package/dist/util/accessTokenParser.js +0 -34
- package/dist/util/accessTokenParser.js.map +0 -1
- package/dist/util/apiPaginate.d.ts +0 -11
- package/dist/util/apiPaginate.js +0 -33
- package/dist/util/apiPaginate.js.map +0 -1
- package/dist/util/apiResponse.d.ts +0 -9
- package/dist/util/apiResponse.js +0 -23
- package/dist/util/apiResponse.js.map +0 -1
- package/dist/util/auth.d.ts +0 -11
- package/dist/util/auth.js +0 -48
- package/dist/util/auth.js.map +0 -1
- package/dist/util/aws-config-migration.d.ts +0 -11
- package/dist/util/aws-config-migration.js +0 -68
- package/dist/util/aws-config-migration.js.map +0 -1
- package/dist/util/formUtil.d.ts +0 -2
- package/dist/util/formUtil.js +0 -15
- package/dist/util/formUtil.js.map +0 -1
- package/dist/util/githubAuth.d.ts +0 -2
- package/dist/util/githubAuth.js +0 -82
- package/dist/util/githubAuth.js.map +0 -1
- package/dist/util/googleAuth.d.ts +0 -2
- package/dist/util/googleAuth.js +0 -85
- package/dist/util/googleAuth.js.map +0 -1
- package/dist/util/mailer.d.ts +0 -7
- package/dist/util/mailer.js +0 -98
- package/dist/util/mailer.js.map +0 -1
- package/dist/util/page-status-migration.d.ts +0 -23
- package/dist/util/page-status-migration.js +0 -48
- package/dist/util/page-status-migration.js.map +0 -1
- package/dist/util/ssr.d.ts +0 -3
- package/dist/util/ssr.js +0 -9
- package/dist/util/ssr.js.map +0 -1
- package/dist/util/view.d.ts +0 -10
- package/dist/util/view.js +0 -99
- package/dist/util/view.js.map +0 -1
package/dist/mcp/tools/search.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.searchTools = void 0;
|
|
3
|
+
exports.searchTools = exports.mapSearchResult = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* RFC-0011 §8 — search tool catalog.
|
|
6
6
|
*
|
|
@@ -10,17 +10,33 @@ exports.searchTools = void 0;
|
|
|
10
10
|
*/
|
|
11
11
|
const api_contract_1 = require("@crowi/api-contract");
|
|
12
12
|
const result_1 = require("../result");
|
|
13
|
+
/**
|
|
14
|
+
* RFC-0011 §10.7 — a search snippet is a body excerpt = user-generated and
|
|
15
|
+
* untrusted, so it carries the same injection risk as a full page body. The
|
|
16
|
+
* path / count / pager around it are server-generated metadata and stay
|
|
17
|
+
* plain. We fence the snippets (not the whole line) so a single
|
|
18
|
+
* `wrapUntrusted` notice + nonce covers every snippet in the response while
|
|
19
|
+
* the structural `- <path>` scaffolding the model needs to act on stays
|
|
20
|
+
* outside the data region. The `structuredContent.data` array is left raw but
|
|
21
|
+
* flagged `trust: 'untrusted'` (parallel to `okResultWithBody`'s raw +
|
|
22
|
+
* flagged `structuredContent.body`).
|
|
23
|
+
*/
|
|
13
24
|
const mapSearchResult = (body) => {
|
|
14
25
|
const env = body;
|
|
15
26
|
const data = env.data ?? [];
|
|
27
|
+
// One nonce per response (see okResultWithBody): an attacker cannot guess
|
|
28
|
+
// it, so a forged close tag inside a snippet cannot break out of its fence.
|
|
29
|
+
const nonce = (0, result_1.generateNonce)();
|
|
16
30
|
const lines = data.map((hit) => {
|
|
17
|
-
const
|
|
18
|
-
|
|
31
|
+
const line = `- ${String(hit.path)}`;
|
|
32
|
+
const snippet = typeof hit.snippet === 'string' ? hit.snippet.replace(/\s+/g, ' ').trim() : '';
|
|
33
|
+
return snippet ? `${line} — ${(0, result_1.wrapUntrusted)(snippet, nonce)}` : line;
|
|
19
34
|
});
|
|
20
35
|
const total = env.meta?.total ?? data.length;
|
|
21
36
|
const text = data.length ? `${total} match(es) (showing ${data.length}):\n${lines.join('\n')}` : 'No matching pages.';
|
|
22
|
-
return (0, result_1.okResult)(text, { data, meta: env.meta });
|
|
37
|
+
return (0, result_1.okResult)(text, { data, trust: 'untrusted', meta: env.meta });
|
|
23
38
|
};
|
|
39
|
+
exports.mapSearchResult = mapSearchResult;
|
|
24
40
|
exports.searchTools = [
|
|
25
41
|
{
|
|
26
42
|
name: 'crowi_search_pages',
|
|
@@ -30,7 +46,7 @@ exports.searchTools = [
|
|
|
30
46
|
schema: api_contract_1.SearchPagesRequestSchema.shape,
|
|
31
47
|
kind: 'query',
|
|
32
48
|
scope: 'pages:read',
|
|
33
|
-
resultMapper: mapSearchResult,
|
|
49
|
+
resultMapper: exports.mapSearchResult,
|
|
34
50
|
},
|
|
35
51
|
];
|
|
36
52
|
//# sourceMappingURL=search.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/mcp/tools/search.ts"],"names":[],"mappings":";;;AAAA;;;;;;GAMG;AACH,sDAA+D;
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/mcp/tools/search.ts"],"names":[],"mappings":";;;AAAA;;;;;;GAMG;AACH,sDAA+D;AAC/D,sCAAmE;AAKnE;;;;;;;;;;GAUG;AACI,MAAM,eAAe,GAAG,CAAC,IAAa,EAAE,EAAE;IAC/C,MAAM,GAAG,GAAG,IAA2C,CAAC;IACxD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IAC5B,0EAA0E;IAC1E,4EAA4E;IAC5E,MAAM,KAAK,GAAG,IAAA,sBAAa,GAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/F,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,IAAA,sBAAa,EAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACvE,CAAC,CAAC,CAAC;IACH,MAAM,KAAK,GAAI,GAAG,CAAC,IAAuC,EAAE,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC;IACjF,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,uBAAuB,IAAI,CAAC,MAAM,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC;IACtH,OAAO,IAAA,iBAAQ,EAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC;AAdW,QAAA,eAAe,mBAc1B;AAEW,QAAA,WAAW,GAAqB;IAC3C;QACE,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EACT,yKAAyK;QAC3K,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,uCAAwB,CAAC,KAAK;QACtC,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,YAAY;QACnB,YAAY,EAAE,uBAAe;KAC9B;CACF,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MigrationContext } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the user id to credit a preflight migration's body rewrites to:
|
|
4
|
+
* 1. `CROWI_MIGRATE_USER=<email>` if set,
|
|
5
|
+
* 2. otherwise the oldest admin (`{ admin: true }` by `createdAt`).
|
|
6
|
+
*
|
|
7
|
+
* Throws with `migrationName` in the message when neither yields a user, so the
|
|
8
|
+
* operator sees which migration tripped instead of a per-page `user should have
|
|
9
|
+
* _id` failure deep inside the rewrite. Used by every preflight migration that
|
|
10
|
+
* pushes new revisions on the operator's behalf (`wikilink-format`,
|
|
11
|
+
* `files-url-to-attachments`, …).
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveActingUserId(ctx: MigrationContext, migrationName: string): Promise<string>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveActingUserId = resolveActingUserId;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the user id to credit a preflight migration's body rewrites to:
|
|
6
|
+
* 1. `CROWI_MIGRATE_USER=<email>` if set,
|
|
7
|
+
* 2. otherwise the oldest admin (`{ admin: true }` by `createdAt`).
|
|
8
|
+
*
|
|
9
|
+
* Throws with `migrationName` in the message when neither yields a user, so the
|
|
10
|
+
* operator sees which migration tripped instead of a per-page `user should have
|
|
11
|
+
* _id` failure deep inside the rewrite. Used by every preflight migration that
|
|
12
|
+
* pushes new revisions on the operator's behalf (`wikilink-format`,
|
|
13
|
+
* `files-url-to-attachments`, …).
|
|
14
|
+
*/
|
|
15
|
+
async function resolveActingUserId(ctx, migrationName) {
|
|
16
|
+
const User = ctx.crowi.model('User');
|
|
17
|
+
const explicit = process.env.CROWI_MIGRATE_USER;
|
|
18
|
+
if (explicit) {
|
|
19
|
+
const named = await User.findOne({ email: explicit }).select('_id').lean().exec();
|
|
20
|
+
if (named)
|
|
21
|
+
return String(named._id);
|
|
22
|
+
throw new Error(`CROWI_MIGRATE_USER='${explicit}' but no user with that email exists.`);
|
|
23
|
+
}
|
|
24
|
+
const admin = await User.findOne({ admin: true }).sort({ createdAt: 1 }).select('_id').lean().exec();
|
|
25
|
+
if (admin)
|
|
26
|
+
return String(admin._id);
|
|
27
|
+
throw new Error(`${migrationName}: no admin user found; set CROWI_MIGRATE_USER=<email> or create an admin user first.`);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/migration/helpers.ts"],"names":[],"mappings":";;AAaA,kDAWC;AAtBD;;;;;;;;;;GAUG;AACI,KAAK,UAAU,mBAAmB,CAAC,GAAqB,EAAE,aAAqB;IACpF,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAChD,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;QAClF,IAAI,KAAK;YAAE,OAAO,MAAM,CAAE,KAA0B,CAAC,GAAG,CAAC,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,uCAAuC,CAAC,CAAC;IAC1F,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;IACrG,IAAI,KAAK;QAAE,OAAO,MAAM,CAAE,KAA0B,CAAC,GAAG,CAAC,CAAC;IAC1D,MAAM,IAAI,KAAK,CAAC,GAAG,aAAa,sFAAsF,CAAC,CAAC;AAC1H,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-body breakdown of what a rewrite touched / skipped, returned alongside
|
|
3
|
+
* the rewritten body so callers walk the regex once.
|
|
4
|
+
* - `relative`: rule 1 (relative `/files/<id>`) rewrites.
|
|
5
|
+
* - `selfHostAbsolute`: rule 2 (self-host absolute) rewrites.
|
|
6
|
+
* - `externalSkipped`: rule 3 (external absolute) left untouched.
|
|
7
|
+
*/
|
|
8
|
+
export interface FilesUrlRewriteCounts {
|
|
9
|
+
relative: number;
|
|
10
|
+
selfHostAbsolute: number;
|
|
11
|
+
externalSkipped: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Single-pass detect-and-rewrite. Returns the rewritten body plus a count
|
|
15
|
+
* breakdown so callers don't walk the regex twice. Pure — no I/O. Returns
|
|
16
|
+
* `body` by reference when nothing changed (no rule-1/2 rewrite), letting
|
|
17
|
+
* callers cheap-skip via `result.body === body`.
|
|
18
|
+
*
|
|
19
|
+
* `origins` is the self-host allow-list (`getAppOrigins()`); pass `[]` to
|
|
20
|
+
* disable rule 2 (CLIENT_URL / BASE_URL unset).
|
|
21
|
+
*/
|
|
22
|
+
export declare function rewriteFilesUrls(body: string, origins: readonly string[]): {
|
|
23
|
+
body: string;
|
|
24
|
+
counts: FilesUrlRewriteCounts;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* True iff `body` holds at least one *rewritable* v1 file URL — a relative
|
|
28
|
+
* `/files/<id>` or a self-host absolute one (external-only bodies report
|
|
29
|
+
* false). `/files/` is a cheap prefilter so bodies that can't contain one skip
|
|
30
|
+
* the regex; the verdict itself is the full rule (external skips don't count)
|
|
31
|
+
* so a body whose only `/files/<id>` is external correctly reports false.
|
|
32
|
+
* Shared by `isPending` and `collectRewritablePages`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function bodyHasRewritableFilesUrl(body: string, origins: readonly string[]): boolean;
|
|
35
|
+
export declare const filesUrlToAttachments: import("../types").MigrationDefinition;
|
|
@@ -0,0 +1,291 @@
|
|
|
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.filesUrlToAttachments = void 0;
|
|
7
|
+
exports.rewriteFilesUrls = rewriteFilesUrls;
|
|
8
|
+
exports.bodyHasRewritableFilesUrl = bodyHasRewritableFilesUrl;
|
|
9
|
+
const linkDetector_1 = __importDefault(require("../../util/linkDetector"));
|
|
10
|
+
const page_1 = require("../../models/page");
|
|
11
|
+
const helpers_1 = require("../helpers");
|
|
12
|
+
const types_1 = require("../types");
|
|
13
|
+
/**
|
|
14
|
+
* v1 → v2 — `files-url-to-attachments` (preflight layer).
|
|
15
|
+
*
|
|
16
|
+
* v1 embedded attachment / image references in page bodies as the v1 file
|
|
17
|
+
* URL `/files/<24hex>` (absolute `https://<host>/files/<id>` when the editor
|
|
18
|
+
* pasted a full URL, or relative `/files/<id>`). v2 serves attachments from a
|
|
19
|
+
* dedicated stream route at `/api/v2/attachments/<id>` and the legacy
|
|
20
|
+
* `/files/<id>` compat redirect was removed with the Express host (RFC-0006
|
|
21
|
+
* Phase 6 Sub-batch D), so those v1 URLs now 404 — every such image is
|
|
22
|
+
* broken. The id is identical in both forms (the same 24-hex `Attachment._id`;
|
|
23
|
+
* `attachment.ts` `ATTACHMENT_URI_RE` extracts the same id from either), so the
|
|
24
|
+
* fix is a pure URL rewrite — no id mapping.
|
|
25
|
+
*
|
|
26
|
+
* Modelled on `wikilink-format.ts` (the sibling v1→v2 body-rewrite preflight):
|
|
27
|
+
* walk published (+ legacy `null`) pages, rewrite each current-revision body
|
|
28
|
+
* with a single-pass detect-and-rewrite, route every write through
|
|
29
|
+
* `ctx.rewritePageBody` (the `updatePage`-equivalent path that nulls
|
|
30
|
+
* `yjsState` / `yjsCheckpointAt` so an active editor can't revert the rewrite
|
|
31
|
+
* from a stale `Y.Doc` — see wikilink-format §4.3.1), and use a cheap
|
|
32
|
+
* substring prefilter (`/files/`) before the detail regex in `isPending`.
|
|
33
|
+
*
|
|
34
|
+
* Rewrite rules (Markdown `` images and `[text](url)` links only —
|
|
35
|
+
* raw HTML `<img src>` / `<a href>` is out of scope; v1 emitted Markdown):
|
|
36
|
+
*
|
|
37
|
+
* 1. relative `/files/<id>` → `/api/v2/attachments/<id>`
|
|
38
|
+
* (unconditional — a root-relative path is always this site).
|
|
39
|
+
* 2. self-host absolute `https://<origin>/files/<id>`
|
|
40
|
+
* → `/api/v2/attachments/<id>`
|
|
41
|
+
* (relativised — drops the host so the URL is portable). `<origin>` must
|
|
42
|
+
* match `linkDetector.getAppOrigins()` (CLIENT_URL / BASE_URL).
|
|
43
|
+
* 3. external absolute `https://other/files/<id>` → left untouched
|
|
44
|
+
* (we must not rewrite an unrelated third-party `/files/<id>` image).
|
|
45
|
+
*
|
|
46
|
+
* Host moves (v1 domain ≠ v2 domain) are out of scope: the separate `replace
|
|
47
|
+
* url` admin-cli command rewrites the old host → new host first, after which
|
|
48
|
+
* the self-host absolute URLs match CLIENT_URL and rule 2 relativises them.
|
|
49
|
+
*
|
|
50
|
+
* Idempotent: the output `/api/v2/attachments/<id>` never matches the
|
|
51
|
+
* `/files/` regex, so a re-apply is a no-op (no double rewrite).
|
|
52
|
+
*
|
|
53
|
+
* CLIENT_URL / BASE_URL unset: `getAppOrigins()` returns `[]`, so the
|
|
54
|
+
* self-host alternation is empty and rule 2 is skipped — only relative
|
|
55
|
+
* `/files/<id>` (rule 1) is rewritten and absolute URLs are left alone.
|
|
56
|
+
*/
|
|
57
|
+
/** v2 attachment URL prefix the rewrite targets. */
|
|
58
|
+
const V2_ATTACHMENT_PREFIX = '/api/v2/attachments/';
|
|
59
|
+
/**
|
|
60
|
+
* Substring that necessarily precedes every rewritable v1 file URL: `/files/`.
|
|
61
|
+
* Cheapest probe guaranteed present whenever a real `/files/<id>` reference
|
|
62
|
+
* exists, so a body without it can skip the regex entirely (no false
|
|
63
|
+
* negatives). The actual verdict still applies the full detect rule — see
|
|
64
|
+
* `bodyHasRewritableFilesUrl`.
|
|
65
|
+
*/
|
|
66
|
+
const FILES_SUBSTRING_PROBE = '/files/';
|
|
67
|
+
const emptyCounts = () => ({ relative: 0, selfHostAbsolute: 0, externalSkipped: 0 });
|
|
68
|
+
/**
|
|
69
|
+
* Build the per-body rewrite regex. It matches a Markdown image/link whose URL
|
|
70
|
+
* payload points at `/files/<24hex>` in one of two forms:
|
|
71
|
+
*
|
|
72
|
+
* - relative: the URL part starts with `/files/<id>`
|
|
73
|
+
* - absolute: the URL part is `<scheme>://<host>.../files/<id>`
|
|
74
|
+
*
|
|
75
|
+
* The `![alt]` / `[text]` head and the trailing path/query/fragment after the
|
|
76
|
+
* id are captured verbatim and re-emitted unchanged; only the host + `/files/`
|
|
77
|
+
* → `/api/v2/attachments/` portion is rewritten. Self-host classification of
|
|
78
|
+
* absolute URLs is decided in the callback (not the regex) so external hosts
|
|
79
|
+
* fall through untouched.
|
|
80
|
+
*
|
|
81
|
+
* A fresh `RegExp` per call keeps `lastIndex` state local (the regex is `g`).
|
|
82
|
+
*/
|
|
83
|
+
function buildFilesUrlRegex() {
|
|
84
|
+
// Group layout:
|
|
85
|
+
// 1: the markdown head `![alt]` or `[text]` (incl. the leading `!` if image)
|
|
86
|
+
// 2: optional `<scheme>://<host>` for an absolute URL (undefined when relative)
|
|
87
|
+
// 3: the 24-hex attachment id
|
|
88
|
+
// 4: the trailing remainder inside the parens after the id (path/query/#),
|
|
89
|
+
// excluding the closing `)` and whitespace
|
|
90
|
+
return /(!?\[[^\]]*\])\((https?:\/\/[^\s)/]+)?\/files\/([0-9a-fA-F]{24})([^\s)]*)\)/g;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Decide whether an absolute URL's `<scheme>://<host>` prefix belongs to this
|
|
94
|
+
* Crowi instance. `origins` are the normalised `getAppOrigins()` values
|
|
95
|
+
* (trailing slash trimmed). A match means the URL is self-host and should be
|
|
96
|
+
* relativised (rule 2); a non-match is external and left untouched (rule 3).
|
|
97
|
+
*
|
|
98
|
+
* The match is exact against the captured `<scheme>://<host>` (no path), so
|
|
99
|
+
* `https://wiki.example.com` matches origin `https://wiki.example.com` but not
|
|
100
|
+
* `https://evil.example.com`.
|
|
101
|
+
*/
|
|
102
|
+
function isSelfHostOrigin(schemeAndHost, origins) {
|
|
103
|
+
return origins.includes(schemeAndHost);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Single-pass detect-and-rewrite. Returns the rewritten body plus a count
|
|
107
|
+
* breakdown so callers don't walk the regex twice. Pure — no I/O. Returns
|
|
108
|
+
* `body` by reference when nothing changed (no rule-1/2 rewrite), letting
|
|
109
|
+
* callers cheap-skip via `result.body === body`.
|
|
110
|
+
*
|
|
111
|
+
* `origins` is the self-host allow-list (`getAppOrigins()`); pass `[]` to
|
|
112
|
+
* disable rule 2 (CLIENT_URL / BASE_URL unset).
|
|
113
|
+
*/
|
|
114
|
+
function rewriteFilesUrls(body, origins) {
|
|
115
|
+
const counts = emptyCounts();
|
|
116
|
+
const rewritten = body.replace(buildFilesUrlRegex(), (whole, head, schemeAndHost, id, rest) => {
|
|
117
|
+
if (schemeAndHost === undefined) {
|
|
118
|
+
// Rule 1 — relative `/files/<id>` is unconditionally this site.
|
|
119
|
+
counts.relative += 1;
|
|
120
|
+
return `${head}(${V2_ATTACHMENT_PREFIX}${id}${rest})`;
|
|
121
|
+
}
|
|
122
|
+
if (isSelfHostOrigin(schemeAndHost, origins)) {
|
|
123
|
+
// Rule 2 — self-host absolute URL; relativise (drop the host).
|
|
124
|
+
counts.selfHostAbsolute += 1;
|
|
125
|
+
return `${head}(${V2_ATTACHMENT_PREFIX}${id}${rest})`;
|
|
126
|
+
}
|
|
127
|
+
// Rule 3 — external host; leave untouched.
|
|
128
|
+
counts.externalSkipped += 1;
|
|
129
|
+
return whole;
|
|
130
|
+
});
|
|
131
|
+
const changed = counts.relative > 0 || counts.selfHostAbsolute > 0;
|
|
132
|
+
return { body: changed ? rewritten : body, counts };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* True iff `body` holds at least one *rewritable* v1 file URL — a relative
|
|
136
|
+
* `/files/<id>` or a self-host absolute one (external-only bodies report
|
|
137
|
+
* false). `/files/` is a cheap prefilter so bodies that can't contain one skip
|
|
138
|
+
* the regex; the verdict itself is the full rule (external skips don't count)
|
|
139
|
+
* so a body whose only `/files/<id>` is external correctly reports false.
|
|
140
|
+
* Shared by `isPending` and `collectRewritablePages`.
|
|
141
|
+
*/
|
|
142
|
+
function bodyHasRewritableFilesUrl(body, origins) {
|
|
143
|
+
if (!body.includes(FILES_SUBSTRING_PROBE))
|
|
144
|
+
return false;
|
|
145
|
+
const { counts } = rewriteFilesUrls(body, origins);
|
|
146
|
+
return counts.relative > 0 || counts.selfHostAbsolute > 0;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The self-host origins for the current instance, via the same
|
|
150
|
+
* `linkDetector.getAppOrigins()` helper backlink classification uses
|
|
151
|
+
* (CLIENT_URL + BASE_URL, trailing slash trimmed, deduped). Returns `[]` when
|
|
152
|
+
* neither is configured — rule 2 is then disabled (relative-only rewrite).
|
|
153
|
+
*/
|
|
154
|
+
function resolveAppOrigins(ctx) {
|
|
155
|
+
return (0, linkDetector_1.default)(ctx.crowi).getAppOrigins();
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* One full scan of every published (+ legacy `null`) page (trash & deprecated
|
|
159
|
+
* are read-only fixtures — same scope as `wikilink-format`). Returns:
|
|
160
|
+
* - `rewritable`: the pages that actually change (≥1 relative / self-host
|
|
161
|
+
* rewrite), each with its rewritten body for `ctx.rewritePageBody`.
|
|
162
|
+
* - `totals`: the rewrite breakdown aggregated across **every** page with a
|
|
163
|
+
* `/files/` reference (so `externalSkipped` reflects external URLs even on
|
|
164
|
+
* pages with no rewritable URL — an operator signal for "why some /files/
|
|
165
|
+
* references remain").
|
|
166
|
+
* Stream-walks so memory stays constant on large installs.
|
|
167
|
+
*/
|
|
168
|
+
async function scanFilesUrls(ctx, origins) {
|
|
169
|
+
const Page = ctx.crowi.model('Page');
|
|
170
|
+
const Revision = ctx.crowi.model('Revision');
|
|
171
|
+
const rewritable = [];
|
|
172
|
+
const totals = emptyCounts();
|
|
173
|
+
const cursor = Page.find({ $or: [{ status: page_1.STATUS_PUBLISHED }, { status: null }] })
|
|
174
|
+
.select('_id revision')
|
|
175
|
+
.lean()
|
|
176
|
+
.cursor();
|
|
177
|
+
for await (const page of cursor) {
|
|
178
|
+
const pageDoc = page;
|
|
179
|
+
if (!pageDoc.revision)
|
|
180
|
+
continue;
|
|
181
|
+
const revision = await Revision.findById(pageDoc.revision).select('body').lean().exec();
|
|
182
|
+
const body = revision?.body;
|
|
183
|
+
if (typeof body !== 'string')
|
|
184
|
+
continue;
|
|
185
|
+
if (!body.includes(FILES_SUBSTRING_PROBE))
|
|
186
|
+
continue;
|
|
187
|
+
const result = rewriteFilesUrls(body, origins);
|
|
188
|
+
totals.relative += result.counts.relative;
|
|
189
|
+
totals.selfHostAbsolute += result.counts.selfHostAbsolute;
|
|
190
|
+
totals.externalSkipped += result.counts.externalSkipped;
|
|
191
|
+
if (result.body === body)
|
|
192
|
+
continue;
|
|
193
|
+
rewritable.push({ pageId: String(pageDoc._id), newBody: result.body, counts: result.counts });
|
|
194
|
+
}
|
|
195
|
+
return { rewritable, totals };
|
|
196
|
+
}
|
|
197
|
+
exports.filesUrlToAttachments = (0, types_1.defineMigration)({
|
|
198
|
+
id: 'files-url-to-attachments',
|
|
199
|
+
fromVersion: '1.x',
|
|
200
|
+
toVersion: '2.1',
|
|
201
|
+
layer: 'preflight',
|
|
202
|
+
description: 'Rewrite v1 /files/<id> attachment URLs to v2 /api/v2/attachments/<id>',
|
|
203
|
+
/**
|
|
204
|
+
* Pending verdict = at least one published page whose **current** revision
|
|
205
|
+
* body still contains a rewritable v1 file URL. Mirrors `wikilink-format`:
|
|
206
|
+
*
|
|
207
|
+
* 1. The verdict uses the **full rule** (`bodyHasRewritableFilesUrl`), not
|
|
208
|
+
* the bare substring. `/files/` could appear in an external URL we leave
|
|
209
|
+
* alone (rule 3); counting that would report pending forever after apply
|
|
210
|
+
* (apply only rewrites self URLs), deadlocking boot under preflight +
|
|
211
|
+
* `block`. The full rule reports false once only external `/files/`
|
|
212
|
+
* references remain, so boot clears.
|
|
213
|
+
* 2. We scan only each page's **current** revision, never the whole
|
|
214
|
+
* `revisions` collection — historical revisions keep their original
|
|
215
|
+
* `/files/<id>` text forever (immutable), so a collection-wide scan
|
|
216
|
+
* would pend permanently after any such page ever existed.
|
|
217
|
+
*
|
|
218
|
+
* Short-circuits at the first rewritable page.
|
|
219
|
+
*/
|
|
220
|
+
isPending: async (ctx) => {
|
|
221
|
+
const origins = resolveAppOrigins(ctx);
|
|
222
|
+
const Page = ctx.crowi.model('Page');
|
|
223
|
+
const Revision = ctx.crowi.model('Revision');
|
|
224
|
+
const cursor = Page.find({ $or: [{ status: page_1.STATUS_PUBLISHED }, { status: null }] })
|
|
225
|
+
.select('_id revision')
|
|
226
|
+
.lean()
|
|
227
|
+
.cursor();
|
|
228
|
+
for await (const page of cursor) {
|
|
229
|
+
const revisionId = page.revision;
|
|
230
|
+
if (!revisionId)
|
|
231
|
+
continue;
|
|
232
|
+
const revision = await Revision.findById(revisionId).select('body').lean().exec();
|
|
233
|
+
const body = revision?.body;
|
|
234
|
+
if (typeof body === 'string' && bodyHasRewritableFilesUrl(body, origins)) {
|
|
235
|
+
await cursor.close();
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return false;
|
|
240
|
+
},
|
|
241
|
+
/**
|
|
242
|
+
* Full scan for `plan`: affected page count plus the rewrite breakdown
|
|
243
|
+
* (relative / self-host absolute rewrites + external skips, the last
|
|
244
|
+
* aggregated across every `/files/` page — see `scanFilesUrls`). Not called
|
|
245
|
+
* at boot.
|
|
246
|
+
*/
|
|
247
|
+
detect: async (ctx) => {
|
|
248
|
+
const origins = resolveAppOrigins(ctx);
|
|
249
|
+
const { rewritable, totals } = await scanFilesUrls(ctx, origins);
|
|
250
|
+
const rewrites = totals.relative + totals.selfHostAbsolute;
|
|
251
|
+
return {
|
|
252
|
+
summary: `${rewritable.length} page(s) need a v1 /files/<id> rewrite (${rewrites} rewrite(s): ${totals.relative} relative, ${totals.selfHostAbsolute} self-host absolute; ${totals.externalSkipped} external skipped)`,
|
|
253
|
+
counts: {
|
|
254
|
+
pages: rewritable.length,
|
|
255
|
+
rewrites,
|
|
256
|
+
relative: totals.relative,
|
|
257
|
+
selfHostAbsolute: totals.selfHostAbsolute,
|
|
258
|
+
externalSkipped: totals.externalSkipped,
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
},
|
|
262
|
+
stages: [
|
|
263
|
+
{
|
|
264
|
+
name: 'rewrite-files-url',
|
|
265
|
+
fn: async (ctx) => {
|
|
266
|
+
const origins = resolveAppOrigins(ctx);
|
|
267
|
+
if (ctx.dryRun) {
|
|
268
|
+
const { rewritable } = await scanFilesUrls(ctx, origins);
|
|
269
|
+
return { name: 'rewrite-files-url', transformed: 0, stats: { wouldRewrite: rewritable.length } };
|
|
270
|
+
}
|
|
271
|
+
const actingUserId = await (0, helpers_1.resolveActingUserId)(ctx, 'files-url-to-attachments');
|
|
272
|
+
const { rewritable: pages } = await scanFilesUrls(ctx, origins);
|
|
273
|
+
ctx.progress.setTotal(pages.length);
|
|
274
|
+
let rewritten = 0;
|
|
275
|
+
// Serial walk through `ctx.rewritePageBody` (each call re-fetches the
|
|
276
|
+
// live page, prepares a revision, and pushes it via the updatePage
|
|
277
|
+
// path so yjsState / yjsCheckpointAt are nulled).
|
|
278
|
+
for (const page of pages) {
|
|
279
|
+
await ctx.rewritePageBody(page.pageId, page.newBody, { userId: actingUserId });
|
|
280
|
+
rewritten += 1;
|
|
281
|
+
ctx.progress.increment();
|
|
282
|
+
}
|
|
283
|
+
if (rewritten > 0) {
|
|
284
|
+
ctx.logger.info(`files-url-to-attachments: rewrote ${rewritten} page(s) via the updatePage path (yjsState invalidated)`);
|
|
285
|
+
}
|
|
286
|
+
return { name: 'rewrite-files-url', transformed: rewritten };
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
});
|
|
291
|
+
//# sourceMappingURL=files-url-to-attachments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files-url-to-attachments.js","sourceRoot":"","sources":["../../../src/migration/migrations/files-url-to-attachments.ts"],"names":[],"mappings":";;;;;;AA+HA,4CAmBC;AAUD,8DAIC;AAhKD,yEAAwD;AACxD,0CAAmD;AAEnD,wCAAiD;AACjD,oCAA2C;AAG3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,oDAAoD;AACpD,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,qBAAqB,GAAG,SAAS,CAAC;AAexC,MAAM,WAAW,GAAG,GAA0B,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC,CAAC;AAE5G;;;;;;;;;;;;;;GAcG;AACH,SAAS,kBAAkB;IACzB,gBAAgB;IAChB,+EAA+E;IAC/E,kFAAkF;IAClF,gCAAgC;IAChC,6EAA6E;IAC7E,gDAAgD;IAChD,OAAO,8EAA8E,CAAC;AACxF,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,gBAAgB,CAAC,aAAqB,EAAE,OAA0B;IACzE,OAAO,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,gBAAgB,CAAC,IAAY,EAAE,OAA0B;IACvE,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,KAAK,EAAE,IAAY,EAAE,aAAiC,EAAE,EAAU,EAAE,IAAY,EAAE,EAAE;QACxI,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,gEAAgE;YAChE,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;YACrB,OAAO,GAAG,IAAI,IAAI,oBAAoB,GAAG,EAAE,GAAG,IAAI,GAAG,CAAC;QACxD,CAAC;QACD,IAAI,gBAAgB,CAAC,aAAa,EAAE,OAAO,CAAC,EAAE,CAAC;YAC7C,+DAA+D;YAC/D,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC;YAC7B,OAAO,GAAG,IAAI,IAAI,oBAAoB,GAAG,EAAE,GAAG,IAAI,GAAG,CAAC;QACxD,CAAC;QACD,2CAA2C;QAC3C,MAAM,CAAC,eAAe,IAAI,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,GAAG,CAAC,IAAI,MAAM,CAAC,gBAAgB,GAAG,CAAC,CAAC;IACnE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;AACtD,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,yBAAyB,CAAC,IAAY,EAAE,OAA0B;IAChF,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QAAE,OAAO,KAAK,CAAC;IACxD,MAAM,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC,QAAQ,GAAG,CAAC,IAAI,MAAM,CAAC,gBAAgB,GAAG,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,GAAqB;IAC9C,OAAO,IAAA,sBAAmB,EAAC,GAAG,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;AACxD,CAAC;AAoBD;;;;;;;;;;GAUG;AACH,KAAK,UAAU,aAAa,CAAC,GAAqB,EAAE,OAA0B;IAC5E,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAE7C,MAAM,UAAU,GAAqB,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,uBAAgB,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;SAChF,MAAM,CAAC,cAAc,CAAC;SACtB,IAAI,EAAE;SACN,MAAM,EAAE,CAAC;IAEZ,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,IAA4C,CAAC;QAC7D,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,SAAS;QAChC,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;QACxF,MAAM,IAAI,GAAI,QAAsC,EAAE,IAAI,CAAC;QAC3D,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,SAAS;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC;YAAE,SAAS;QACpD,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;QAC1C,MAAM,CAAC,gBAAgB,IAAI,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC;QAC1D,MAAM,CAAC,eAAe,IAAI,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC;QACxD,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI;YAAE,SAAS;QACnC,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AAChC,CAAC;AAEY,QAAA,qBAAqB,GAAG,IAAA,uBAAe,EAAC;IACnD,EAAE,EAAE,0BAA0B;IAC9B,WAAW,EAAE,KAAK;IAClB,SAAS,EAAE,KAAK;IAChB,KAAK,EAAE,WAAW;IAClB,WAAW,EAAE,uEAAuE;IAEpF;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACvB,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,uBAAgB,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;aAChF,MAAM,CAAC,cAAc,CAAC;aACtB,IAAI,EAAE;aACN,MAAM,EAAE,CAAC;QACZ,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAChC,MAAM,UAAU,GAAI,IAA+B,CAAC,QAAQ,CAAC;YAC7D,IAAI,CAAC,UAAU;gBAAE,SAAS;YAC1B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;YAClF,MAAM,IAAI,GAAI,QAAsC,EAAE,IAAI,CAAC;YAC3D,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,yBAAyB,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;gBACzE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;gBACrB,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;OAKG;IACH,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACpB,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACjE,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAC3D,OAAO;YACL,OAAO,EAAE,GAAG,UAAU,CAAC,MAAM,2CAA2C,QAAQ,gBAAgB,MAAM,CAAC,QAAQ,cAAc,MAAM,CAAC,gBAAgB,wBAAwB,MAAM,CAAC,eAAe,oBAAoB;YACtN,MAAM,EAAE;gBACN,KAAK,EAAE,UAAU,CAAC,MAAM;gBACxB,QAAQ;gBACR,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;gBACzC,eAAe,EAAE,MAAM,CAAC,eAAe;aACxC;SACF,CAAC;IACJ,CAAC;IAED,MAAM,EAAE;QACN;YACE,IAAI,EAAE,mBAAmB;YACzB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;gBAChB,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;gBACvC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;oBACf,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;oBACzD,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;gBACnG,CAAC;gBAED,MAAM,YAAY,GAAG,MAAM,IAAA,6BAAmB,EAAC,GAAG,EAAE,0BAA0B,CAAC,CAAC;gBAChF,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;gBAChE,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAEpC,IAAI,SAAS,GAAG,CAAC,CAAC;gBAClB,sEAAsE;gBACtE,mEAAmE;gBACnE,kDAAkD;gBAClD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,MAAM,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;oBAC/E,SAAS,IAAI,CAAC,CAAC;oBACf,GAAG,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;gBAC3B,CAAC;gBAED,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;oBAClB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,qCAAqC,SAAS,yDAAyD,CAAC,CAAC;gBAC3H,CAAC;gBACD,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;YAC/D,CAAC;SACF;KACF;CACF,CAAC,CAAC"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.allMigrations = void 0;
|
|
4
|
+
const files_url_to_attachments_1 = require("./files-url-to-attachments");
|
|
4
5
|
const page_status_default_1 = require("./page-status-default");
|
|
5
6
|
const relocate_reserved_api_paths_1 = require("./relocate-reserved-api-paths");
|
|
6
7
|
const revisions_schema_unify_1 = require("./revisions-schema-unify");
|
|
7
8
|
const user_unique_prepare_1 = require("./user-unique-prepare");
|
|
8
9
|
const wikilink_format_1 = require("./wikilink-format");
|
|
10
|
+
const wikilink_html_recover_1 = require("./wikilink-html-recover");
|
|
9
11
|
/**
|
|
10
12
|
* RFC-0008 §5.5 — the migration barrel.
|
|
11
13
|
*
|
|
@@ -22,5 +24,7 @@ exports.allMigrations = [
|
|
|
22
24
|
user_unique_prepare_1.userUniquePrepare, // phase 5 (preflight)
|
|
23
25
|
revisions_schema_unify_1.revisionsSchemaUnify, // phase 6 (boot — RFC-classified preflight, see migration JSDoc)
|
|
24
26
|
relocate_reserved_api_paths_1.relocateReservedApiPaths, // fix/mcp-endpoint (preflight) — v2 /api namespace reservation
|
|
27
|
+
files_url_to_attachments_1.filesUrlToAttachments, // feature-migration-files-url-rewrite (preflight) — v1 /files/<id> body rewrite (independent regex from wikilink-format/html-tag-fixes)
|
|
28
|
+
wikilink_html_recover_1.wikilinkHtmlRecover, // migration-html-tag-fixes (preflight) — recover </font> etc. corrupted by wikilink-format
|
|
25
29
|
];
|
|
26
30
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/migration/migrations/index.ts"],"names":[],"mappings":";;;AACA,+DAA0D;AAC1D,+EAAyE;AACzE,qEAAgE;AAChE,+DAA0D;AAC1D,uDAAmD;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/migration/migrations/index.ts"],"names":[],"mappings":";;;AACA,yEAAmE;AACnE,+DAA0D;AAC1D,+EAAyE;AACzE,qEAAgE;AAChE,+DAA0D;AAC1D,uDAAmD;AACnD,mEAA8D;AAE9D;;;;;;;;;GASG;AACU,QAAA,aAAa,GAA0B;IAClD,uCAAiB,EAAE,iBAAiB;IACpC,gCAAc,EAAE,sBAAsB;IACtC,uCAAiB,EAAE,sBAAsB;IACzC,6CAAoB,EAAE,iEAAiE;IACvF,sDAAwB,EAAE,+DAA+D;IACzF,gDAAqB,EAAE,wIAAwI;IAC/J,2CAAmB,EAAE,2FAA2F;CACjH,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { MigrationContext } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Shared "walk every published page's current revision" helper for the
|
|
4
|
+
* preflight migrations that have to project a revision field (no index on
|
|
5
|
+
* `meta.toc.text` / `revision.body`, so an index-backed O(1) probe is
|
|
6
|
+
* impossible — matches `wikilink-format`'s accepted tradeoff). It exists so the
|
|
7
|
+
* walk skeleton + the page→revision pairing are defined once and cannot drift
|
|
8
|
+
* between `isPending` (early-stop verdict) and `detect`/stage (full scan).
|
|
9
|
+
*
|
|
10
|
+
* Streaming + batching:
|
|
11
|
+
* - streams the published-page collection projecting only `_id revision`
|
|
12
|
+
* (`status: published` or legacy `null`, treated as published — trash /
|
|
13
|
+
* deprecated pages are read-only fixtures and out of scope), and
|
|
14
|
+
* - batch-fetches the paired current revisions with a single
|
|
15
|
+
* `Revision.find({ _id: { $in: batch } })` per `batchSize` pages instead of
|
|
16
|
+
* one `findById` per page (eliminates the per-page N+1).
|
|
17
|
+
*
|
|
18
|
+
* Early stop: `visit` may return `STOP` to abort the walk at the first hit, so
|
|
19
|
+
* `isPending` can short-circuit without reading every page.
|
|
20
|
+
*
|
|
21
|
+
* NOTE: `wikilink-format` predates this helper and keeps its own copy on
|
|
22
|
+
* purpose (its tests pin the existing walk); it can adopt this later.
|
|
23
|
+
*/
|
|
24
|
+
/** Sentinel a `visit` callback returns to abort the walk early. */
|
|
25
|
+
export declare const STOP: unique symbol;
|
|
26
|
+
/** A current revision, with the `select(projection)` fields plus its page. */
|
|
27
|
+
export interface RevisionVisit {
|
|
28
|
+
/** The projected revision fields (`select`-ed by `projection`). */
|
|
29
|
+
revision: Record<string, unknown>;
|
|
30
|
+
/** The owning page's `_id`, as a string. */
|
|
31
|
+
pageId: string;
|
|
32
|
+
}
|
|
33
|
+
export interface WalkOptions {
|
|
34
|
+
/**
|
|
35
|
+
* Mongoose `.select(...)` projection string for the revision fetch
|
|
36
|
+
* (e.g. `'meta.toc'`, `'body'`). `_id` is always available on the result.
|
|
37
|
+
*/
|
|
38
|
+
projection: string;
|
|
39
|
+
/** Pages per `$in` revision batch. Defaults to 200. */
|
|
40
|
+
batchSize?: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Stream published pages, batch-fetch their current revisions with the given
|
|
44
|
+
* projection, and invoke `visit(revision)` for each. Returning `STOP` from
|
|
45
|
+
* `visit` aborts the walk immediately.
|
|
46
|
+
*/
|
|
47
|
+
export declare function forEachPublishedCurrentRevision(ctx: MigrationContext, options: WalkOptions, visit: (entry: RevisionVisit) => typeof STOP | void | Promise<typeof STOP | void>): Promise<void>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.STOP = void 0;
|
|
4
|
+
exports.forEachPublishedCurrentRevision = forEachPublishedCurrentRevision;
|
|
5
|
+
const page_1 = require("../../models/page");
|
|
6
|
+
/**
|
|
7
|
+
* Shared "walk every published page's current revision" helper for the
|
|
8
|
+
* preflight migrations that have to project a revision field (no index on
|
|
9
|
+
* `meta.toc.text` / `revision.body`, so an index-backed O(1) probe is
|
|
10
|
+
* impossible — matches `wikilink-format`'s accepted tradeoff). It exists so the
|
|
11
|
+
* walk skeleton + the page→revision pairing are defined once and cannot drift
|
|
12
|
+
* between `isPending` (early-stop verdict) and `detect`/stage (full scan).
|
|
13
|
+
*
|
|
14
|
+
* Streaming + batching:
|
|
15
|
+
* - streams the published-page collection projecting only `_id revision`
|
|
16
|
+
* (`status: published` or legacy `null`, treated as published — trash /
|
|
17
|
+
* deprecated pages are read-only fixtures and out of scope), and
|
|
18
|
+
* - batch-fetches the paired current revisions with a single
|
|
19
|
+
* `Revision.find({ _id: { $in: batch } })` per `batchSize` pages instead of
|
|
20
|
+
* one `findById` per page (eliminates the per-page N+1).
|
|
21
|
+
*
|
|
22
|
+
* Early stop: `visit` may return `STOP` to abort the walk at the first hit, so
|
|
23
|
+
* `isPending` can short-circuit without reading every page.
|
|
24
|
+
*
|
|
25
|
+
* NOTE: `wikilink-format` predates this helper and keeps its own copy on
|
|
26
|
+
* purpose (its tests pin the existing walk); it can adopt this later.
|
|
27
|
+
*/
|
|
28
|
+
/** Sentinel a `visit` callback returns to abort the walk early. */
|
|
29
|
+
exports.STOP = Symbol('stop-walk');
|
|
30
|
+
const DEFAULT_BATCH_SIZE = 200;
|
|
31
|
+
/**
|
|
32
|
+
* Stream published pages, batch-fetch their current revisions with the given
|
|
33
|
+
* projection, and invoke `visit(revision)` for each. Returning `STOP` from
|
|
34
|
+
* `visit` aborts the walk immediately.
|
|
35
|
+
*/
|
|
36
|
+
async function forEachPublishedCurrentRevision(ctx, options, visit) {
|
|
37
|
+
const Page = ctx.crowi.model('Page');
|
|
38
|
+
const Revision = ctx.crowi.model('Revision');
|
|
39
|
+
const projection = options.projection;
|
|
40
|
+
const batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
41
|
+
const cursor = Page.find({ $or: [{ status: page_1.STATUS_PUBLISHED }, { status: null }] })
|
|
42
|
+
.select('_id revision')
|
|
43
|
+
.lean()
|
|
44
|
+
.cursor();
|
|
45
|
+
// Buffer of pages whose current revision still needs fetching.
|
|
46
|
+
let batch = [];
|
|
47
|
+
// Fetch the batch's revisions in one `$in` round-trip and pair each back to
|
|
48
|
+
// its page (preserving page order). Returns STOP if `visit` asked to abort.
|
|
49
|
+
const flush = async () => {
|
|
50
|
+
if (batch.length === 0)
|
|
51
|
+
return;
|
|
52
|
+
const ids = batch.map((p) => p.revision);
|
|
53
|
+
const revisions = await Revision.find({ _id: { $in: ids } })
|
|
54
|
+
.select(projection)
|
|
55
|
+
.lean()
|
|
56
|
+
.exec();
|
|
57
|
+
const byId = new Map();
|
|
58
|
+
for (const rev of revisions) {
|
|
59
|
+
if (rev?._id != null)
|
|
60
|
+
byId.set(String(rev._id), rev);
|
|
61
|
+
}
|
|
62
|
+
const pages = batch;
|
|
63
|
+
batch = [];
|
|
64
|
+
for (const page of pages) {
|
|
65
|
+
const revision = byId.get(String(page.revision));
|
|
66
|
+
if (!revision)
|
|
67
|
+
continue;
|
|
68
|
+
const result = await visit({ revision, pageId: String(page._id) });
|
|
69
|
+
if (result === exports.STOP)
|
|
70
|
+
return exports.STOP;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
for await (const raw of cursor) {
|
|
75
|
+
const page = raw;
|
|
76
|
+
if (!page.revision)
|
|
77
|
+
continue;
|
|
78
|
+
batch.push(page);
|
|
79
|
+
if (batch.length >= batchSize) {
|
|
80
|
+
if ((await flush()) === exports.STOP)
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
await flush();
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
await cursor.close();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=published-current-revision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"published-current-revision.js","sourceRoot":"","sources":["../../../src/migration/migrations/published-current-revision.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,17 +20,6 @@
|
|
|
20
20
|
* The textual conversion logic below is moved verbatim from the old command so
|
|
21
21
|
* the rewrite output is byte-identical to the legacy migrator.
|
|
22
22
|
*/
|
|
23
|
-
/**
|
|
24
|
-
* HTML5 element name set used to reject `</foo>` matches whose first path
|
|
25
|
-
* segment is actually a closing HTML tag. Source:
|
|
26
|
-
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element — the full
|
|
27
|
-
* standard element list as of the HTML Living Standard.
|
|
28
|
-
*
|
|
29
|
-
* Kept as a top-level `Set<string>` so detection runs O(1) per match.
|
|
30
|
-
* `h1`..`h6` are listed explicitly because the regex captures `foo` for
|
|
31
|
-
* `</foo>` and we want both `</h1>` and `</h6>` to be rejected.
|
|
32
|
-
*/
|
|
33
|
-
export declare const KNOWN_HTML_ELEMENTS: ReadonlySet<string>;
|
|
34
23
|
/**
|
|
35
24
|
* v1 angle-bracket internal link form. The capture group grabs the path-style
|
|
36
25
|
* payload (starts with `/`, no whitespace, no `<` / `>` / `|` other than the
|