lcp-sdk 1.0.0

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.
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module LcpSdk
6
+ class SchemaValidationError < StandardError; end
7
+
8
+ class SchemaValidator
9
+ def initialize(schema_documents)
10
+ require "json_schemer"
11
+ # Keep a private copy so self-references in core.json can be made
12
+ # fragment-local without mutating the caller's canonical documents.
13
+ @documents = schema_documents.transform_values do |document|
14
+ JSON.parse(JSON.generate(document))
15
+ end
16
+ @documents.each_value do |document|
17
+ rewrite_core_refs(document) if document["$id"] == "https://lcp.dev/schemas/core.json"
18
+ end
19
+ @ids = {}
20
+ @documents.each do |name, document|
21
+ id = document.fetch("$id", name)
22
+ @ids[normalize(name)] = id
23
+ @ids[normalize(id)] = id
24
+ end
25
+ end
26
+
27
+ def self.from_directory(root)
28
+ documents = {}
29
+ Dir.glob(File.join(root, "**", "*.json")).each do |path|
30
+ name = path.delete_prefix("#{root}/")
31
+ documents[name] = JSON.parse(File.read(path))
32
+ end
33
+ new(documents)
34
+ end
35
+
36
+ def validate(schema_name, instance)
37
+ id = @ids.fetch(normalize(schema_name)) { raise KeyError, "unknown LCP schema: #{schema_name}" }
38
+ schema = @documents.values.find { |candidate| candidate["$id"] == id } || @documents.fetch(schema_name)
39
+ errors = JSONSchemer.schema(schema, ref_resolver: lambda do |uri|
40
+ reference = uri.to_s
41
+ @documents.values.find { |candidate| candidate["$id"].to_s == reference } ||
42
+ @documents[reference] ||
43
+ @documents[reference.sub(%r{.*/}, "")]
44
+ end).validate(instance).to_a
45
+ raise SchemaValidationError, "LCP schema validation failed for #{schema_name}: #{errors.first}" unless errors.empty?
46
+ true
47
+ end
48
+
49
+ def validate_envelope(envelope)
50
+ validate("schemas/envelope.json", envelope)
51
+ type = envelope.dig("lcp", "message", "type")
52
+ raise SchemaValidationError, "missing lcp.message.type" unless type.is_a?(String)
53
+ validate("schemas/#{type}.json", envelope.dig("lcp", "payload"))
54
+ end
55
+
56
+ def validate_offer(offer)
57
+ validate("schemas/offer.json", offer)
58
+ end
59
+
60
+ def validate_vertical(vertical, attributes)
61
+ validate("verticals/#{vertical}.json", attributes)
62
+ end
63
+
64
+ private
65
+
66
+ def rewrite_core_refs(value)
67
+ case value
68
+ when Hash
69
+ if value["$ref"].is_a?(String)
70
+ value["$ref"] = value["$ref"].sub(/\Acore\.json(?=#)/, "")
71
+ end
72
+ value.each_value { |child| rewrite_core_refs(child) }
73
+ when Array
74
+ value.each { |child| rewrite_core_refs(child) }
75
+ end
76
+ end
77
+
78
+ def normalize(name)
79
+ name.to_s.tr("\\", "/").sub(%r{^/}, "").sub(%r{^(schemas|verticals)/}, "").sub(/\.json$/, "")
80
+ end
81
+ end
82
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lcp-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Spear Systems
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: json_schemer
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.5'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.5'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '13.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '13.0'
40
+ description: Signing, envelopes, webhooks, and HTTP helpers for LCP.
41
+ executables: []
42
+ extensions: []
43
+ extra_rdoc_files: []
44
+ files:
45
+ - README.md
46
+ - lib/generated_models.rb
47
+ - lib/lcp_sdk.rb
48
+ - lib/schema-bundle.json
49
+ - lib/schema_validator.rb
50
+ licenses:
51
+ - Apache-2.0
52
+ metadata: {}
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubygems_version: 4.0.16
68
+ specification_version: 4
69
+ summary: LCP Lead Context Protocol SDK
70
+ test_files: []