@crowi/api-contract 2.0.0-alpha.15 → 2.0.0-alpha.16

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/index.mjs CHANGED
@@ -108,6 +108,11 @@ var ERROR_CODES = [
108
108
  // --- federated sign-in (RFC-0014) ---
109
109
  "FEDERATED_HANDOFF_INVALID",
110
110
  "FEDERATED_HANDOFF_CONSUMED",
111
+ // --- federated account linking (RFC-0014 §5.4) ---
112
+ "FEDERATED_IDENTITY_IN_USE",
113
+ "FEDERATED_LINK_AUTH_STATE_CHANGED",
114
+ "FEDERATED_LINK_NOT_LINKED",
115
+ "LINK_COMPLETION_CONSUMED",
111
116
  // --- admin subsystems ---
112
117
  "ENCRYPTION_NOT_CONFIGURED",
113
118
  "MAIL_FROM_NOT_CONFIGURED",
@@ -6053,12 +6058,28 @@ var FederatedHandoffResponseSchema = TokenAuthResponseSchema;
6053
6058
  var LinkedAuthProviderListResponseSchema = z52.object({
6054
6059
  identities: z52.array(z52.object({ provider: z52.string() }))
6055
6060
  });
6056
- var CreateLinkGrantRequestSchema = z52.object({
6057
- /** RFC 7638 thumbprint of the P-256 public key this browser will use at `/start` — binds the grant to this browser (AC-2). */
6058
- handoffChallenge: z52.string().min(1)
6061
+ var LinkCompletionCodeSchema = z52.string().regex(/^[A-Za-z0-9_-]{43}$/, "must be a 43-character base64url completion code");
6062
+ var StartProviderLinkResponseSchema = z52.object({
6063
+ authorizationUrl: z52.string().url()
6059
6064
  });
6060
- var CreateLinkGrantResponseSchema = z52.object({
6061
- linkGrant: z52.string()
6065
+ var PendingLinkCompletionResponseSchema = z52.object({
6066
+ provider: z52.string(),
6067
+ accountLabel: z52.string().optional()
6068
+ });
6069
+ var CompleteProviderLinkResponseSchema = z52.object({
6070
+ result: z52.literal("linked")
6071
+ });
6072
+ var LinkCompletionConsumedErrorSchema = ApiErrorSchema.extend({
6073
+ error: z52.object({
6074
+ code: z52.literal("LINK_COMPLETION_CONSUMED"),
6075
+ message: z52.string()
6076
+ })
6077
+ });
6078
+ var CompleteProviderLinkConflictErrorSchema = ApiErrorSchema.extend({
6079
+ error: z52.object({
6080
+ code: z52.enum(["FEDERATED_IDENTITY_IN_USE", "FEDERATED_LINK_AUTH_STATE_CHANGED", "FEDERATED_LINK_NOT_LINKED"]),
6081
+ message: z52.string()
6082
+ })
6062
6083
  });
6063
6084
  var UnlinkAuthProviderErrorSchema = z52.object({
6064
6085
  error: z52.object({
@@ -6089,7 +6110,7 @@ var startFederatedProviderRoute = createRoute29({
6089
6110
  method: "get",
6090
6111
  path: "/auth/providers/{name}/start",
6091
6112
  tags: ["federatedAuth"],
6092
- summary: "Top-level navigation that redirects the browser to the named provider",
6113
+ summary: "Top-level navigation that redirects the browser to the named provider (public sign-in ONLY)",
6093
6114
  request: {
6094
6115
  params: z53.object({ name: z53.string() }),
6095
6116
  query: z53.object({
@@ -6097,31 +6118,13 @@ var startFederatedProviderRoute = createRoute29({
6097
6118
  /** base64url(JSON) of the sender's P-256 public JWK. */
6098
6119
  handoff_jwk: z53.string().min(1),
6099
6120
  /** base64url ES256 signature over the start canonical message. */
6100
- handoff_proof: z53.string().min(1),
6101
- /**
6102
- * RFC-0014 phase 3 — `'1'` switches this start into LINK mode: the
6103
- * request must carry a web-session JWT, and the flow attaches the
6104
- * resulting identity to that session's user instead of signing
6105
- * anyone in. Absent (the ordinary sign-in start) the route stays
6106
- * fully public.
6107
- */
6108
- link: z53.literal("1").optional(),
6109
- /** The opaque id from `POST /auth/providers/{name}/link-grants`. Required when `link=1`, ignored otherwise. */
6110
- link_grant: z53.string().min(1).optional()
6121
+ handoff_proof: z53.string().min(1)
6111
6122
  })
6112
6123
  },
6113
6124
  responses: {
6114
6125
  302: { description: "Redirect to the provider authorization endpoint" },
6115
6126
  400: {
6116
- description: "Malformed continue / sender proof, or an invalid/expired/mismatched link grant",
6117
- content: { "application/json": { schema: ApiErrorSchema } }
6118
- },
6119
- 401: {
6120
- description: "link=1 without a web-session JWT \u2014 never downgraded to the public sign-in start",
6121
- content: { "application/json": { schema: ApiErrorSchema } }
6122
- },
6123
- 403: {
6124
- description: "link=1 with a non-web credential (PAT / OAuth access token)",
6127
+ description: "Malformed continue / sender proof, OR a raw `link` query key is present (any value) \u2014 the retired link-via-GET flow is gone entirely; a raw `link` key is always rejected rather than silently downgraded to public sign-in.",
6125
6128
  content: { "application/json": { schema: ApiErrorSchema } }
6126
6129
  },
6127
6130
  404: {
@@ -6154,32 +6157,113 @@ var listLinkedAuthProvidersRoute = createRoute29({
6154
6157
  }
6155
6158
  }
6156
6159
  });
6157
- var createAuthProviderLinkGrantRoute = createRoute29({
6160
+ var startProviderLinkRoute = createRoute29({
6158
6161
  method: "post",
6159
- path: "/auth/providers/{name}/link-grants",
6162
+ path: "/auth/providers/{name}/link-start",
6160
6163
  tags: ["federatedAuth"],
6161
- summary: "Mint a short-lived, opaque grant that authorizes ONE link start for the current web session",
6164
+ summary: "Mint an IdP authorization URL + flow-specific state cookie for the current web session (stage 1 of 3)",
6162
6165
  request: {
6163
- params: z53.object({ name: z53.string() }),
6164
- body: { content: { "application/json": { schema: CreateLinkGrantRequestSchema } } }
6166
+ params: z53.object({ name: z53.string() })
6165
6167
  },
6166
6168
  responses: {
6167
6169
  200: {
6168
- description: "Opaque single-use grant id",
6169
- content: { "application/json": { schema: CreateLinkGrantResponseSchema } }
6170
+ description: "Authorization URL to navigate the browser to. Sets a flow-specific, 300s state cookie.",
6171
+ content: { "application/json": { schema: StartProviderLinkResponseSchema } }
6172
+ },
6173
+ 400: {
6174
+ description: "The signed link-state cookie value would exceed its per-cookie byte limit, or the aggregate Cookie-header admission budget cannot be satisfied even after pruning \u2014 no Set-Cookie or authorizationUrl is returned.",
6175
+ content: { "application/json": { schema: ApiErrorSchema } }
6170
6176
  },
6171
6177
  401: {
6172
- description: "Authentication required",
6178
+ description: "Authentication required (credential missing/invalid \u2014 resolved by middleware before this route's own validation)",
6173
6179
  content: { "application/json": { schema: AuthenticationRequiredErrorSchema } }
6174
6180
  },
6175
6181
  403: {
6176
- description: "Non-web credential (PAT / OAuth access token)",
6182
+ description: "Non-web credential (PAT / OAuth access token) \u2014 linking is a session-level account change",
6177
6183
  content: { "application/json": { schema: ApiErrorSchema } }
6178
6184
  },
6179
6185
  404: {
6180
6186
  description: "Unknown, unconfigured, or credential-kind provider",
6181
6187
  content: { "application/json": { schema: ApiErrorSchema } }
6182
6188
  },
6189
+ 500: {
6190
+ description: "Internal server error (e.g. a declared multi-instance topology with no reachable Redis)",
6191
+ content: { "application/json": { schema: InternalServerErrorSchema } }
6192
+ }
6193
+ }
6194
+ });
6195
+ var getProviderLinkCompletionRoute = createRoute29({
6196
+ method: "get",
6197
+ path: "/auth/providers/{name}/link-completions/{code}",
6198
+ tags: ["federatedAuth"],
6199
+ summary: "Read a pending link completion's confirmation details (stage 3a \u2014 non-destructive)",
6200
+ request: {
6201
+ params: z53.object({ name: z53.string(), code: LinkCompletionCodeSchema })
6202
+ },
6203
+ responses: {
6204
+ 200: {
6205
+ description: "Pending, unconsumed completion bound to the caller \u2014 provider label fallback + optional display-only accountLabel",
6206
+ content: { "application/json": { schema: PendingLinkCompletionResponseSchema } }
6207
+ },
6208
+ 400: {
6209
+ description: "Authenticated but `{code}` fails the 43-character base64url shape (VALIDATION_ERROR)",
6210
+ content: { "application/json": { schema: ValidationErrorSchema } }
6211
+ },
6212
+ 401: {
6213
+ description: "Authentication required \u2014 resolved by middleware before this route's own `{code}` shape validation, so an unauthenticated + malformed code is still 401, never 400",
6214
+ content: { "application/json": { schema: AuthenticationRequiredErrorSchema } }
6215
+ },
6216
+ 403: {
6217
+ description: "Non-web credential (PAT / OAuth access token)",
6218
+ content: { "application/json": { schema: ApiErrorSchema } }
6219
+ },
6220
+ 404: {
6221
+ description: "Never-issued, expired, retention-expired, or bound to a different user/provider/authVersion \u2014 all collapse to the same generic NOT_FOUND (no result-unknown code exists)",
6222
+ content: { "application/json": { schema: ApiErrorSchema } }
6223
+ },
6224
+ 409: {
6225
+ description: "The caller's own completion was already consumed",
6226
+ content: { "application/json": { schema: LinkCompletionConsumedErrorSchema } }
6227
+ },
6228
+ 500: {
6229
+ description: "Internal server error",
6230
+ content: { "application/json": { schema: InternalServerErrorSchema } }
6231
+ }
6232
+ }
6233
+ });
6234
+ var completeProviderLinkRoute = createRoute29({
6235
+ method: "post",
6236
+ path: "/auth/providers/{name}/link-completions/{code}",
6237
+ tags: ["federatedAuth"],
6238
+ summary: "Atomically consume a link completion code and insert the identity (stage 3b \u2014 terminal)",
6239
+ request: {
6240
+ params: z53.object({ name: z53.string(), code: LinkCompletionCodeSchema })
6241
+ },
6242
+ responses: {
6243
+ 200: {
6244
+ description: "Linked (fresh winner OR an already-consumed replay that resolves to the same owner) \u2014 the same body either way",
6245
+ content: { "application/json": { schema: CompleteProviderLinkResponseSchema } }
6246
+ },
6247
+ 400: {
6248
+ description: "Authenticated but `{code}` fails the 43-character base64url shape (VALIDATION_ERROR)",
6249
+ content: { "application/json": { schema: ValidationErrorSchema } }
6250
+ },
6251
+ 401: {
6252
+ description: "Authentication required \u2014 resolved by middleware before this route's own `{code}` shape validation, so an unauthenticated + malformed code is still 401, never 400",
6253
+ content: { "application/json": { schema: AuthenticationRequiredErrorSchema } }
6254
+ },
6255
+ 403: {
6256
+ description: "Non-web credential (PAT / OAuth access token)",
6257
+ content: { "application/json": { schema: ApiErrorSchema } }
6258
+ },
6259
+ 404: {
6260
+ description: "Never-issued, expired, retention-expired, or bound to a different user/provider \u2014 all collapse to the same generic NOT_FOUND",
6261
+ content: { "application/json": { schema: ApiErrorSchema } }
6262
+ },
6263
+ 409: {
6264
+ description: "FEDERATED_IDENTITY_IN_USE (provider account owned by someone else, or this user already has a different account of this provider), FEDERATED_LINK_AUTH_STATE_CHANGED (fresh User re-read found the session inactive or authVersion changed since link-start), or FEDERATED_LINK_NOT_LINKED (an already-consumed replay whose original insert has not landed) \u2014 no other conflict code exists.",
6265
+ content: { "application/json": { schema: CompleteProviderLinkConflictErrorSchema } }
6266
+ },
6183
6267
  500: {
6184
6268
  description: "Internal server error",
6185
6269
  content: { "application/json": { schema: InternalServerErrorSchema } }
@@ -6233,7 +6317,7 @@ var callbackFederatedProviderRoute = createRoute29({
6233
6317
  },
6234
6318
  responses: {
6235
6319
  302: {
6236
- description: "Redirect to the trusted web login/complete page on success, or back to the trusted web /login on failure"
6320
+ description: "Ordinary sign-in: redirect to the trusted web login/complete page on success, or back to the trusted web /login on failure. Link flow (query `state` in the reserved crowilnk_ namespace): success redirects to `/me?provider=<name>&link_completion=<code>` (provider + completion code ONLY); failure redirects to `/me?provider=<name>&link=link_failed` (provider + the generic marker ONLY \u2014 never a completion code, never accountLabel, never the underlying reason)."
6237
6321
  },
6238
6322
  404: {
6239
6323
  description: "Unknown or unconfigured provider (also used when trusted origins cannot be resolved)",
@@ -6278,7 +6362,9 @@ var federatedAuthRoutes = {
6278
6362
  callbackFederatedProviderRoute,
6279
6363
  federatedHandoffRoute,
6280
6364
  listLinkedAuthProvidersRoute,
6281
- createAuthProviderLinkGrantRoute,
6365
+ startProviderLinkRoute,
6366
+ getProviderLinkCompletionRoute,
6367
+ completeProviderLinkRoute,
6282
6368
  unlinkAuthProviderRoute
6283
6369
  };
6284
6370
 
@@ -7214,7 +7300,7 @@ var lateContractApp = new OpenAPIHono().openapi(draftRoutes.createDraftRoute, (c
7214
7300
  var adminSettingsContractApp = new OpenAPIHono().openapi(adminAppRoutes.getAppSettingsRoute, (c) => c.json(stubGetAppSettings, 200)).openapi(adminAppRoutes.updateAppSettingsRoute, (c) => c.json(stubUpdateAppSettings, 200)).openapi(adminAuthRoutes.getAuthSettingsRoute, (c) => c.json(stubAuthSettings, 200)).openapi(adminAuthRoutes.updateAuthSettingsRoute, (c) => c.json(stubAuthSettings, 200)).openapi(adminSecurityRoutes.getSecuritySettingsRoute, (c) => c.json(stubSecuritySettings, 200)).openapi(adminSecurityRoutes.updateSecuritySettingsRoute, (c) => c.json(stubSecuritySettings, 200)).openapi(adminMailRoutes.getMailSettingsRoute, (c) => c.json(stubMailSettings, 200)).openapi(adminMailRoutes.updateMailSettingsRoute, (c) => c.json(stubUpdateMailSettings, 200)).openapi(adminMailRoutes.sendTestMailRoute, (c) => c.json(stubSendTestMail, 200)).openapi(adminStorageRoutes.getStorageStatusRoute, (c) => c.json(stubStorageStatus, 200)).openapi(adminSearchRoutes.getSearchStatusRoute, (c) => c.json(stubSearchStatus, 200));
7215
7301
  var adminUsersPluginsContractApp = new OpenAPIHono().openapi(adminUsersRoutes.listUsersRoute, (c) => c.json(stubListAdminUsers, 200)).openapi(adminUsersRoutes.searchUsersByEmailRoute, (c) => c.json(stubSearchAdminUsersByEmail, 200)).openapi(adminUsersRoutes.pendingUsersCountRoute, (c) => c.json(stubPendingUsersCount, 200)).openapi(adminUsersRoutes.inviteUsersRoute, (c) => c.json(stubInviteUsers, 200)).openapi(adminUsersRoutes.editUserRoute, (c) => c.json(stubAdminUserMutation, 200)).openapi(adminUsersRoutes.makeAdminRoute, (c) => c.json(stubAdminUserMutation, 200)).openapi(adminUsersRoutes.removeFromAdminRoute, (c) => c.json(stubAdminUserMutation, 200)).openapi(adminUsersRoutes.activateUserRoute, (c) => c.json(stubAdminUserMutation, 200)).openapi(adminUsersRoutes.suspendUserRoute, (c) => c.json(stubAdminUserMutation, 200)).openapi(adminUsersRoutes.resetPasswordRoute, (c) => c.json(stubResetPassword, 200)).openapi(adminUsersRoutes.resendInviteRoute, (c) => c.json(stubAdminUserMutation, 200)).openapi(adminUsersRoutes.updateUserEmailRoute, (c) => c.json(stubAdminUserMutation, 200)).openapi(adminUsersRoutes.unlinkUserIdentityRoute, (c) => c.json(stubUnlinkUserIdentity, 200)).openapi(adminUsersRoutes.deleteUserRoute, (c) => c.json(stubDeleteAdminUser, 200)).openapi(adminPluginsRoutes.listPluginsRoute, (c) => c.json(stubListPlugins, 200)).openapi(adminPluginsRoutes.getPluginConfigRoute, (c) => c.json(stubPluginConfig, 200)).openapi(adminPluginsRoutes.updatePluginConfigRoute, (c) => c.json(stubUpdatePluginConfig, 200)).openapi(adminPluginsRoutes.getPluginReadinessRoute, (c) => c.json(stubPluginReadiness, 200)).openapi(adminPluginsRoutes.clearRenderCacheAllRoute, (c) => c.json(stubClearRenderCache, 200)).openapi(adminPluginsRoutes.clearRenderCachePluginRoute, (c) => c.json(stubClearRenderCache, 200));
7216
7302
  var oauthContractApp = new OpenAPIHono().openapi(oauthRoutes.authorizeRoute, (c) => c.json(stubAuthorize, 200)).openapi(oauthRoutes.tokenRoute, (c) => c.json(stubToken, 200)).openapi(oauthRoutes.revokeRoute, (c) => c.json(stubRevoke, 200)).openapi(oauthRoutes.discoveryRoute, (c) => c.json(stubDiscovery, 200)).openapi(oauthRoutes.deviceAuthorizeRoute, (c) => c.json(stubDeviceAuthorize, 200)).openapi(oauthRoutes.deviceInfoRoute, (c) => c.json(stubDeviceInfo, 200)).openapi(oauthRoutes.deviceVerifyRoute, (c) => c.json(stubDeviceVerify, 200)).openapi(oauthRoutes.clientInfoRoute, (c) => c.json(stubClientInfo, 200));
7217
- var federatedAuthContractApp = new OpenAPIHono().openapi(federatedAuthRoutes.listFederatedProvidersRoute, (c) => c.json(stubProviderList, 200)).openapi(federatedAuthRoutes.startFederatedProviderRoute, (c) => c.redirect("", 302)).openapi(federatedAuthRoutes.callbackFederatedProviderRoute, (c) => c.redirect("", 302)).openapi(federatedAuthRoutes.federatedHandoffRoute, (c) => c.json(stubTokens, 200)).openapi(federatedAuthRoutes.listLinkedAuthProvidersRoute, (c) => c.json({ identities: [] }, 200)).openapi(federatedAuthRoutes.createAuthProviderLinkGrantRoute, (c) => c.json({ linkGrant: "" }, 200)).openapi(federatedAuthRoutes.unlinkAuthProviderRoute, (c) => c.body(null, 204));
7303
+ var federatedAuthContractApp = new OpenAPIHono().openapi(federatedAuthRoutes.listFederatedProvidersRoute, (c) => c.json(stubProviderList, 200)).openapi(federatedAuthRoutes.startFederatedProviderRoute, (c) => c.redirect("", 302)).openapi(federatedAuthRoutes.callbackFederatedProviderRoute, (c) => c.redirect("", 302)).openapi(federatedAuthRoutes.federatedHandoffRoute, (c) => c.json(stubTokens, 200)).openapi(federatedAuthRoutes.listLinkedAuthProvidersRoute, (c) => c.json({ identities: [] }, 200)).openapi(federatedAuthRoutes.startProviderLinkRoute, (c) => c.json({ authorizationUrl: "" }, 200)).openapi(federatedAuthRoutes.getProviderLinkCompletionRoute, (c) => c.json({ provider: "" }, 200)).openapi(federatedAuthRoutes.completeProviderLinkRoute, (c) => c.json({ result: "linked" }, 200)).openapi(federatedAuthRoutes.unlinkAuthProviderRoute, (c) => c.body(null, 204));
7218
7304
  var federatedRegistrationContractApp = new OpenAPIHono().openapi(federatedRegistrationRoutes.getFederatedRegistrationRoute, (c) => c.json(stubFederatedRegistrationSnapshot, 200)).openapi(federatedRegistrationRoutes.submitFederatedRegistrationRoute, (c) => c.json({ status: "approval_required" }, 200)).openapi(federatedRegistrationRoutes.logoutFederatedRegistrationRoute, (c) => c.body(null, 204));
7219
7305
  var createClient = (baseUrl, options = {}) => hc(baseUrl, {
7220
7306
  headers: options.headers,
@@ -7487,6 +7573,8 @@ export {
7487
7573
  CommentInvalidRequestErrorSchema,
7488
7574
  CommentNotFoundErrorSchema,
7489
7575
  CommentSchema,
7576
+ CompleteProviderLinkConflictErrorSchema,
7577
+ CompleteProviderLinkResponseSchema,
7490
7578
  ConfigReadinessIssueSchema,
7491
7579
  ConfigReadinessResponseSchema,
7492
7580
  ConfirmEmailChangeRequestSchema,
@@ -7499,8 +7587,6 @@ export {
7499
7587
  CreateAdminResponseSchema,
7500
7588
  CreateDraftRequestSchema,
7501
7589
  CreateDraftResponseSchema,
7502
- CreateLinkGrantRequestSchema,
7503
- CreateLinkGrantResponseSchema,
7504
7590
  CreatePageRequestSchema,
7505
7591
  CrowiCodeSidecarSchema,
7506
7592
  CrowiDiagramNodeSchema,
@@ -7591,6 +7677,8 @@ export {
7591
7677
  LanguageSchema,
7592
7678
  LikerSchema,
7593
7679
  LikersResponseSchema,
7680
+ LinkCompletionCodeSchema,
7681
+ LinkCompletionConsumedErrorSchema,
7594
7682
  LinkedAuthProviderListResponseSchema,
7595
7683
  ListAccessTokensResponseSchema,
7596
7684
  ListAdminUsersRequestSchema,
@@ -7655,6 +7743,7 @@ export {
7655
7743
  PasswordErrorResponseSchema,
7656
7744
  PasswordUpdateSuccessSchema,
7657
7745
  PastAttachmentUsageSchema,
7746
+ PendingLinkCompletionResponseSchema,
7658
7747
  PendingUsersCountResponseSchema,
7659
7748
  PictureUploadResponseSchema,
7660
7749
  PluginAdminPlacementSchema,
@@ -7734,6 +7823,7 @@ export {
7734
7823
  ShikiTokenLinesSchema,
7735
7824
  ShikiTokenSchema,
7736
7825
  ShikiTokenStyleSchema,
7826
+ StartProviderLinkResponseSchema,
7737
7827
  StorageDriverEntrySchema,
7738
7828
  SuccessResponseSchema,
7739
7829
  ThemeSchema,
@@ -7822,10 +7912,10 @@ export {
7822
7912
  clearRenderCachePluginRoute,
7823
7913
  clientInfoRoute,
7824
7914
  commentRoutes,
7915
+ completeProviderLinkRoute,
7825
7916
  confirmEmailChangeRoute,
7826
7917
  createAccessTokenRoute,
7827
7918
  createAdminRoute,
7828
- createAuthProviderLinkGrantRoute,
7829
7919
  createClient,
7830
7920
  createDraftRoute,
7831
7921
  createPageRoute,
@@ -7863,6 +7953,7 @@ export {
7863
7953
  getPluginReadinessRoute,
7864
7954
  getPresenceTokenRoute,
7865
7955
  getProfileRoute,
7956
+ getProviderLinkCompletionRoute,
7866
7957
  getRevisionRoute,
7867
7958
  getRevisionsRoute,
7868
7959
  getSearchStatusRoute,
@@ -7936,6 +8027,7 @@ export {
7936
8027
  setPageGrantRoute,
7937
8028
  setWatchStatusRoute,
7938
8029
  startFederatedProviderRoute,
8030
+ startProviderLinkRoute,
7939
8031
  stripKnownHtmlTags,
7940
8032
  submitFederatedRegistrationRoute,
7941
8033
  suspendUserRoute,