refactor: expose shared memo as memo resource

Rename GetMemoByShare to GetSharedMemo and move REST resolution to /api/v1/shares/{share_token}/memo.\n\nBREAKING CHANGE: remove GET /api/v1/shares/{share_id} and the GetMemoByShare RPC.
This commit is contained in:
johnnyjoygh 2026-07-26 21:13:18 +08:00
parent 390126f1cd
commit 0d2cbd4f5a
16 changed files with 146 additions and 145 deletions

View file

@ -128,10 +128,10 @@ service MemoService {
option (google.api.http) = {delete: "/api/v1/{name=memos/*/shares/*}"};
option (google.api.method_signature) = "name";
}
// GetMemoByShare resolves a share token to its memo. No authentication required.
// GetSharedMemo resolves a share token to its memo. No authentication required.
// Returns NOT_FOUND if the token is invalid or expired.
rpc GetMemoByShare(GetMemoByShareRequest) returns (Memo) {
option (google.api.http) = {get: "/api/v1/shares/{share_id}"};
rpc GetSharedMemo(GetSharedMemoRequest) returns (Memo) {
option (google.api.http) = {get: "/api/v1/shares/{share_token}/memo"};
}
// GetLinkMetadata gets metadata for a link.
rpc GetLinkMetadata(GetLinkMetadataRequest) returns (LinkMetadata) {
@ -622,9 +622,9 @@ message DeleteMemoShareRequest {
];
}
message GetMemoByShareRequest {
// Required. The share token extracted from the share URL (/s/{share_id}).
string share_id = 1 [(google.api.field_behavior) = REQUIRED];
message GetSharedMemoRequest {
// Required. The opaque bearer token extracted from the share URL.
string share_token = 1 [(google.api.field_behavior) = REQUIRED];
}
message GetLinkMetadataRequest {

View file

@ -23,7 +23,7 @@ plugins:
- remote: buf.build/community/google-gnostic-openapi
out: gen
opt: enum_type=string
- remote: buf.build/bufbuild/es
- remote: buf.build/bufbuild/es:v2.12.1
out: ../web/src/types/proto
opt:
- target=ts

View file

@ -80,9 +80,9 @@ const (
// MemoServiceDeleteMemoShareProcedure is the fully-qualified name of the MemoService's
// DeleteMemoShare RPC.
MemoServiceDeleteMemoShareProcedure = "/memos.api.v1.MemoService/DeleteMemoShare"
// MemoServiceGetMemoByShareProcedure is the fully-qualified name of the MemoService's
// GetMemoByShare RPC.
MemoServiceGetMemoByShareProcedure = "/memos.api.v1.MemoService/GetMemoByShare"
// MemoServiceGetSharedMemoProcedure is the fully-qualified name of the MemoService's GetSharedMemo
// RPC.
MemoServiceGetSharedMemoProcedure = "/memos.api.v1.MemoService/GetSharedMemo"
// MemoServiceGetLinkMetadataProcedure is the fully-qualified name of the MemoService's
// GetLinkMetadata RPC.
MemoServiceGetLinkMetadataProcedure = "/memos.api.v1.MemoService/GetLinkMetadata"
@ -134,9 +134,9 @@ type MemoServiceClient interface {
ListMemoShares(context.Context, *connect.Request[v1.ListMemoSharesRequest]) (*connect.Response[v1.ListMemoSharesResponse], error)
// DeleteMemoShare revokes a share link. Requires authentication as the memo creator.
DeleteMemoShare(context.Context, *connect.Request[v1.DeleteMemoShareRequest]) (*connect.Response[emptypb.Empty], error)
// GetMemoByShare resolves a share token to its memo. No authentication required.
// GetSharedMemo resolves a share token to its memo. No authentication required.
// Returns NOT_FOUND if the token is invalid or expired.
GetMemoByShare(context.Context, *connect.Request[v1.GetMemoByShareRequest]) (*connect.Response[v1.Memo], error)
GetSharedMemo(context.Context, *connect.Request[v1.GetSharedMemoRequest]) (*connect.Response[v1.Memo], error)
// GetLinkMetadata gets metadata for a link.
GetLinkMetadata(context.Context, *connect.Request[v1.GetLinkMetadataRequest]) (*connect.Response[v1.LinkMetadata], error)
// BatchGetLinkMetadata gets metadata for links.
@ -256,10 +256,10 @@ func NewMemoServiceClient(httpClient connect.HTTPClient, baseURL string, opts ..
connect.WithSchema(memoServiceMethods.ByName("DeleteMemoShare")),
connect.WithClientOptions(opts...),
),
getMemoByShare: connect.NewClient[v1.GetMemoByShareRequest, v1.Memo](
getSharedMemo: connect.NewClient[v1.GetSharedMemoRequest, v1.Memo](
httpClient,
baseURL+MemoServiceGetMemoByShareProcedure,
connect.WithSchema(memoServiceMethods.ByName("GetMemoByShare")),
baseURL+MemoServiceGetSharedMemoProcedure,
connect.WithSchema(memoServiceMethods.ByName("GetSharedMemo")),
connect.WithClientOptions(opts...),
),
getLinkMetadata: connect.NewClient[v1.GetLinkMetadataRequest, v1.LinkMetadata](
@ -296,7 +296,7 @@ type memoServiceClient struct {
createMemoShare *connect.Client[v1.CreateMemoShareRequest, v1.MemoShare]
listMemoShares *connect.Client[v1.ListMemoSharesRequest, v1.ListMemoSharesResponse]
deleteMemoShare *connect.Client[v1.DeleteMemoShareRequest, emptypb.Empty]
getMemoByShare *connect.Client[v1.GetMemoByShareRequest, v1.Memo]
getSharedMemo *connect.Client[v1.GetSharedMemoRequest, v1.Memo]
getLinkMetadata *connect.Client[v1.GetLinkMetadataRequest, v1.LinkMetadata]
batchGetLinkMetadata *connect.Client[v1.BatchGetLinkMetadataRequest, v1.BatchGetLinkMetadataResponse]
}
@ -386,9 +386,9 @@ func (c *memoServiceClient) DeleteMemoShare(ctx context.Context, req *connect.Re
return c.deleteMemoShare.CallUnary(ctx, req)
}
// GetMemoByShare calls memos.api.v1.MemoService.GetMemoByShare.
func (c *memoServiceClient) GetMemoByShare(ctx context.Context, req *connect.Request[v1.GetMemoByShareRequest]) (*connect.Response[v1.Memo], error) {
return c.getMemoByShare.CallUnary(ctx, req)
// GetSharedMemo calls memos.api.v1.MemoService.GetSharedMemo.
func (c *memoServiceClient) GetSharedMemo(ctx context.Context, req *connect.Request[v1.GetSharedMemoRequest]) (*connect.Response[v1.Memo], error) {
return c.getSharedMemo.CallUnary(ctx, req)
}
// GetLinkMetadata calls memos.api.v1.MemoService.GetLinkMetadata.
@ -444,9 +444,9 @@ type MemoServiceHandler interface {
ListMemoShares(context.Context, *connect.Request[v1.ListMemoSharesRequest]) (*connect.Response[v1.ListMemoSharesResponse], error)
// DeleteMemoShare revokes a share link. Requires authentication as the memo creator.
DeleteMemoShare(context.Context, *connect.Request[v1.DeleteMemoShareRequest]) (*connect.Response[emptypb.Empty], error)
// GetMemoByShare resolves a share token to its memo. No authentication required.
// GetSharedMemo resolves a share token to its memo. No authentication required.
// Returns NOT_FOUND if the token is invalid or expired.
GetMemoByShare(context.Context, *connect.Request[v1.GetMemoByShareRequest]) (*connect.Response[v1.Memo], error)
GetSharedMemo(context.Context, *connect.Request[v1.GetSharedMemoRequest]) (*connect.Response[v1.Memo], error)
// GetLinkMetadata gets metadata for a link.
GetLinkMetadata(context.Context, *connect.Request[v1.GetLinkMetadataRequest]) (*connect.Response[v1.LinkMetadata], error)
// BatchGetLinkMetadata gets metadata for links.
@ -562,10 +562,10 @@ func NewMemoServiceHandler(svc MemoServiceHandler, opts ...connect.HandlerOption
connect.WithSchema(memoServiceMethods.ByName("DeleteMemoShare")),
connect.WithHandlerOptions(opts...),
)
memoServiceGetMemoByShareHandler := connect.NewUnaryHandler(
MemoServiceGetMemoByShareProcedure,
svc.GetMemoByShare,
connect.WithSchema(memoServiceMethods.ByName("GetMemoByShare")),
memoServiceGetSharedMemoHandler := connect.NewUnaryHandler(
MemoServiceGetSharedMemoProcedure,
svc.GetSharedMemo,
connect.WithSchema(memoServiceMethods.ByName("GetSharedMemo")),
connect.WithHandlerOptions(opts...),
)
memoServiceGetLinkMetadataHandler := connect.NewUnaryHandler(
@ -616,8 +616,8 @@ func NewMemoServiceHandler(svc MemoServiceHandler, opts ...connect.HandlerOption
memoServiceListMemoSharesHandler.ServeHTTP(w, r)
case MemoServiceDeleteMemoShareProcedure:
memoServiceDeleteMemoShareHandler.ServeHTTP(w, r)
case MemoServiceGetMemoByShareProcedure:
memoServiceGetMemoByShareHandler.ServeHTTP(w, r)
case MemoServiceGetSharedMemoProcedure:
memoServiceGetSharedMemoHandler.ServeHTTP(w, r)
case MemoServiceGetLinkMetadataProcedure:
memoServiceGetLinkMetadataHandler.ServeHTTP(w, r)
case MemoServiceBatchGetLinkMetadataProcedure:
@ -699,8 +699,8 @@ func (UnimplementedMemoServiceHandler) DeleteMemoShare(context.Context, *connect
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("memos.api.v1.MemoService.DeleteMemoShare is not implemented"))
}
func (UnimplementedMemoServiceHandler) GetMemoByShare(context.Context, *connect.Request[v1.GetMemoByShareRequest]) (*connect.Response[v1.Memo], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("memos.api.v1.MemoService.GetMemoByShare is not implemented"))
func (UnimplementedMemoServiceHandler) GetSharedMemo(context.Context, *connect.Request[v1.GetSharedMemoRequest]) (*connect.Response[v1.Memo], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("memos.api.v1.MemoService.GetSharedMemo is not implemented"))
}
func (UnimplementedMemoServiceHandler) GetLinkMetadata(context.Context, *connect.Request[v1.GetLinkMetadataRequest]) (*connect.Response[v1.LinkMetadata], error) {

View file

@ -1925,28 +1925,28 @@ func (x *DeleteMemoShareRequest) GetName() string {
return ""
}
type GetMemoByShareRequest struct {
type GetSharedMemoRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
// Required. The share token extracted from the share URL (/s/{share_id}).
ShareId string `protobuf:"bytes,1,opt,name=share_id,json=shareId,proto3" json:"share_id,omitempty"`
// Required. The opaque bearer token extracted from the share URL.
ShareToken string `protobuf:"bytes,1,opt,name=share_token,json=shareToken,proto3" json:"share_token,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetMemoByShareRequest) Reset() {
*x = GetMemoByShareRequest{}
func (x *GetSharedMemoRequest) Reset() {
*x = GetSharedMemoRequest{}
mi := &file_api_v1_memo_service_proto_msgTypes[28]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetMemoByShareRequest) String() string {
func (x *GetSharedMemoRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetMemoByShareRequest) ProtoMessage() {}
func (*GetSharedMemoRequest) ProtoMessage() {}
func (x *GetMemoByShareRequest) ProtoReflect() protoreflect.Message {
func (x *GetSharedMemoRequest) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_memo_service_proto_msgTypes[28]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -1958,14 +1958,14 @@ func (x *GetMemoByShareRequest) ProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
// Deprecated: Use GetMemoByShareRequest.ProtoReflect.Descriptor instead.
func (*GetMemoByShareRequest) Descriptor() ([]byte, []int) {
// Deprecated: Use GetSharedMemoRequest.ProtoReflect.Descriptor instead.
func (*GetSharedMemoRequest) Descriptor() ([]byte, []int) {
return file_api_v1_memo_service_proto_rawDescGZIP(), []int{28}
}
func (x *GetMemoByShareRequest) GetShareId() string {
func (x *GetSharedMemoRequest) GetShareToken() string {
if x != nil {
return x.ShareId
return x.ShareToken
}
return ""
}
@ -2480,9 +2480,10 @@ const file_api_v1_memo_service_proto_rawDesc = "" +
"memoShares\"L\n" +
"\x16DeleteMemoShareRequest\x122\n" +
"\x04name\x18\x01 \x01(\tB\x1e\xe0A\x02\xfaA\x18\n" +
"\x16memos.api.v1/MemoShareR\x04name\"7\n" +
"\x15GetMemoByShareRequest\x12\x1e\n" +
"\bshare_id\x18\x01 \x01(\tB\x03\xe0A\x02R\ashareId\"/\n" +
"\x16memos.api.v1/MemoShareR\x04name\"<\n" +
"\x14GetSharedMemoRequest\x12$\n" +
"\vshare_token\x18\x01 \x01(\tB\x03\xe0A\x02R\n" +
"shareToken\"/\n" +
"\x16GetLinkMetadataRequest\x12\x15\n" +
"\x03url\x18\x01 \x01(\tB\x03\xe0A\x02R\x03url\"6\n" +
"\x1bBatchGetLinkMetadataRequest\x12\x17\n" +
@ -2500,7 +2501,7 @@ const file_api_v1_memo_service_proto_rawDesc = "" +
"\aPRIVATE\x10\x01\x12\r\n" +
"\tPROTECTED\x10\x02\x12\n" +
"\n" +
"\x06PUBLIC\x10\x032\x8b\x15\n" +
"\x06PUBLIC\x10\x032\x91\x15\n" +
"\vMemoService\x12e\n" +
"\n" +
"CreateMemo\x12\x1f.memos.api.v1.CreateMemoRequest\x1a\x12.memos.api.v1.Memo\"\"\xdaA\x04memo\x82\xd3\xe4\x93\x02\x15:\x04memo\"\r/api/v1/memos\x12f\n" +
@ -2522,8 +2523,8 @@ const file_api_v1_memo_service_proto_rawDesc = "" +
"\x0fCreateMemoShare\x12$.memos.api.v1.CreateMemoShareRequest\x1a\x17.memos.api.v1.MemoShare\"G\xdaA\x11parent,memo_share\x82\xd3\xe4\x93\x02-:\n" +
"memo_share\"\x1f/api/v1/{parent=memos/*}/shares\x12\x8d\x01\n" +
"\x0eListMemoShares\x12#.memos.api.v1.ListMemoSharesRequest\x1a$.memos.api.v1.ListMemoSharesResponse\"0\xdaA\x06parent\x82\xd3\xe4\x93\x02!\x12\x1f/api/v1/{parent=memos/*}/shares\x12\x7f\n" +
"\x0fDeleteMemoShare\x12$.memos.api.v1.DeleteMemoShareRequest\x1a\x16.google.protobuf.Empty\".\xdaA\x04name\x82\xd3\xe4\x93\x02!*\x1f/api/v1/{name=memos/*/shares/*}\x12l\n" +
"\x0eGetMemoByShare\x12#.memos.api.v1.GetMemoByShareRequest\x1a\x12.memos.api.v1.Memo\"!\x82\xd3\xe4\x93\x02\x1b\x12\x19/api/v1/shares/{share_id}\x12y\n" +
"\x0fDeleteMemoShare\x12$.memos.api.v1.DeleteMemoShareRequest\x1a\x16.google.protobuf.Empty\".\xdaA\x04name\x82\xd3\xe4\x93\x02!*\x1f/api/v1/{name=memos/*/shares/*}\x12r\n" +
"\rGetSharedMemo\x12\".memos.api.v1.GetSharedMemoRequest\x1a\x12.memos.api.v1.Memo\")\x82\xd3\xe4\x93\x02#\x12!/api/v1/shares/{share_token}/memo\x12y\n" +
"\x0fGetLinkMetadata\x12$.memos.api.v1.GetLinkMetadataRequest\x1a\x1a.memos.api.v1.LinkMetadata\"$\x82\xd3\xe4\x93\x02\x1e\x12\x1c/api/v1/memos/-/linkMetadata\x12\x9f\x01\n" +
"\x14BatchGetLinkMetadata\x12).memos.api.v1.BatchGetLinkMetadataRequest\x1a*.memos.api.v1.BatchGetLinkMetadataResponse\"0\x82\xd3\xe4\x93\x02*:\x01*\"%/api/v1/memos/-/linkMetadata:batchGetB\xa8\x01\n" +
"\x10com.memos.api.v1B\x10MemoServiceProtoP\x01Z0github.com/usememos/memos/proto/gen/api/v1;apiv1\xa2\x02\x03MAX\xaa\x02\fMemos.Api.V1\xca\x02\fMemos\\Api\\V1\xe2\x02\x18Memos\\Api\\V1\\GPBMetadata\xea\x02\x0eMemos::Api::V1b\x06proto3"
@ -2573,7 +2574,7 @@ var file_api_v1_memo_service_proto_goTypes = []any{
(*ListMemoSharesRequest)(nil), // 27: memos.api.v1.ListMemoSharesRequest
(*ListMemoSharesResponse)(nil), // 28: memos.api.v1.ListMemoSharesResponse
(*DeleteMemoShareRequest)(nil), // 29: memos.api.v1.DeleteMemoShareRequest
(*GetMemoByShareRequest)(nil), // 30: memos.api.v1.GetMemoByShareRequest
(*GetSharedMemoRequest)(nil), // 30: memos.api.v1.GetSharedMemoRequest
(*GetLinkMetadataRequest)(nil), // 31: memos.api.v1.GetLinkMetadataRequest
(*BatchGetLinkMetadataRequest)(nil), // 32: memos.api.v1.BatchGetLinkMetadataRequest
(*BatchGetLinkMetadataResponse)(nil), // 33: memos.api.v1.BatchGetLinkMetadataResponse
@ -2635,7 +2636,7 @@ var file_api_v1_memo_service_proto_depIdxs = []int32{
26, // 45: memos.api.v1.MemoService.CreateMemoShare:input_type -> memos.api.v1.CreateMemoShareRequest
27, // 46: memos.api.v1.MemoService.ListMemoShares:input_type -> memos.api.v1.ListMemoSharesRequest
29, // 47: memos.api.v1.MemoService.DeleteMemoShare:input_type -> memos.api.v1.DeleteMemoShareRequest
30, // 48: memos.api.v1.MemoService.GetMemoByShare:input_type -> memos.api.v1.GetMemoByShareRequest
30, // 48: memos.api.v1.MemoService.GetSharedMemo:input_type -> memos.api.v1.GetSharedMemoRequest
31, // 49: memos.api.v1.MemoService.GetLinkMetadata:input_type -> memos.api.v1.GetLinkMetadataRequest
32, // 50: memos.api.v1.MemoService.BatchGetLinkMetadata:input_type -> memos.api.v1.BatchGetLinkMetadataRequest
3, // 51: memos.api.v1.MemoService.CreateMemo:output_type -> memos.api.v1.Memo
@ -2655,7 +2656,7 @@ var file_api_v1_memo_service_proto_depIdxs = []int32{
25, // 65: memos.api.v1.MemoService.CreateMemoShare:output_type -> memos.api.v1.MemoShare
28, // 66: memos.api.v1.MemoService.ListMemoShares:output_type -> memos.api.v1.ListMemoSharesResponse
41, // 67: memos.api.v1.MemoService.DeleteMemoShare:output_type -> google.protobuf.Empty
3, // 68: memos.api.v1.MemoService.GetMemoByShare:output_type -> memos.api.v1.Memo
3, // 68: memos.api.v1.MemoService.GetSharedMemo:output_type -> memos.api.v1.Memo
34, // 69: memos.api.v1.MemoService.GetLinkMetadata:output_type -> memos.api.v1.LinkMetadata
33, // 70: memos.api.v1.MemoService.BatchGetLinkMetadata:output_type -> memos.api.v1.BatchGetLinkMetadataResponse
51, // [51:71] is the sub-list for method output_type

View file

@ -852,42 +852,42 @@ func local_request_MemoService_DeleteMemoShare_0(ctx context.Context, marshaler
return msg, metadata, err
}
func request_MemoService_GetMemoByShare_0(ctx context.Context, marshaler runtime.Marshaler, client MemoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
func request_MemoService_GetSharedMemo_0(ctx context.Context, marshaler runtime.Marshaler, client MemoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq GetMemoByShareRequest
protoReq GetSharedMemoRequest
metadata runtime.ServerMetadata
err error
)
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body)
}
val, ok := pathParams["share_id"]
val, ok := pathParams["share_token"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "share_id")
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "share_token")
}
protoReq.ShareId, err = runtime.String(val)
protoReq.ShareToken, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "share_id", err)
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "share_token", err)
}
msg, err := client.GetMemoByShare(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
msg, err := client.GetSharedMemo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_MemoService_GetMemoByShare_0(ctx context.Context, marshaler runtime.Marshaler, server MemoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
func local_request_MemoService_GetSharedMemo_0(ctx context.Context, marshaler runtime.Marshaler, server MemoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq GetMemoByShareRequest
protoReq GetSharedMemoRequest
metadata runtime.ServerMetadata
err error
)
val, ok := pathParams["share_id"]
val, ok := pathParams["share_token"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "share_id")
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "share_token")
}
protoReq.ShareId, err = runtime.String(val)
protoReq.ShareToken, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "share_id", err)
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "share_token", err)
}
msg, err := server.GetMemoByShare(ctx, &protoReq)
msg, err := server.GetSharedMemo(ctx, &protoReq)
return msg, metadata, err
}
@ -1299,25 +1299,25 @@ func RegisterMemoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux
}
forward_MemoService_DeleteMemoShare_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodGet, pattern_MemoService_GetMemoByShare_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle(http.MethodGet, pattern_MemoService_GetSharedMemo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.MemoService/GetMemoByShare", runtime.WithHTTPPathPattern("/api/v1/shares/{share_id}"))
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.MemoService/GetSharedMemo", runtime.WithHTTPPathPattern("/api/v1/shares/{share_token}/memo"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_MemoService_GetMemoByShare_0(annotatedContext, inboundMarshaler, server, req, pathParams)
resp, md, err := local_request_MemoService_GetSharedMemo_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_MemoService_GetMemoByShare_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_MemoService_GetSharedMemo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodGet, pattern_MemoService_GetLinkMetadata_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
@ -1688,22 +1688,22 @@ func RegisterMemoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
}
forward_MemoService_DeleteMemoShare_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodGet, pattern_MemoService_GetMemoByShare_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle(http.MethodGet, pattern_MemoService_GetSharedMemo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.MemoService/GetMemoByShare", runtime.WithHTTPPathPattern("/api/v1/shares/{share_id}"))
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.MemoService/GetSharedMemo", runtime.WithHTTPPathPattern("/api/v1/shares/{share_token}/memo"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_MemoService_GetMemoByShare_0(annotatedContext, inboundMarshaler, client, req, pathParams)
resp, md, err := request_MemoService_GetSharedMemo_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_MemoService_GetMemoByShare_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_MemoService_GetSharedMemo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodGet, pattern_MemoService_GetLinkMetadata_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
@ -1760,7 +1760,7 @@ var (
pattern_MemoService_CreateMemoShare_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "memos", "parent", "shares"}, ""))
pattern_MemoService_ListMemoShares_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "memos", "parent", "shares"}, ""))
pattern_MemoService_DeleteMemoShare_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "memos", "shares", "name"}, ""))
pattern_MemoService_GetMemoByShare_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "shares", "share_id"}, ""))
pattern_MemoService_GetSharedMemo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "shares", "share_token", "memo"}, ""))
pattern_MemoService_GetLinkMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"api", "v1", "memos", "-", "linkMetadata"}, ""))
pattern_MemoService_BatchGetLinkMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"api", "v1", "memos", "-", "linkMetadata"}, "batchGet"))
)
@ -1783,7 +1783,7 @@ var (
forward_MemoService_CreateMemoShare_0 = runtime.ForwardResponseMessage
forward_MemoService_ListMemoShares_0 = runtime.ForwardResponseMessage
forward_MemoService_DeleteMemoShare_0 = runtime.ForwardResponseMessage
forward_MemoService_GetMemoByShare_0 = runtime.ForwardResponseMessage
forward_MemoService_GetSharedMemo_0 = runtime.ForwardResponseMessage
forward_MemoService_GetLinkMetadata_0 = runtime.ForwardResponseMessage
forward_MemoService_BatchGetLinkMetadata_0 = runtime.ForwardResponseMessage
)

View file

@ -37,7 +37,7 @@ const (
MemoService_CreateMemoShare_FullMethodName = "/memos.api.v1.MemoService/CreateMemoShare"
MemoService_ListMemoShares_FullMethodName = "/memos.api.v1.MemoService/ListMemoShares"
MemoService_DeleteMemoShare_FullMethodName = "/memos.api.v1.MemoService/DeleteMemoShare"
MemoService_GetMemoByShare_FullMethodName = "/memos.api.v1.MemoService/GetMemoByShare"
MemoService_GetSharedMemo_FullMethodName = "/memos.api.v1.MemoService/GetSharedMemo"
MemoService_GetLinkMetadata_FullMethodName = "/memos.api.v1.MemoService/GetLinkMetadata"
MemoService_BatchGetLinkMetadata_FullMethodName = "/memos.api.v1.MemoService/BatchGetLinkMetadata"
)
@ -87,9 +87,9 @@ type MemoServiceClient interface {
ListMemoShares(ctx context.Context, in *ListMemoSharesRequest, opts ...grpc.CallOption) (*ListMemoSharesResponse, error)
// DeleteMemoShare revokes a share link. Requires authentication as the memo creator.
DeleteMemoShare(ctx context.Context, in *DeleteMemoShareRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// GetMemoByShare resolves a share token to its memo. No authentication required.
// GetSharedMemo resolves a share token to its memo. No authentication required.
// Returns NOT_FOUND if the token is invalid or expired.
GetMemoByShare(ctx context.Context, in *GetMemoByShareRequest, opts ...grpc.CallOption) (*Memo, error)
GetSharedMemo(ctx context.Context, in *GetSharedMemoRequest, opts ...grpc.CallOption) (*Memo, error)
// GetLinkMetadata gets metadata for a link.
GetLinkMetadata(ctx context.Context, in *GetLinkMetadataRequest, opts ...grpc.CallOption) (*LinkMetadata, error)
// BatchGetLinkMetadata gets metadata for links.
@ -274,10 +274,10 @@ func (c *memoServiceClient) DeleteMemoShare(ctx context.Context, in *DeleteMemoS
return out, nil
}
func (c *memoServiceClient) GetMemoByShare(ctx context.Context, in *GetMemoByShareRequest, opts ...grpc.CallOption) (*Memo, error) {
func (c *memoServiceClient) GetSharedMemo(ctx context.Context, in *GetSharedMemoRequest, opts ...grpc.CallOption) (*Memo, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Memo)
err := c.cc.Invoke(ctx, MemoService_GetMemoByShare_FullMethodName, in, out, cOpts...)
err := c.cc.Invoke(ctx, MemoService_GetSharedMemo_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
@ -349,9 +349,9 @@ type MemoServiceServer interface {
ListMemoShares(context.Context, *ListMemoSharesRequest) (*ListMemoSharesResponse, error)
// DeleteMemoShare revokes a share link. Requires authentication as the memo creator.
DeleteMemoShare(context.Context, *DeleteMemoShareRequest) (*emptypb.Empty, error)
// GetMemoByShare resolves a share token to its memo. No authentication required.
// GetSharedMemo resolves a share token to its memo. No authentication required.
// Returns NOT_FOUND if the token is invalid or expired.
GetMemoByShare(context.Context, *GetMemoByShareRequest) (*Memo, error)
GetSharedMemo(context.Context, *GetSharedMemoRequest) (*Memo, error)
// GetLinkMetadata gets metadata for a link.
GetLinkMetadata(context.Context, *GetLinkMetadataRequest) (*LinkMetadata, error)
// BatchGetLinkMetadata gets metadata for links.
@ -417,8 +417,8 @@ func (UnimplementedMemoServiceServer) ListMemoShares(context.Context, *ListMemoS
func (UnimplementedMemoServiceServer) DeleteMemoShare(context.Context, *DeleteMemoShareRequest) (*emptypb.Empty, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteMemoShare not implemented")
}
func (UnimplementedMemoServiceServer) GetMemoByShare(context.Context, *GetMemoByShareRequest) (*Memo, error) {
return nil, status.Error(codes.Unimplemented, "method GetMemoByShare not implemented")
func (UnimplementedMemoServiceServer) GetSharedMemo(context.Context, *GetSharedMemoRequest) (*Memo, error) {
return nil, status.Error(codes.Unimplemented, "method GetSharedMemo not implemented")
}
func (UnimplementedMemoServiceServer) GetLinkMetadata(context.Context, *GetLinkMetadataRequest) (*LinkMetadata, error) {
return nil, status.Error(codes.Unimplemented, "method GetLinkMetadata not implemented")
@ -753,20 +753,20 @@ func _MemoService_DeleteMemoShare_Handler(srv interface{}, ctx context.Context,
return interceptor(ctx, in, info, handler)
}
func _MemoService_GetMemoByShare_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetMemoByShareRequest)
func _MemoService_GetSharedMemo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetSharedMemoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MemoServiceServer).GetMemoByShare(ctx, in)
return srv.(MemoServiceServer).GetSharedMemo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MemoService_GetMemoByShare_FullMethodName,
FullMethod: MemoService_GetSharedMemo_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MemoServiceServer).GetMemoByShare(ctx, req.(*GetMemoByShareRequest))
return srv.(MemoServiceServer).GetSharedMemo(ctx, req.(*GetSharedMemoRequest))
}
return interceptor(ctx, in, info, handler)
}
@ -883,8 +883,8 @@ var MemoService_ServiceDesc = grpc.ServiceDesc{
Handler: _MemoService_DeleteMemoShare_Handler,
},
{
MethodName: "GetMemoByShare",
Handler: _MemoService_GetMemoByShare_Handler,
MethodName: "GetSharedMemo",
Handler: _MemoService_GetSharedMemo_Handler,
},
{
MethodName: "GetLinkMetadata",

View file

@ -1266,18 +1266,18 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Status'
/api/v1/shares/{shareId}:
/api/v1/shares/{shareToken}/memo:
get:
tags:
- MemoService
description: |-
GetMemoByShare resolves a share token to its memo. No authentication required.
GetSharedMemo resolves a share token to its memo. No authentication required.
Returns NOT_FOUND if the token is invalid or expired.
operationId: MemoService_GetMemoByShare
operationId: MemoService_GetSharedMemo
parameters:
- name: shareId
- name: shareToken
in: path
description: Required. The share token extracted from the share URL (/s/{share_id}).
description: Required. The opaque bearer token extracted from the share URL.
required: true
schema:
type: string

View file

@ -37,7 +37,7 @@ var PublicMethods = map[string]struct{}{
"/memos.api.v1.MemoService/BatchGetLinkMetadata": {},
// Memo sharing - share-token endpoints require no authentication
"/memos.api.v1.MemoService/GetMemoByShare": {},
"/memos.api.v1.MemoService/GetSharedMemo": {},
}
// IsPublicMethod checks if a procedure path is public (no authentication required).
@ -70,7 +70,7 @@ var AuthBootstrapMethods = map[string]struct{}{
"/memos.api.v1.UserService/CreateUser": {},
// Memo sharing - share-token access stays public even on a private instance.
"/memos.api.v1.MemoService/GetMemoByShare": {},
"/memos.api.v1.MemoService/GetSharedMemo": {},
}
// IsAuthBootstrapMethod reports whether an anonymous request to procedure is one

View file

@ -112,7 +112,7 @@ func TestAuthBootstrapClassification(t *testing.T) {
"/memos.api.v1.InstanceService/GetInstanceSetting",
"/memos.api.v1.InstanceService/BatchGetInstanceSettings",
"/memos.api.v1.IdentityProviderService/ListIdentityProviders",
"/memos.api.v1.MemoService/GetMemoByShare",
"/memos.api.v1.MemoService/GetSharedMemo",
}
for _, method := range bootstrap {
t.Run("bootstrap/"+method, func(t *testing.T) {

View file

@ -25,7 +25,7 @@ func TestAuthorizerCheckAccess(t *testing.T) {
publicMethod = "/memos.api.v1.MemoService/ListMemos"
bootstrapMethod = "/memos.api.v1.AuthService/SignIn"
createUser = "/memos.api.v1.UserService/CreateUser"
shareMethod = "/memos.api.v1.MemoService/GetMemoByShare"
shareMethod = "/memos.api.v1.MemoService/GetSharedMemo"
)
cases := []struct {

View file

@ -439,8 +439,8 @@ func (s *ConnectServiceHandler) DeleteMemoShare(ctx context.Context, req *connec
return connect.NewResponse(resp), nil
}
func (s *ConnectServiceHandler) GetMemoByShare(ctx context.Context, req *connect.Request[v1pb.GetMemoByShareRequest]) (*connect.Response[v1pb.Memo], error) {
resp, err := s.APIV1Service.GetMemoByShare(ctx, req.Msg)
func (s *ConnectServiceHandler) GetSharedMemo(ctx context.Context, req *connect.Request[v1pb.GetSharedMemoRequest]) (*connect.Response[v1pb.Memo], error) {
resp, err := s.APIV1Service.GetSharedMemo(ctx, req.Msg)
if err != nil {
return nil, convertGRPCError(err)
}

View file

@ -148,10 +148,10 @@ func (s *APIV1Service) DeleteMemoShare(ctx context.Context, request *v1pb.Delete
return &emptypb.Empty{}, nil
}
// GetMemoByShare resolves a share token to its memo. No authentication required.
// GetSharedMemo resolves a share token to its memo. No authentication required.
// Returns NOT_FOUND for invalid or expired tokens (no information leakage).
func (s *APIV1Service) GetMemoByShare(ctx context.Context, request *v1pb.GetMemoByShareRequest) (*v1pb.Memo, error) {
ms, err := s.getActiveMemoShare(ctx, request.ShareId)
func (s *APIV1Service) GetSharedMemo(ctx context.Context, request *v1pb.GetSharedMemoRequest) (*v1pb.Memo, error) {
ms, err := s.getActiveMemoShare(ctx, request.ShareToken)
if err != nil {
return nil, err
}

View file

@ -26,10 +26,10 @@ func TestAuthorizerPrivateInstanceRegistration(t *testing.T) {
authorizer := apiv1.NewAuthorizer(ts.Store, ts.Secret, &profile.Profile{InstanceURL: ""})
const (
createUser = "/memos.api.v1.UserService/CreateUser"
signIn = "/memos.api.v1.AuthService/SignIn"
listMemos = "/memos.api.v1.MemoService/ListMemos"
getMemoShare = "/memos.api.v1.MemoService/GetMemoByShare"
createUser = "/memos.api.v1.UserService/CreateUser"
signIn = "/memos.api.v1.AuthService/SignIn"
listMemos = "/memos.api.v1.MemoService/ListMemos"
getSharedMemo = "/memos.api.v1.MemoService/GetSharedMemo"
)
// Anonymous request with no Authorization header resolves to no identity.
@ -38,7 +38,7 @@ func TestAuthorizerPrivateInstanceRegistration(t *testing.T) {
// Registration and other bootstrap methods are allowed; browsing is still gated.
require.NoError(t, authorizer.CheckAccess(ctx, createUser, nil))
require.NoError(t, authorizer.CheckAccess(ctx, signIn, nil))
require.NoError(t, authorizer.CheckAccess(ctx, getMemoShare, nil))
require.NoError(t, authorizer.CheckAccess(ctx, getSharedMemo, nil))
require.ErrorIs(t, authorizer.CheckAccess(ctx, listMemos, nil), apiv1.ErrUnauthenticated)
// Once a user exists, CreateUser remains reachable so UserService can enforce

View file

@ -59,14 +59,14 @@ func TestDeleteMemoShare_VerifiesShareBelongsToMemo(t *testing.T) {
require.Error(t, err)
require.Equal(t, codes.NotFound, status.Code(err))
sharedMemo, err := ts.Service.GetMemoByShare(ctx, &apiv1.GetMemoByShareRequest{
ShareId: shareToken,
sharedMemo, err := ts.Service.GetSharedMemo(ctx, &apiv1.GetSharedMemoRequest{
ShareToken: shareToken,
})
require.NoError(t, err)
require.Equal(t, memoTwo.Name, sharedMemo.Name)
}
func TestGetMemoByShare_IncludesReactions(t *testing.T) {
func TestGetSharedMemo_IncludesReactions(t *testing.T) {
ctx := context.Background()
ts := NewTestService(t)
@ -101,8 +101,8 @@ func TestGetMemoByShare_IncludesReactions(t *testing.T) {
require.NoError(t, err)
shareToken := share.Name[strings.LastIndex(share.Name, "/")+1:]
sharedMemo, err := ts.Service.GetMemoByShare(ctx, &apiv1.GetMemoByShareRequest{
ShareId: shareToken,
sharedMemo, err := ts.Service.GetSharedMemo(ctx, &apiv1.GetSharedMemoRequest{
ShareToken: shareToken,
})
require.NoError(t, err)
require.Len(t, sharedMemo.Reactions, 1)
@ -110,7 +110,7 @@ func TestGetMemoByShare_IncludesReactions(t *testing.T) {
require.Equal(t, memo.Name, sharedMemo.Reactions[0].ContentId)
}
func TestGetMemoByShare_SkipsReactionsWithMissingCreators(t *testing.T) {
func TestGetSharedMemo_SkipsReactionsWithMissingCreators(t *testing.T) {
ctx := context.Background()
ts := NewTestService(t)
@ -151,27 +151,27 @@ func TestGetMemoByShare_SkipsReactionsWithMissingCreators(t *testing.T) {
require.NoError(t, err)
shareToken := share.Name[strings.LastIndex(share.Name, "/")+1:]
sharedMemo, err := ts.Service.GetMemoByShare(ctx, &apiv1.GetMemoByShareRequest{
ShareId: shareToken,
sharedMemo, err := ts.Service.GetSharedMemo(ctx, &apiv1.GetSharedMemoRequest{
ShareToken: shareToken,
})
require.NoError(t, err)
require.Empty(t, sharedMemo.Reactions)
}
func TestGetMemoByShare_ReturnsNotFoundForUnknownShare(t *testing.T) {
func TestGetSharedMemo_ReturnsNotFoundForUnknownShare(t *testing.T) {
ctx := context.Background()
ts := NewTestService(t)
defer ts.Cleanup()
_, err := ts.Service.GetMemoByShare(ctx, &apiv1.GetMemoByShareRequest{
ShareId: "missing-share-token",
_, err := ts.Service.GetSharedMemo(ctx, &apiv1.GetSharedMemoRequest{
ShareToken: "missing-share-token",
})
require.Error(t, err)
require.Equal(t, codes.NotFound, status.Code(err))
}
func TestGetMemoByShare_ReturnsNotFoundForExpiredShare(t *testing.T) {
func TestGetSharedMemo_ReturnsNotFoundForExpiredShare(t *testing.T) {
ctx := context.Background()
ts := NewTestService(t)
@ -198,14 +198,14 @@ func TestGetMemoByShare_ReturnsNotFoundForExpiredShare(t *testing.T) {
})
require.NoError(t, err)
_, err = ts.Service.GetMemoByShare(ctx, &apiv1.GetMemoByShareRequest{
ShareId: expiredShare.UID,
_, err = ts.Service.GetSharedMemo(ctx, &apiv1.GetSharedMemoRequest{
ShareToken: expiredShare.UID,
})
require.Error(t, err)
require.Equal(t, codes.NotFound, status.Code(err))
}
func TestGetMemoByShare_ReturnsNotFoundForArchivedMemo(t *testing.T) {
func TestGetSharedMemo_ReturnsNotFoundForArchivedMemo(t *testing.T) {
ctx := context.Background()
ts := NewTestService(t)
@ -242,8 +242,8 @@ func TestGetMemoByShare_ReturnsNotFoundForArchivedMemo(t *testing.T) {
require.NoError(t, err)
shareToken := share.Name[strings.LastIndex(share.Name, "/")+1:]
_, err = ts.Service.GetMemoByShare(ctx, &apiv1.GetMemoByShareRequest{
ShareId: shareToken,
_, err = ts.Service.GetSharedMemo(ctx, &apiv1.GetSharedMemoRequest{
ShareToken: shareToken,
})
require.Error(t, err)
require.Equal(t, codes.NotFound, status.Code(err))

View file

@ -7,7 +7,7 @@ import type { MemoShare } from "@/types/proto/api/v1/memo_service_pb";
import {
CreateMemoShareRequestSchema,
DeleteMemoShareRequestSchema,
GetMemoByShareRequestSchema,
GetSharedMemoRequestSchema,
ListMemoSharesRequestSchema,
MemoShareSchema,
} from "@/types/proto/api/v1/memo_service_pb";
@ -16,7 +16,7 @@ import {
export const memoShareKeys = {
all: ["memo-shares"] as const,
list: (memoName: string) => [...memoShareKeys.all, "list", memoName] as const,
byShare: (shareId: string) => [...memoShareKeys.all, "by-share", shareId] as const,
byShare: (shareToken: string) => [...memoShareKeys.all, "by-share", shareToken] as const,
};
/** Lists all active share links for a memo (creator-only). */
@ -63,14 +63,14 @@ export function useDeleteMemoShare() {
}
/** Resolves a share token to its memo. Used by the public SharedMemo page. */
export function useSharedMemo(shareId: string, options?: { enabled?: boolean }) {
export function useSharedMemo(shareToken: string, options?: { enabled?: boolean }) {
return useQuery({
queryKey: memoShareKeys.byShare(shareId),
queryKey: memoShareKeys.byShare(shareToken),
queryFn: async () => {
const memo = await memoServiceClient.getMemoByShare(create(GetMemoByShareRequestSchema, { shareId }));
const memo = await memoServiceClient.getSharedMemo(create(GetSharedMemoRequestSchema, { shareToken }));
return memo;
},
enabled: options?.enabled ?? !!shareId,
enabled: options?.enabled ?? !!shareToken,
retry: false, // Don't retry NOT_FOUND — the link is invalid or expired
});
}

File diff suppressed because one or more lines are too long