From 1a2bb225529911c69bafb1aaefab87ecbe4a6077 Mon Sep 17 00:00:00 2001 From: Youngteac Hong Date: Tue, 8 Apr 2025 19:23:25 +0900 Subject: [PATCH] Add schema support --- packages/schema/{src => public}/style.css | 0 packages/schema/src/index.ts | 1 + packages/schema/src/rulesets.ts | 116 ++++++ packages/schema/test/ruleset.test.ts | 75 ++++ .../{schema.test.ts => validator.test.ts} | 0 packages/sdk/public/index.html | 1 + .../sdk/src/api/yorkie/v1/resources.proto | 52 ++- .../sdk/src/api/yorkie/v1/resources_pb.ts | 331 +++++++++++++++++- packages/sdk/src/api/yorkie/v1/yorkie.proto | 1 + .../sdk/src/api/yorkie/v1/yorkie_connect.ts | 2 +- packages/sdk/src/api/yorkie/v1/yorkie_pb.ts | 6 + packages/sdk/src/client/client.ts | 7 + 12 files changed, 572 insertions(+), 20 deletions(-) rename packages/schema/{src => public}/style.css (100%) create mode 100644 packages/schema/src/rulesets.ts create mode 100644 packages/schema/test/ruleset.test.ts rename packages/schema/test/{schema.test.ts => validator.test.ts} (100%) diff --git a/packages/schema/src/style.css b/packages/schema/public/style.css similarity index 100% rename from packages/schema/src/style.css rename to packages/schema/public/style.css diff --git a/packages/schema/src/index.ts b/packages/schema/src/index.ts index ef10f05be..972d03a11 100644 --- a/packages/schema/src/index.ts +++ b/packages/schema/src/index.ts @@ -15,3 +15,4 @@ */ export { validate } from './validator'; +export { buildRuleset } from './rulesets'; diff --git a/packages/schema/src/rulesets.ts b/packages/schema/src/rulesets.ts new file mode 100644 index 000000000..ba89fe43b --- /dev/null +++ b/packages/schema/src/rulesets.ts @@ -0,0 +1,116 @@ +/* + * Copyright 2025 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CharStreams, CommonTokenStream } from 'antlr4ts'; +import { ParseTreeWalker } from 'antlr4ts/tree'; +import { + PrimitiveTypeContext, + PropertyNameContext, + TypeAliasDeclarationContext, + YorkieSchemaParser, +} from '../antlr/YorkieSchemaParser'; +import { YorkieSchemaLexer } from '../antlr/YorkieSchemaLexer'; +import { YorkieSchemaListener } from '../antlr/YorkieSchemaListener'; + +/** + * `Rule` represents a rule for a field in the schema. + */ +export type Rule = StringRule | ObjectRule | ArrayRule; +export type RuleType = 'string' | 'object' | 'array'; + +export type RuleBase = { + path: string; + type: RuleType; +}; + +export type StringRule = { + type: 'string'; +} & RuleBase; + +export type ObjectRule = { + type: 'object'; + properties: { [key: string]: RuleBase }; +} & RuleBase; + +export type ArrayRule = { + type: 'array'; +} & RuleBase; + +/** + * `RulesetBuilder` is a visitor that builds a ruleset from the given schema. + */ +export class RulesetBuilder implements YorkieSchemaListener { + private currentPath: Array = ['$']; + private ruleMap: Map = new Map(); + + /** + * `enterTypeAliasDeclaration` is called when entering a type alias declaration. + */ + enterTypeAliasDeclaration(ctx: TypeAliasDeclarationContext) { + const typeName = ctx.Identifier().text; + if (typeName === 'Document') { + this.currentPath = ['$']; + } + } + + /** + * `enterPropertyName` is called when entering a property name. + */ + enterPropertyName(ctx: PropertyNameContext) { + const propName = ctx.Identifier()!.text; + this.currentPath.push(propName); + } + + /** + * `enterPrimitiveType` is called when entering a primitive type. + */ + enterPrimitiveType(ctx: PrimitiveTypeContext) { + const type = ctx.text; + const path = this.buildPath(); + const rule = { + path, + type, + } as Rule; + + this.ruleMap.set(path, rule); + this.currentPath.pop(); + } + + private buildPath(): string { + return this.currentPath.join('.'); + } + + /** + * `build` returns the built ruleset. + */ + build(): Map { + return this.ruleMap; + } +} + +/** + * `buildRuleset` builds a ruleset from the given schema string. + */ +export function buildRuleset(schema: string): Map { + const stream = CharStreams.fromString(schema); + const lexer = new YorkieSchemaLexer(stream); + const tokens = new CommonTokenStream(lexer); + const parser = new YorkieSchemaParser(tokens); + const tree = parser.document(); + const builder = new RulesetBuilder(); + ParseTreeWalker.DEFAULT.walk(builder as any, tree); + return builder.build(); +} diff --git a/packages/schema/test/ruleset.test.ts b/packages/schema/test/ruleset.test.ts new file mode 100644 index 000000000..df27d3aaf --- /dev/null +++ b/packages/schema/test/ruleset.test.ts @@ -0,0 +1,75 @@ +/* + * Copyright 2025 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, it, expect } from 'vitest'; +import { buildRuleset } from '../src/rulesets'; + +describe('RulesetBuilder', () => { + it('should create rules for simple document', () => { + const schema = ` + type Document = { + name: string; + age: number; + }; + `; + + const ruleset = buildRuleset(schema); + expect(ruleset.get('$.name')!.type).to.eq('string'); + expect(ruleset.get('$.age')!.type).to.eq('number'); + }); + + it('should handle nested objects', () => { + const schema = ` + type Document = { + user: User; + }; + + type User = { + name: string; + address: Address; + }; + + type Address = { + street: string; + city: string; + }; + `; + + const ruleset = buildRuleset(schema); + expect(ruleset.get('$.user.name')!.type).to.eq('string'); + expect(ruleset.get('$.user.address.street')!.type).to.eq('string'); + expect(ruleset.get('$.user.address.city')!.type).to.eq('string'); + }); + + // TODO(hackerwins): Implement array type handling. + it.todo('should handle array types', () => { + const schema = ` + type Document = { + todos: Array; + }; + + type Todo = { + id: string; + text: string; + }; + `; + + const ruleset = buildRuleset(schema); + expect(ruleset.get('$.todos')!.type).to.eq('array'); + expect(ruleset.get('$.todos[*].id')!.type).to.be('string'); + expect(ruleset.get('$.todos[*].text')!.type).to.be('string'); + }); +}); diff --git a/packages/schema/test/schema.test.ts b/packages/schema/test/validator.test.ts similarity index 100% rename from packages/schema/test/schema.test.ts rename to packages/schema/test/validator.test.ts diff --git a/packages/sdk/public/index.html b/packages/sdk/public/index.html index c03952e5f..f9f039633 100644 --- a/packages/sdk/public/index.html +++ b/packages/sdk/public/index.html @@ -340,6 +340,7 @@

await client.attach(doc, { initialPresence: { color: getRandomColor() }, + schema: 'test@1', }); doc.update((root) => { diff --git a/packages/sdk/src/api/yorkie/v1/resources.proto b/packages/sdk/src/api/yorkie/v1/resources.proto index 547ec6c55..62fa52e47 100644 --- a/packages/sdk/src/api/yorkie/v1/resources.proto +++ b/packages/sdk/src/api/yorkie/v1/resources.proto @@ -47,6 +47,7 @@ message ChangePack { TimeTicket min_synced_ticket = 5; bool is_removed = 6; VersionVector version_vector = 7; + repeated Rule rules = 8; } message Change { @@ -286,8 +287,9 @@ message TreePos { message User { string id = 1; - string username = 2; - google.protobuf.Timestamp created_at = 3; + string auth_provider = 2; + string username = 3; + google.protobuf.Timestamp created_at = 4; } message Project { @@ -297,9 +299,19 @@ message Project { string secret_key = 4; string auth_webhook_url = 5; repeated string auth_webhook_methods = 6; - string client_deactivate_threshold = 7; - google.protobuf.Timestamp created_at = 8; - google.protobuf.Timestamp updated_at = 9; + string event_webhook_url = 7; + repeated string event_webhook_events = 8; + string client_deactivate_threshold = 9; + int32 max_subscribers_per_document = 10; + int32 max_attachments_per_document = 11; + repeated string allowed_origins = 14; + google.protobuf.Timestamp created_at = 12; + google.protobuf.Timestamp updated_at = 13; +} + +message MetricPoint { + int64 timestamp = 1; + int32 value = 2; } message UpdatableProjectFields { @@ -307,16 +319,30 @@ message UpdatableProjectFields { repeated string methods = 1; } + message EventWebhookEvents { + repeated string events = 1; + } + + message AllowedOrigins { + repeated string origins = 1; + } + google.protobuf.StringValue name = 1; google.protobuf.StringValue auth_webhook_url = 2; AuthWebhookMethods auth_webhook_methods = 3; - google.protobuf.StringValue client_deactivate_threshold = 4; + google.protobuf.StringValue event_webhook_url = 4; + EventWebhookEvents event_webhook_events = 5; + google.protobuf.StringValue client_deactivate_threshold = 6; + google.protobuf.Int32Value max_subscribers_per_document = 7; + google.protobuf.Int32Value max_attachments_per_document = 8; + AllowedOrigins allowed_origins = 9; } message DocumentSummary { string id = 1; string key = 2; string snapshot = 3; + int32 attached_clients = 7; google.protobuf.Timestamp created_at = 4; google.protobuf.Timestamp accessed_at = 5; google.protobuf.Timestamp updated_at = 6; @@ -388,3 +414,17 @@ message DocEvent { string publisher = 2; DocEventBody body = 3; } + +message Schema { + string id = 1; + string name = 2; + int32 version = 3; + string body = 4; + repeated Rule rules = 5; + google.protobuf.Timestamp created_at = 6; +} + +message Rule { + string path = 1; + string type = 2; +} diff --git a/packages/sdk/src/api/yorkie/v1/resources_pb.ts b/packages/sdk/src/api/yorkie/v1/resources_pb.ts index 9297e1fb0..b38e71002 100644 --- a/packages/sdk/src/api/yorkie/v1/resources_pb.ts +++ b/packages/sdk/src/api/yorkie/v1/resources_pb.ts @@ -19,7 +19,7 @@ // @ts-nocheck import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; -import { Message, proto3, protoInt64, StringValue, Timestamp } from "@bufbuild/protobuf"; +import { Int32Value, Message, proto3, protoInt64, StringValue, Timestamp } from "@bufbuild/protobuf"; /** * @generated from enum yorkie.v1.ValueType @@ -234,6 +234,11 @@ export class ChangePack extends Message { */ versionVector?: VersionVector; + /** + * @generated from field: repeated yorkie.v1.Rule rules = 8; + */ + rules: Rule[] = []; + constructor(data?: PartialMessage) { super(); proto3.util.initPartial(data, this); @@ -249,6 +254,7 @@ export class ChangePack extends Message { { no: 5, name: "min_synced_ticket", kind: "message", T: TimeTicket }, { no: 6, name: "is_removed", kind: "scalar", T: 8 /* ScalarType.BOOL */ }, { no: 7, name: "version_vector", kind: "message", T: VersionVector }, + { no: 8, name: "rules", kind: "message", T: Rule, repeated: true }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): ChangePack { @@ -2130,12 +2136,17 @@ export class User extends Message { id = ""; /** - * @generated from field: string username = 2; + * @generated from field: string auth_provider = 2; + */ + authProvider = ""; + + /** + * @generated from field: string username = 3; */ username = ""; /** - * @generated from field: google.protobuf.Timestamp created_at = 3; + * @generated from field: google.protobuf.Timestamp created_at = 4; */ createdAt?: Timestamp; @@ -2148,8 +2159,9 @@ export class User extends Message { static readonly typeName = "yorkie.v1.User"; static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, - { no: 2, name: "username", kind: "scalar", T: 9 /* ScalarType.STRING */ }, - { no: 3, name: "created_at", kind: "message", T: Timestamp }, + { no: 2, name: "auth_provider", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "username", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 4, name: "created_at", kind: "message", T: Timestamp }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): User { @@ -2204,17 +2216,42 @@ export class Project extends Message { authWebhookMethods: string[] = []; /** - * @generated from field: string client_deactivate_threshold = 7; + * @generated from field: string event_webhook_url = 7; + */ + eventWebhookUrl = ""; + + /** + * @generated from field: repeated string event_webhook_events = 8; + */ + eventWebhookEvents: string[] = []; + + /** + * @generated from field: string client_deactivate_threshold = 9; */ clientDeactivateThreshold = ""; /** - * @generated from field: google.protobuf.Timestamp created_at = 8; + * @generated from field: int32 max_subscribers_per_document = 10; + */ + maxSubscribersPerDocument = 0; + + /** + * @generated from field: int32 max_attachments_per_document = 11; + */ + maxAttachmentsPerDocument = 0; + + /** + * @generated from field: repeated string allowed_origins = 14; + */ + allowedOrigins: string[] = []; + + /** + * @generated from field: google.protobuf.Timestamp created_at = 12; */ createdAt?: Timestamp; /** - * @generated from field: google.protobuf.Timestamp updated_at = 9; + * @generated from field: google.protobuf.Timestamp updated_at = 13; */ updatedAt?: Timestamp; @@ -2232,9 +2269,14 @@ export class Project extends Message { { no: 4, name: "secret_key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 5, name: "auth_webhook_url", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 6, name: "auth_webhook_methods", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, - { no: 7, name: "client_deactivate_threshold", kind: "scalar", T: 9 /* ScalarType.STRING */ }, - { no: 8, name: "created_at", kind: "message", T: Timestamp }, - { no: 9, name: "updated_at", kind: "message", T: Timestamp }, + { no: 7, name: "event_webhook_url", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 8, name: "event_webhook_events", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + { no: 9, name: "client_deactivate_threshold", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 10, name: "max_subscribers_per_document", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 11, name: "max_attachments_per_document", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 14, name: "allowed_origins", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + { no: 12, name: "created_at", kind: "message", T: Timestamp }, + { no: 13, name: "updated_at", kind: "message", T: Timestamp }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): Project { @@ -2254,6 +2296,49 @@ export class Project extends Message { } } +/** + * @generated from message yorkie.v1.MetricPoint + */ +export class MetricPoint extends Message { + /** + * @generated from field: int64 timestamp = 1; + */ + timestamp = protoInt64.zero; + + /** + * @generated from field: int32 value = 2; + */ + value = 0; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "yorkie.v1.MetricPoint"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "timestamp", kind: "scalar", T: 3 /* ScalarType.INT64 */ }, + { no: 2, name: "value", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): MetricPoint { + return new MetricPoint().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): MetricPoint { + return new MetricPoint().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): MetricPoint { + return new MetricPoint().fromJsonString(jsonString, options); + } + + static equals(a: MetricPoint | PlainMessage | undefined, b: MetricPoint | PlainMessage | undefined): boolean { + return proto3.util.equals(MetricPoint, a, b); + } +} + /** * @generated from message yorkie.v1.UpdatableProjectFields */ @@ -2274,10 +2359,35 @@ export class UpdatableProjectFields extends Message { authWebhookMethods?: UpdatableProjectFields_AuthWebhookMethods; /** - * @generated from field: google.protobuf.StringValue client_deactivate_threshold = 4; + * @generated from field: google.protobuf.StringValue event_webhook_url = 4; + */ + eventWebhookUrl?: string; + + /** + * @generated from field: yorkie.v1.UpdatableProjectFields.EventWebhookEvents event_webhook_events = 5; + */ + eventWebhookEvents?: UpdatableProjectFields_EventWebhookEvents; + + /** + * @generated from field: google.protobuf.StringValue client_deactivate_threshold = 6; */ clientDeactivateThreshold?: string; + /** + * @generated from field: google.protobuf.Int32Value max_subscribers_per_document = 7; + */ + maxSubscribersPerDocument?: number; + + /** + * @generated from field: google.protobuf.Int32Value max_attachments_per_document = 8; + */ + maxAttachmentsPerDocument?: number; + + /** + * @generated from field: yorkie.v1.UpdatableProjectFields.AllowedOrigins allowed_origins = 9; + */ + allowedOrigins?: UpdatableProjectFields_AllowedOrigins; + constructor(data?: PartialMessage) { super(); proto3.util.initPartial(data, this); @@ -2289,7 +2399,12 @@ export class UpdatableProjectFields extends Message { { no: 1, name: "name", kind: "message", T: StringValue }, { no: 2, name: "auth_webhook_url", kind: "message", T: StringValue }, { no: 3, name: "auth_webhook_methods", kind: "message", T: UpdatableProjectFields_AuthWebhookMethods }, - { no: 4, name: "client_deactivate_threshold", kind: "message", T: StringValue }, + { no: 4, name: "event_webhook_url", kind: "message", T: StringValue }, + { no: 5, name: "event_webhook_events", kind: "message", T: UpdatableProjectFields_EventWebhookEvents }, + { no: 6, name: "client_deactivate_threshold", kind: "message", T: StringValue }, + { no: 7, name: "max_subscribers_per_document", kind: "message", T: Int32Value }, + { no: 8, name: "max_attachments_per_document", kind: "message", T: Int32Value }, + { no: 9, name: "allowed_origins", kind: "message", T: UpdatableProjectFields_AllowedOrigins }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): UpdatableProjectFields { @@ -2346,6 +2461,80 @@ export class UpdatableProjectFields_AuthWebhookMethods extends Message { + /** + * @generated from field: repeated string events = 1; + */ + events: string[] = []; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "yorkie.v1.UpdatableProjectFields.EventWebhookEvents"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "events", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): UpdatableProjectFields_EventWebhookEvents { + return new UpdatableProjectFields_EventWebhookEvents().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): UpdatableProjectFields_EventWebhookEvents { + return new UpdatableProjectFields_EventWebhookEvents().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): UpdatableProjectFields_EventWebhookEvents { + return new UpdatableProjectFields_EventWebhookEvents().fromJsonString(jsonString, options); + } + + static equals(a: UpdatableProjectFields_EventWebhookEvents | PlainMessage | undefined, b: UpdatableProjectFields_EventWebhookEvents | PlainMessage | undefined): boolean { + return proto3.util.equals(UpdatableProjectFields_EventWebhookEvents, a, b); + } +} + +/** + * @generated from message yorkie.v1.UpdatableProjectFields.AllowedOrigins + */ +export class UpdatableProjectFields_AllowedOrigins extends Message { + /** + * @generated from field: repeated string origins = 1; + */ + origins: string[] = []; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "yorkie.v1.UpdatableProjectFields.AllowedOrigins"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "origins", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): UpdatableProjectFields_AllowedOrigins { + return new UpdatableProjectFields_AllowedOrigins().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): UpdatableProjectFields_AllowedOrigins { + return new UpdatableProjectFields_AllowedOrigins().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): UpdatableProjectFields_AllowedOrigins { + return new UpdatableProjectFields_AllowedOrigins().fromJsonString(jsonString, options); + } + + static equals(a: UpdatableProjectFields_AllowedOrigins | PlainMessage | undefined, b: UpdatableProjectFields_AllowedOrigins | PlainMessage | undefined): boolean { + return proto3.util.equals(UpdatableProjectFields_AllowedOrigins, a, b); + } +} + /** * @generated from message yorkie.v1.DocumentSummary */ @@ -2365,6 +2554,11 @@ export class DocumentSummary extends Message { */ snapshot = ""; + /** + * @generated from field: int32 attached_clients = 7; + */ + attachedClients = 0; + /** * @generated from field: google.protobuf.Timestamp created_at = 4; */ @@ -2391,6 +2585,7 @@ export class DocumentSummary extends Message { { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "key", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 3, name: "snapshot", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 7, name: "attached_clients", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, { no: 4, name: "created_at", kind: "message", T: Timestamp }, { no: 5, name: "accessed_at", kind: "message", T: Timestamp }, { no: 6, name: "updated_at", kind: "message", T: Timestamp }, @@ -2758,3 +2953,113 @@ export class DocEvent extends Message { } } +/** + * @generated from message yorkie.v1.Schema + */ +export class Schema extends Message { + /** + * @generated from field: string id = 1; + */ + id = ""; + + /** + * @generated from field: string name = 2; + */ + name = ""; + + /** + * @generated from field: int32 version = 3; + */ + version = 0; + + /** + * @generated from field: string body = 4; + */ + body = ""; + + /** + * @generated from field: repeated yorkie.v1.Rule rules = 5; + */ + rules: Rule[] = []; + + /** + * @generated from field: google.protobuf.Timestamp created_at = 6; + */ + createdAt?: Timestamp; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "yorkie.v1.Schema"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "name", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 3, name: "version", kind: "scalar", T: 5 /* ScalarType.INT32 */ }, + { no: 4, name: "body", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 5, name: "rules", kind: "message", T: Rule, repeated: true }, + { no: 6, name: "created_at", kind: "message", T: Timestamp }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): Schema { + return new Schema().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): Schema { + return new Schema().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): Schema { + return new Schema().fromJsonString(jsonString, options); + } + + static equals(a: Schema | PlainMessage | undefined, b: Schema | PlainMessage | undefined): boolean { + return proto3.util.equals(Schema, a, b); + } +} + +/** + * @generated from message yorkie.v1.Rule + */ +export class Rule extends Message { + /** + * @generated from field: string path = 1; + */ + path = ""; + + /** + * @generated from field: string type = 2; + */ + type = ""; + + constructor(data?: PartialMessage) { + super(); + proto3.util.initPartial(data, this); + } + + static readonly runtime: typeof proto3 = proto3; + static readonly typeName = "yorkie.v1.Rule"; + static readonly fields: FieldList = proto3.util.newFieldList(() => [ + { no: 1, name: "path", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 2, name: "type", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): Rule { + return new Rule().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): Rule { + return new Rule().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): Rule { + return new Rule().fromJsonString(jsonString, options); + } + + static equals(a: Rule | PlainMessage | undefined, b: Rule | PlainMessage | undefined): boolean { + return proto3.util.equals(Rule, a, b); + } +} + diff --git a/packages/sdk/src/api/yorkie/v1/yorkie.proto b/packages/sdk/src/api/yorkie/v1/yorkie.proto index 49e819a18..3015193b0 100644 --- a/packages/sdk/src/api/yorkie/v1/yorkie.proto +++ b/packages/sdk/src/api/yorkie/v1/yorkie.proto @@ -58,6 +58,7 @@ message DeactivateClientResponse { message AttachDocumentRequest { string client_id = 1; ChangePack change_pack = 2; + string schema = 3; } message AttachDocumentResponse { diff --git a/packages/sdk/src/api/yorkie/v1/yorkie_connect.ts b/packages/sdk/src/api/yorkie/v1/yorkie_connect.ts index a02610c3e..4fbfb8055 100644 --- a/packages/sdk/src/api/yorkie/v1/yorkie_connect.ts +++ b/packages/sdk/src/api/yorkie/v1/yorkie_connect.ts @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// @generated by protoc-gen-connect-es v1.4.0 with parameter "target=ts,import_extension=none" +// @generated by protoc-gen-connect-es v1.6.1 with parameter "target=ts,import_extension=none" // @generated from file src/api/yorkie/v1/yorkie.proto (package yorkie.v1, syntax proto3) /* eslint-disable */ // @ts-nocheck diff --git a/packages/sdk/src/api/yorkie/v1/yorkie_pb.ts b/packages/sdk/src/api/yorkie/v1/yorkie_pb.ts index 51152844c..32db1ee83 100644 --- a/packages/sdk/src/api/yorkie/v1/yorkie_pb.ts +++ b/packages/sdk/src/api/yorkie/v1/yorkie_pb.ts @@ -184,6 +184,11 @@ export class AttachDocumentRequest extends Message { */ changePack?: ChangePack; + /** + * @generated from field: string schema = 3; + */ + schema = ""; + constructor(data?: PartialMessage) { super(); proto3.util.initPartial(data, this); @@ -194,6 +199,7 @@ export class AttachDocumentRequest extends Message { static readonly fields: FieldList = proto3.util.newFieldList(() => [ { no: 1, name: "client_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 2, name: "change_pack", kind: "message", T: ChangePack }, + { no: 3, name: "schema", kind: "scalar", T: 9 /* ScalarType.STRING */ }, ]); static fromBinary(bytes: Uint8Array, options?: Partial): AttachDocumentRequest { diff --git a/packages/sdk/src/client/client.ts b/packages/sdk/src/client/client.ts index f32fdbf42..e6277f283 100644 --- a/packages/sdk/src/client/client.ts +++ b/packages/sdk/src/client/client.ts @@ -195,6 +195,12 @@ export interface AttachOptions { * `syncMode` defines the synchronization mode of the document. */ syncMode?: SyncMode; + + /** + * `schema` is the schema of the document. It is used to validate the + * document. + */ + schema?: string; } /** @@ -437,6 +443,7 @@ export class Client { { clientId: this.id!, changePack: converter.toChangePack(doc.createChangePack()), + schema: opts.schema ? opts.schema : undefined, }, { headers: { 'x-shard-key': `${this.apiKey}/${doc.getKey()}` } }, );