bridgetown-ai-chatbot 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ec8a22027dea0a642f58f72dc9f1ea495fc7ba4e424eb6139445f2e78755d048
4
+ data.tar.gz: f742004f93f182466e5435c286b665730f3e9b92d724979cce44bace1a8898e7
5
+ SHA512:
6
+ metadata.gz: 067652eae23aedca9679dcec2a24902d7407dc440b2e3d1a671a87f2c5f14fc1645288e12bbf616c78dc79ff1ae76b9dbe6806f7f4e75687e80f061ddc56fd88
7
+ data.tar.gz: 0ed08586920bb6c31e0cfccc1c12478c1aec91ebaeabab5cdc25a44a1fe65488f04ece64bc44a977c2425a14b55b0de2de463cb493745a50511ab41180815e7a
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Asyntai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # bridgetown-ai-chatbot
2
+
3
+ Add the [Asyntai](https://asyntai.com) AI chat assistant to your Bridgetown
4
+ site. It answers visitor questions from your own content, in more than 80
5
+ languages.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ bundle add bridgetown-ai-chatbot
11
+ ```
12
+
13
+ Then add the plugin in `config/initializers.rb`:
14
+
15
+ ```ruby
16
+ Bridgetown.configure do |config|
17
+ init :"bridgetown-ai-chatbot", widget_id: "asyntai_1a2b3c4d5e6f"
18
+ end
19
+ ```
20
+
21
+ Build the site. The chat bubble is on every page.
22
+
23
+ ## Where the widget ID comes from
24
+
25
+ Open the Install page in your [Asyntai dashboard](https://asyntai.com/dashboard).
26
+ The widget ID is the value of `data-asyntai-id` in the snippet shown there. It
27
+ starts with `asyntai_`.
28
+
29
+ Creating an account is free, and the Free plan is enough to try the widget.
30
+
31
+ ## Options
32
+
33
+ | Option | Type | Default | What it does |
34
+ | --- | --- | --- | --- |
35
+ | `widget_id` | string | required | Your Asyntai widget ID |
36
+ | `enable_in_development` | boolean | `true` | Set to `false` to keep the widget off the site while `BRIDGETOWN_ENV` is `development` |
37
+ | `script_url` | string | the Asyntai CDN | Advanced. Load the widget from another URL |
38
+
39
+ You can also use the block form:
40
+
41
+ ```ruby
42
+ init :"bridgetown-ai-chatbot" do
43
+ widget_id "asyntai_1a2b3c4d5e6f"
44
+ enable_in_development false
45
+ end
46
+ ```
47
+
48
+ A missing or malformed `widget_id` stops the build with a message that says how
49
+ to fix it.
50
+
51
+ ## What the plugin does
52
+
53
+ - It adds the Asyntai loader to every HTML page, just before `</body>`.
54
+ That includes pages from collections, posts and pagination.
55
+ - The loader waits for the page's `load` event, so your own content always
56
+ renders first.
57
+ - Feeds, JSON and other non-HTML files stay as they are.
58
+ - A page that already has the Asyntai snippet keeps it and gets no second one.
59
+
60
+ It works with every template engine: ERB, Serbea and Liquid.
61
+
62
+ Tested with Bridgetown 1.3 and 2.2.
63
+
64
+ ## Answering from your content
65
+
66
+ Asyntai reads your published pages. Add your site URL in the dashboard, and the
67
+ assistant answers from the same pages the widget sits on. You can also add extra
68
+ documents and question and answer pairs.
69
+
70
+ ## Removing it
71
+
72
+ Delete the `init` line and build again. The widget is gone.
73
+
74
+ ## Support
75
+
76
+ Email [hello@asyntai.com](mailto:hello@asyntai.com), or read the
77
+ [Bridgetown guide](https://asyntai.com/documentation/integrations/bridgetown/).
78
+
79
+ ## Licence
80
+
81
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Asyntai AI chatbot for Bridgetown: the logic, without the initializer, so
4
+ # it can be tested outside a Bridgetown build.
5
+ #
6
+ # Adds the Asyntai chat widget to every HTML page the site builds. The plugin
7
+ # hooks into rendering: after a page is rendered, it puts the ordinary embed
8
+ # loader just before </body> and changes nothing else about the page.
9
+
10
+ require "json"
11
+ require "bridgetown"
12
+ require "bridgetown-ai-chatbot/version"
13
+
14
+ module BridgetownAiChatbot
15
+ DEFAULT_SCRIPT_URL = "https://widget.asyntai.com/static/js/chat-widget.js"
16
+ WIDGET_ID_PATTERN = /\Aasyntai_[A-Za-z0-9]+\z/
17
+ NAME = "bridgetown-ai-chatbot"
18
+
19
+ class ConfigurationError < StandardError; end
20
+
21
+ Settings = Struct.new(:widget_id, :script_url, :enable_in_development, keyword_init: true)
22
+
23
+ module_function
24
+
25
+ # Bridgetown runs the initializer before it builds anything, so a wrong option
26
+ # stops the build with a clear message instead of producing a site with no chat.
27
+ def validate_options(options)
28
+ opts = (options || {}).to_h.transform_keys(&:to_sym)
29
+ widget_id = opts[:widget_id].is_a?(String) ? opts[:widget_id].strip : ""
30
+
31
+ if widget_id.empty?
32
+ raise ConfigurationError,
33
+ "#{NAME}: \"widget_id\" is required. Copy it from the Install page of your " \
34
+ "Asyntai dashboard, for example asyntai_1a2b3c4d5e6f."
35
+ end
36
+ unless WIDGET_ID_PATTERN.match?(widget_id)
37
+ raise ConfigurationError,
38
+ "#{NAME}: \"#{widget_id}\" does not look like a widget ID. It starts with " \
39
+ "asyntai_, for example asyntai_1a2b3c4d5e6f."
40
+ end
41
+
42
+ script_url = opts[:script_url].is_a?(String) && !opts[:script_url].strip.empty? ?
43
+ opts[:script_url].strip : DEFAULT_SCRIPT_URL
44
+
45
+ Settings.new(
46
+ widget_id: widget_id,
47
+ script_url: script_url,
48
+ # Set to false to keep the widget off the site while BRIDGETOWN_ENV is development.
49
+ enable_in_development: opts[:enable_in_development] != false
50
+ )
51
+ end
52
+
53
+ # JSON string, safe inside an HTML <script> element.
54
+ def js_string(value)
55
+ JSON.generate(value.to_s).gsub("<", "\\u003c")
56
+ end
57
+
58
+ # The loader waits for the page's load event before it fetches the widget.
59
+ # An ordinary `<script async src>` holds the load event open until its own
60
+ # fetch finishes, so an unreachable server would delay the host page. This
61
+ # pattern cannot.
62
+ def build_loader(widget_id, script_url)
63
+ "(function(){var l=function(){" \
64
+ "if(document.querySelector(\"script[data-asyntai-id]\"))return;" \
65
+ "var s=document.createElement(\"script\");" \
66
+ "s.src=#{js_string(script_url)};s.async=true;" \
67
+ "s.setAttribute(\"data-asyntai-id\",#{js_string(widget_id)});" \
68
+ "document.head.appendChild(s)};" \
69
+ "if(document.readyState===\"complete\"){l()}" \
70
+ "else{window.addEventListener(\"load\",l)}})();"
71
+ end
72
+
73
+ def build_tag(settings)
74
+ "<script data-asyntai-loader>#{build_loader(settings.widget_id, settings.script_url)}</script>"
75
+ end
76
+
77
+ # Puts the tag before the last </body>, or before </html> when the page has no
78
+ # body tag. A fragment with neither is left alone: it is not a whole page.
79
+ # A page that already carries an Asyntai snippet is left alone too.
80
+ def inject_into_html(html, tag)
81
+ return html unless html.is_a?(String)
82
+ return html if html.include?("data-asyntai-id")
83
+
84
+ lower = html.downcase
85
+ at = lower.rindex("</body>") || lower.rindex("</html>")
86
+ return html if at.nil?
87
+
88
+ html[0...at] + tag + html[at..]
89
+ end
90
+
91
+ # Only pages that are written to disk as .html get the widget. Feeds, JSON,
92
+ # CSS and pages with `permalink: false` stay as they are.
93
+ def html_output?(document)
94
+ if document.respond_to?(:write?)
95
+ return false unless document.write?
96
+ end
97
+ ext = document.respond_to?(:output_ext) ? document.output_ext.to_s.downcase : ""
98
+ [".html", ".htm"].include?(ext)
99
+ end
100
+
101
+ def development?
102
+ Bridgetown.environment.to_s == "development"
103
+ end
104
+
105
+ def apply(document, settings, tag)
106
+ return if !settings.enable_in_development && development?
107
+ return unless html_output?(document)
108
+
109
+ document.output = inject_into_html(document.output, tag)
110
+ end
111
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BridgetownAiChatbot
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Asyntai AI chatbot for Bridgetown.
4
+ #
5
+ # In config/initializers.rb:
6
+ #
7
+ # init :"bridgetown-ai-chatbot", widget_id: "asyntai_1a2b3c4d5e6f"
8
+
9
+ require "bridgetown-ai-chatbot/core"
10
+
11
+ Bridgetown.initializer :"bridgetown-ai-chatbot" do |config, **options|
12
+ settings = BridgetownAiChatbot.validate_options(options)
13
+ tag = BridgetownAiChatbot.build_tag(settings)
14
+
15
+ # Low priority, so the widget goes in after other plugins change the page.
16
+ config.hook :resources, :post_render, priority: :low do |resource|
17
+ BridgetownAiChatbot.apply(resource, settings, tag)
18
+ end
19
+ config.hook :generated_pages, :post_render, priority: :low do |page|
20
+ BridgetownAiChatbot.apply(page, settings, tag)
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bridgetown-ai-chatbot
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Asyntai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-10-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bridgetown
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '3.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.2'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.0'
33
+ description: Adds the Asyntai AI chatbot to every page of your Bridgetown site. It
34
+ answers visitor questions from your own content, in 80+ languages.
35
+ email: hello@asyntai.com
36
+ executables: []
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - LICENSE
41
+ - README.md
42
+ - lib/bridgetown-ai-chatbot.rb
43
+ - lib/bridgetown-ai-chatbot/core.rb
44
+ - lib/bridgetown-ai-chatbot/version.rb
45
+ homepage: https://asyntai.com/documentation/integrations/bridgetown/
46
+ licenses:
47
+ - MIT
48
+ metadata:
49
+ homepage_uri: https://asyntai.com/documentation/integrations/bridgetown/
50
+ source_code_uri: https://github.com/asyntai/bridgetown-ai-chatbot
51
+ bug_tracker_uri: https://github.com/asyntai/bridgetown-ai-chatbot/issues
52
+ rubygems_mfa_required: 'true'
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '2.7'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubygems_version: 3.5.22
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Add the Asyntai AI chat assistant to your Bridgetown site.
72
+ test_files: []