@livenetworks/ashlar 1.6.1 → 2.0.1
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/LICENSE +641 -0
- package/README.md +190 -86
- package/{js → components}/COMPONENTS.md +1116 -1108
- package/{js → components}/index.js +81 -58
- package/{js → components}/ln-accordion/README.md +7 -6
- package/components/ln-accordion/ln-accordion-dev.scss +8 -0
- package/components/ln-accordion/ln-accordion.js +1 -0
- package/components/ln-accordion/ln-accordion.schema.json +30 -0
- package/components/ln-accordion/ln-accordion.scss +8 -0
- package/{js → components}/ln-accordion/src/ln-accordion.js +8 -2
- package/{js → components}/ln-ajax/README.md +171 -160
- package/components/ln-ajax/ln-ajax-dev.scss +8 -0
- package/components/ln-ajax/ln-ajax.js +1 -0
- package/components/ln-ajax/ln-ajax.schema.json +30 -0
- package/{js → components}/ln-ajax/src/ln-ajax.js +65 -30
- package/{js → components}/ln-api-connector/README.md +27 -5
- package/components/ln-api-connector/ln-api-connector.js +1 -0
- package/components/ln-api-connector/ln-api-connector.schema.json +96 -0
- package/components/ln-api-connector/src/connector-core.js +97 -0
- package/components/ln-api-connector/src/ln-api-connector.js +447 -0
- package/{js → components}/ln-api-queue/README.md +12 -9
- package/components/ln-api-queue/ln-api-queue.js +1 -0
- package/components/ln-api-queue/ln-api-queue.schema.json +34 -0
- package/{js → components}/ln-api-queue/src/ln-api-queue.js +33 -14
- package/{js → components}/ln-api-queue/src/queue-storage.js +7 -3
- package/{js → components}/ln-autoresize/README.md +129 -127
- package/components/ln-autoresize/ln-autoresize-dev.scss +8 -0
- package/components/ln-autoresize/ln-autoresize.js +1 -0
- package/components/ln-autoresize/ln-autoresize.schema.json +22 -0
- package/{js → components}/ln-autoresize/src/ln-autoresize.js +8 -1
- package/{js → components}/ln-autosave/README.md +127 -124
- package/components/ln-autosave/ln-autosave-dev.scss +13 -0
- package/components/ln-autosave/ln-autosave.js +1 -0
- package/components/ln-autosave/ln-autosave.schema.json +48 -0
- package/components/ln-autosave/src/autosave-model.js +34 -0
- package/{js → components}/ln-autosave/src/ln-autosave.js +65 -58
- package/components/ln-chart/README.md +145 -0
- package/components/ln-chart/ln-chart-dev.scss +20 -0
- package/components/ln-chart/ln-chart.js +1 -0
- package/components/ln-chart/ln-chart.schema.json +146 -0
- package/components/ln-chart/ln-chart.scss +8 -0
- package/components/ln-chart/src/chart-model.js +154 -0
- package/components/ln-chart/src/ln-chart.js +176 -0
- package/{js → components}/ln-circular-progress/README.md +15 -14
- package/components/ln-circular-progress/ln-circular-progress-dev.scss +8 -0
- package/components/ln-circular-progress/ln-circular-progress.js +1 -0
- package/components/ln-circular-progress/ln-circular-progress.schema.json +42 -0
- package/{js → components}/ln-circular-progress/src/ln-circular-progress.js +32 -50
- package/{js → components}/ln-confirm/README.md +69 -18
- package/components/ln-confirm/ln-confirm-dev.scss +24 -0
- package/components/ln-confirm/ln-confirm.js +1 -0
- package/components/ln-confirm/ln-confirm.schema.json +66 -0
- package/components/ln-confirm/ln-confirm.scss +24 -0
- package/{js → components}/ln-confirm/src/ln-confirm.js +180 -171
- package/{js → components}/ln-core/README.md +374 -149
- package/components/ln-core/attrs.js +273 -0
- package/components/ln-core/compare.js +40 -0
- package/components/ln-core/crypto.js +265 -0
- package/components/ln-core/date.js +50 -0
- package/components/ln-core/dom.js +115 -0
- package/components/ln-core/events.js +122 -0
- package/components/ln-core/form.js +136 -0
- package/{js → components}/ln-core/hash.js +149 -92
- package/components/ln-core/helpers.js +33 -0
- package/components/ln-core/http.js +48 -0
- package/components/ln-core/index.js +11 -0
- package/components/ln-core/lifecycle.js +403 -0
- package/components/ln-core/ln-core.schema.json +109 -0
- package/components/ln-core/locale.js +55 -0
- package/components/ln-core/matching.js +78 -0
- package/components/ln-core/number.js +125 -0
- package/components/ln-core/progress.js +30 -0
- package/components/ln-core/template.js +206 -0
- package/{js → components}/ln-core/window-cache.js +247 -213
- package/{js → components}/ln-couchdb-connector/README.md +7 -5
- package/components/ln-couchdb-connector/ln-couchdb-connector.js +1 -0
- package/components/ln-couchdb-connector/ln-couchdb-connector.schema.json +50 -0
- package/{js → components}/ln-couchdb-connector/src/ln-couchdb-connector.js +29 -43
- package/{js → components}/ln-data-coordinator/README.md +109 -73
- package/components/ln-data-coordinator/ln-data-coordinator-dev.scss +8 -0
- package/components/ln-data-coordinator/ln-data-coordinator.js +1 -0
- package/components/ln-data-coordinator/ln-data-coordinator.schema.json +196 -0
- package/components/ln-data-coordinator/src/data-read-policy.js +41 -0
- package/{js → components}/ln-data-coordinator/src/ln-data-coordinator.js +411 -154
- package/{js → components}/ln-data-coordinator/src/mutation-receipts.js +0 -5
- package/{js → components}/ln-data-store/README.md +42 -17
- package/components/ln-data-store/ln-data-store-dev.scss +13 -0
- package/components/ln-data-store/ln-data-store.js +1 -0
- package/components/ln-data-store/ln-data-store.schema.json +84 -0
- package/components/ln-data-store/src/data-store-model.js +155 -0
- package/{js → components}/ln-data-store/src/ln-data-store.js +407 -105
- package/components/ln-data-store/src/window-index.js +119 -0
- package/{js → components}/ln-date/README.md +17 -7
- package/{js → components}/ln-date/ln-date-dev.scss +14 -14
- package/components/ln-date/ln-date.js +1 -0
- package/components/ln-date/ln-date.schema.json +92 -0
- package/components/ln-date/src/date-model.js +186 -0
- package/components/ln-date/src/ln-date.js +486 -0
- package/components/ln-debug/README.md +132 -0
- package/components/ln-debug/ln-debug.js +1 -0
- package/components/ln-debug/ln-debug.schema.json +28 -0
- package/components/ln-debug/src/console-sink.js +19 -0
- package/components/ln-debug/src/debug-verifier.js +331 -0
- package/components/ln-debug/src/gate.js +95 -0
- package/components/ln-debug/src/generated-attributes.js +299 -0
- package/components/ln-debug/src/ln-debug.js +60 -0
- package/{js → components}/ln-dropdown/README.md +150 -140
- package/components/ln-dropdown/ln-dropdown-dev.scss +13 -0
- package/components/ln-dropdown/ln-dropdown.js +1 -0
- package/components/ln-dropdown/ln-dropdown.schema.json +90 -0
- package/components/ln-dropdown/ln-dropdown.scss +18 -0
- package/{js → components}/ln-dropdown/src/ln-dropdown.js +114 -11
- package/{js → components}/ln-editor/README.md +11 -9
- package/components/ln-editor/ln-editor-dev.scss +18 -0
- package/components/ln-editor/ln-editor.js +1 -0
- package/components/ln-editor/ln-editor.schema.json +58 -0
- package/components/ln-editor/ln-editor.scss +13 -0
- package/{js → components}/ln-editor/src/ln-editor.js +59 -11
- package/{js → components}/ln-external-links/README.md +10 -8
- package/components/ln-external-links/ln-external-links.js +1 -0
- package/components/ln-external-links/ln-external-links.schema.json +18 -0
- package/{js → components}/ln-external-links/src/ln-external-links.js +13 -11
- package/{js → components}/ln-fill/README.md +6 -8
- package/components/ln-fill/ln-fill.js +1 -0
- package/components/ln-fill/ln-fill.schema.json +23 -0
- package/{js → components}/ln-fill/src/ln-fill.js +7 -1
- package/components/ln-filter/README.md +131 -0
- package/components/ln-filter/ln-filter-dev.scss +13 -0
- package/components/ln-filter/ln-filter.js +1 -0
- package/components/ln-filter/ln-filter.schema.json +153 -0
- package/components/ln-filter/src/filter-model.js +185 -0
- package/components/ln-filter/src/ln-filter.js +435 -0
- package/{js → components}/ln-form/README.md +260 -264
- package/components/ln-form/ln-form-dev.scss +8 -0
- package/components/ln-form/ln-form.js +1 -0
- package/components/ln-form/ln-form.schema.json +45 -0
- package/{js → components}/ln-form/src/ln-form.js +107 -99
- package/{js → components}/ln-http/README.md +11 -6
- package/components/ln-http/ln-http.js +1 -0
- package/components/ln-http/ln-http.schema.json +6 -0
- package/components/ln-http/src/http-core.js +51 -0
- package/{js → components}/ln-http/src/ln-http.js +28 -33
- package/{js → components}/ln-icon/README.md +16 -9
- package/components/ln-icon/ln-icon.schema.json +6 -0
- package/components/ln-include/README.md +75 -0
- package/components/ln-include/ln-include-dev.scss +13 -0
- package/components/ln-include/ln-include.js +1 -0
- package/components/ln-include/ln-include.schema.json +23 -0
- package/components/ln-include/src/ln-include.js +111 -0
- package/components/ln-key/README.md +130 -0
- package/components/ln-key/ln-key-dev.scss +18 -0
- package/components/ln-key/ln-key.js +1 -0
- package/components/ln-key/ln-key.schema.json +56 -0
- package/components/ln-key/src/key-model.js +146 -0
- package/components/ln-key/src/ln-key.js +201 -0
- package/{js → components}/ln-link/README.md +7 -9
- package/components/ln-link/ln-link-dev.scss +8 -0
- package/components/ln-link/ln-link.js +1 -0
- package/components/ln-link/ln-link.schema.json +22 -0
- package/{js → components}/ln-link/src/ln-link.js +16 -11
- package/components/ln-list/README.md +152 -0
- package/components/ln-list/ln-list-dev.scss +8 -0
- package/components/ln-list/ln-list.js +1 -0
- package/components/ln-list/ln-list.schema.json +166 -0
- package/components/ln-list/ln-list.scss +25 -0
- package/{js → components}/ln-list/src/ln-list.js +1301 -1216
- package/{js → components}/ln-modal/README.md +13 -10
- package/components/ln-modal/ln-modal-dev.scss +18 -0
- package/components/ln-modal/ln-modal.js +1 -0
- package/components/ln-modal/ln-modal.schema.json +54 -0
- package/components/ln-modal/ln-modal.scss +51 -0
- package/{js → components}/ln-modal/src/ln-modal.js +164 -137
- package/{js → components}/ln-nav/README.md +11 -11
- package/components/ln-nav/ln-nav.js +1 -0
- package/components/ln-nav/ln-nav.schema.json +25 -0
- package/{js → components}/ln-nav/src/ln-nav.js +25 -14
- package/components/ln-number/README.md +205 -0
- package/{js → components}/ln-number/ln-number-dev.scss +13 -13
- package/components/ln-number/ln-number.js +1 -0
- package/components/ln-number/ln-number.schema.json +63 -0
- package/components/ln-number/src/ln-number.js +400 -0
- package/components/ln-number/src/number-model.js +31 -0
- package/components/ln-obfuscator/README.md +60 -0
- package/components/ln-obfuscator/ln-obfuscator.js +1 -0
- package/components/ln-obfuscator/ln-obfuscator.schema.json +49 -0
- package/components/ln-obfuscator/src/ln-obfuscator.js +159 -0
- package/components/ln-obfuscator/src/obfuscator-model.js +250 -0
- package/{js → components}/ln-options/README.md +3 -1
- package/components/ln-options/ln-options-dev.scss +13 -0
- package/components/ln-options/ln-options.js +1 -0
- package/components/ln-options/ln-options.schema.json +41 -0
- package/{js → components}/ln-options/src/ln-options.js +13 -5
- package/components/ln-persist/README.md +151 -0
- package/components/ln-persist/ln-persist.js +1 -0
- package/components/ln-persist/ln-persist.schema.json +28 -0
- package/components/ln-persist/src/ln-persist.js +83 -0
- package/components/ln-picklist/README.md +230 -0
- package/components/ln-picklist/ln-picklist-dev.scss +22 -0
- package/components/ln-picklist/ln-picklist.js +1 -0
- package/components/ln-picklist/ln-picklist.schema.json +49 -0
- package/components/ln-picklist/src/ln-picklist.js +228 -0
- package/{js → components}/ln-popover/README.md +164 -162
- package/components/ln-popover/ln-popover-dev.scss +13 -0
- package/components/ln-popover/ln-popover.js +1 -0
- package/components/ln-popover/ln-popover.schema.json +82 -0
- package/components/ln-popover/ln-popover.scss +18 -0
- package/{js → components}/ln-popover/src/ln-popover.js +42 -36
- package/{js → components}/ln-progress/README.md +410 -413
- package/components/ln-progress/ln-progress-dev.scss +8 -0
- package/components/ln-progress/ln-progress.js +1 -0
- package/components/ln-progress/ln-progress.schema.json +40 -0
- package/components/ln-progress/src/ln-progress.js +91 -0
- package/components/ln-progress/src/progress-model.js +20 -0
- package/{js → components}/ln-router/README.md +443 -432
- package/components/ln-router/ln-router-dev.scss +13 -0
- package/components/ln-router/ln-router.js +1 -0
- package/components/ln-router/ln-router.schema.json +68 -0
- package/{js → components}/ln-router/src/ln-router.js +585 -539
- package/components/ln-router/src/router-model.js +50 -0
- package/components/ln-scroll/README.md +45 -0
- package/components/ln-scroll/ln-scroll.js +1 -0
- package/components/ln-scroll/ln-scroll.schema.json +85 -0
- package/components/ln-scroll/src/ln-scroll.js +150 -0
- package/components/ln-search/README.md +188 -0
- package/components/ln-search/ln-search-dev.scss +13 -0
- package/components/ln-search/ln-search.js +1 -0
- package/components/ln-search/ln-search.schema.json +103 -0
- package/components/ln-search/src/ln-search.js +330 -0
- package/{js → components}/ln-slug/README.md +6 -3
- package/components/ln-slug/ln-slug-dev.scss +18 -0
- package/components/ln-slug/ln-slug.js +1 -0
- package/components/ln-slug/ln-slug.schema.json +23 -0
- package/{js → components}/ln-slug/src/ln-slug.js +20 -13
- package/components/ln-slug/src/slug-model.js +21 -0
- package/{js → components}/ln-sort/README.md +178 -170
- package/{js → components}/ln-sort/ln-sort-dev.scss +8 -8
- package/components/ln-sort/ln-sort.js +1 -0
- package/components/ln-sort/ln-sort.schema.json +104 -0
- package/components/ln-sort/src/ln-sort.js +321 -0
- package/components/ln-sort/src/sort-model.js +117 -0
- package/{js → components}/ln-sortable/README.md +7 -11
- package/components/ln-sortable/ln-sortable-dev.scss +13 -0
- package/components/ln-sortable/ln-sortable.js +1 -0
- package/components/ln-sortable/ln-sortable.schema.json +36 -0
- package/{js → components}/ln-sortable/src/ln-sortable.js +8 -13
- package/{js → components}/ln-stat/README.md +3 -1
- package/components/ln-stat/ln-stat-dev.scss +8 -0
- package/components/ln-stat/ln-stat.js +1 -0
- package/components/ln-stat/ln-stat.schema.json +32 -0
- package/{js → components}/ln-stat/src/ln-stat.js +14 -18
- package/components/ln-stat/src/stat-model.js +28 -0
- package/{js → components}/ln-table/README.md +37 -24
- package/{js → components}/ln-table/ln-table-dev.scss +17 -17
- package/components/ln-table/ln-table.js +1 -0
- package/components/ln-table/ln-table.schema.json +211 -0
- package/components/ln-table/ln-table.scss +15 -0
- package/{js → components}/ln-table/src/ln-table.js +1365 -1493
- package/components/ln-table/src/table-model.js +98 -0
- package/components/ln-table-coordinator/README.md +61 -0
- package/components/ln-table-coordinator/ln-table-coordinator.js +1 -0
- package/components/ln-table-coordinator/ln-table-coordinator.schema.json +93 -0
- package/components/ln-table-coordinator/src/ln-table-coordinator.js +193 -0
- package/{js → components}/ln-tabs/README.md +32 -14
- package/components/ln-tabs/ln-tabs-dev.scss +24 -0
- package/components/ln-tabs/ln-tabs.js +1 -0
- package/components/ln-tabs/ln-tabs.schema.json +75 -0
- package/components/ln-tabs/ln-tabs.scss +8 -0
- package/components/ln-tabs/src/ln-tabs.js +207 -0
- package/components/ln-tabs/src/tabs-model.js +82 -0
- package/{js → components}/ln-time/README.md +96 -95
- package/components/ln-time/ln-time-dev.scss +13 -0
- package/components/ln-time/ln-time.js +1 -0
- package/components/ln-time/ln-time.schema.json +38 -0
- package/{js → components}/ln-time/src/ln-time.js +206 -223
- package/components/ln-time/src/time-model.js +64 -0
- package/{js → components}/ln-toast/README.md +23 -5
- package/components/ln-toast/ln-toast-dev.scss +8 -0
- package/components/ln-toast/ln-toast.js +1 -0
- package/components/ln-toast/ln-toast.schema.json +65 -0
- package/components/ln-toast/ln-toast.scss +59 -0
- package/{js → components}/ln-toast/src/ln-toast.js +233 -232
- package/{js → components}/ln-toggle/README.md +198 -196
- package/{js → components}/ln-toggle/ln-toggle-dev.scss +13 -13
- package/components/ln-toggle/ln-toggle.js +1 -0
- package/components/ln-toggle/ln-toggle.schema.json +52 -0
- package/components/ln-toggle/ln-toggle.scss +37 -0
- package/{js → components}/ln-toggle/src/ln-toggle.js +61 -46
- package/{js → components}/ln-tooltip/README.md +6 -6
- package/{js → components}/ln-tooltip/ln-tooltip-dev.scss +9 -9
- package/components/ln-tooltip/ln-tooltip.js +1 -0
- package/components/ln-tooltip/ln-tooltip.schema.json +86 -0
- package/components/ln-tooltip/ln-tooltip.scss +9 -0
- package/{js → components}/ln-tooltip/src/ln-tooltip.js +14 -3
- package/{js → components}/ln-translations/README.md +3 -1
- package/components/ln-translations/ln-translations-dev.scss +13 -0
- package/components/ln-translations/ln-translations.js +1 -0
- package/components/ln-translations/ln-translations.schema.json +120 -0
- package/{js → components}/ln-translations/src/ln-translations.js +25 -10
- package/components/ln-ui-coordinator/README.md +101 -0
- package/components/ln-ui-coordinator/ln-ui-coordinator-dev.scss +8 -0
- package/components/ln-ui-coordinator/ln-ui-coordinator.js +1 -0
- package/components/ln-ui-coordinator/ln-ui-coordinator.schema.json +60 -0
- package/{js/ln-modal-coordinator/src/ln-modal-coordinator.js → components/ln-ui-coordinator/src/ln-ui-coordinator.js} +403 -345
- package/components/ln-upload/README.md +133 -0
- package/components/ln-upload/ln-upload-dev.scss +18 -0
- package/components/ln-upload/ln-upload.js +1 -0
- package/components/ln-upload/ln-upload.schema.json +193 -0
- package/components/ln-upload/ln-upload.scss +20 -0
- package/components/ln-upload/src/ln-upload.js +652 -0
- package/components/ln-upload/src/upload-model.js +78 -0
- package/{js → components}/ln-validate/README.md +182 -180
- package/{js → components}/ln-validate/ln-validate-dev.scss +15 -15
- package/components/ln-validate/ln-validate.js +1 -0
- package/components/ln-validate/ln-validate.schema.json +50 -0
- package/components/ln-validate/ln-validate.scss +7 -0
- package/{js → components}/ln-validate/src/ln-validate.js +23 -45
- package/components/ln-validate/src/validate-model.js +64 -0
- package/components/ln-websocket-connector/README.md +166 -0
- package/components/ln-websocket-connector/ln-websocket-connector.js +1 -0
- package/components/ln-websocket-connector/ln-websocket-connector.schema.json +29 -0
- package/components/ln-websocket-connector/src/ln-websocket-connector.js +279 -0
- package/ln-ashlar.html-data.json +1796 -0
- package/package.json +84 -61
- package/{scss → theme}/base/_global.scss +1 -2
- package/{scss → theme}/base/_reset.scss +1 -1
- package/{scss → theme}/base/_typography.scss +2 -0
- package/theme/brand.css +73 -0
- package/{scss → theme}/components/_app-shell.scss +8 -0
- package/theme/components/_button.scss +24 -0
- package/theme/components/_chart.scss +5 -0
- package/theme/components/_confirm.scss +6 -0
- package/{scss → theme}/components/_date.scss +30 -22
- package/{scss → theme}/components/_dropdown.scss +6 -1
- package/theme/components/_form.scss +140 -0
- package/{scss → theme}/components/_layout.scss +6 -0
- package/{scss → theme}/components/_ln-table.scss +1 -6
- package/theme/components/_picklist.scss +3 -0
- package/{scss → theme}/components/_sort.scss +10 -10
- package/theme/components/_status-badge.scss +6 -0
- package/{scss → theme}/components/_table.scss +16 -0
- package/{scss → theme}/components/_tabs.scss +0 -4
- package/theme/components/_toast.scss +48 -0
- package/{scss → theme}/components/_toggle.scss +1 -1
- package/theme/components/_upload.scss +45 -0
- package/{scss → theme}/config/_breakpoints.scss +1 -1
- package/theme/config/_contrast.scss +128 -0
- package/{scss → theme}/config/_density.scss +191 -205
- package/theme/config/_palette.scss +274 -0
- package/theme/config/_theme.scss +293 -0
- package/{scss → theme}/config/_tokens.scss +285 -441
- package/{scss → theme}/config/mixins/_accordion.scss +1 -1
- package/{scss → theme}/config/mixins/_alert.scss +1 -0
- package/{scss → theme}/config/mixins/_app-shell.scss +4 -2
- package/{scss → theme}/config/mixins/_borders.scss +2 -0
- package/theme/config/mixins/_btn.scss +175 -0
- package/{scss → theme}/config/mixins/_card.scss +55 -46
- package/theme/config/mixins/_chart.scss +82 -0
- package/{scss → theme}/config/mixins/_collapsible.scss +2 -1
- package/{scss → theme}/config/mixins/_colors.scss +8 -14
- package/{scss → theme}/config/mixins/_diagnostics.scss +48 -48
- package/theme/config/mixins/_dropdown.scss +169 -0
- package/{scss → theme}/config/mixins/_editor.scss +0 -7
- package/{scss → theme}/config/mixins/_filter.scss +47 -47
- package/{scss → theme}/config/mixins/_footer.scss +1 -1
- package/{scss → theme}/config/mixins/_form.scss +49 -18
- package/{scss → theme}/config/mixins/_index.scss +62 -61
- package/{scss → theme}/config/mixins/_layout.scss +6 -2
- package/{scss → theme}/config/mixins/_ln-table.scss +31 -10
- package/{scss → theme}/config/mixins/_loader.scss +1 -1
- package/{scss → theme}/config/mixins/_modal.scss +145 -149
- package/{scss → theme}/config/mixins/_motion.scss +13 -0
- package/{scss → theme}/config/mixins/_nav.scss +7 -7
- package/theme/config/mixins/_picklist.scss +66 -0
- package/theme/config/mixins/_popover.scss +96 -0
- package/{scss → theme}/config/mixins/_sidebar.scss +7 -4
- package/{scss → theme}/config/mixins/_sort.scss +43 -42
- package/{scss → theme}/config/mixins/_status-badge.scss +15 -2
- package/{scss → theme}/config/mixins/_table.scss +25 -14
- package/{scss → theme}/config/mixins/_tabs.scss +1 -1
- package/{scss → theme}/config/mixins/_toast.scss +174 -179
- package/{scss → theme}/config/mixins/_tooltip.scss +2 -2
- package/{scss → theme}/config/mixins/_typography.scss +16 -5
- package/{scss → theme}/config/mixins/_upload.scss +8 -6
- package/theme/ln-ashlar-core.scss +24 -0
- package/theme/ln-ashlar-dev.scss +66 -0
- package/theme/ln-ashlar-landing.scss +56 -0
- package/{scss/ln-ashlar.scss → theme/ln-ashlar-theme.scss} +63 -69
- package/theme/ln-ashlar.scss +8 -0
- package/theme/presentation/_bento.scss +151 -0
- package/theme/presentation/_cta.scss +111 -0
- package/theme/presentation/_effects.scss +216 -0
- package/theme/presentation/_features.scss +108 -0
- package/theme/presentation/_footer.scss +129 -0
- package/theme/presentation/_hero.scss +158 -0
- package/theme/presentation/_layout.scss +170 -0
- package/theme/presentation/_navbar.scss +140 -0
- package/theme/presentation/_pricing.scss +262 -0
- package/theme/presentation/_stats.scss +87 -0
- package/theme/presentation/_testimonials.scss +124 -0
- package/theme/presentation/_tokens.scss +39 -0
- package/theme/presentation/_typography.scss +163 -0
- package/{scss → theme}/utilities/_animations.scss +38 -0
- package/{scss → theme}/utilities/_utilities.scss +6 -0
- package/web-types.json +2312 -0
- package/js/ln-accordion/ln-accordion.js +0 -1
- package/js/ln-ajax/ln-ajax.js +0 -1
- package/js/ln-api-connector/ln-api-connector.js +0 -1
- package/js/ln-api-connector/src/ln-api-connector.js +0 -368
- package/js/ln-api-queue/ln-api-queue.js +0 -1
- package/js/ln-autoresize/ln-autoresize.js +0 -1
- package/js/ln-autosave/ln-autosave.js +0 -1
- package/js/ln-circular-progress/ln-circular-progress.js +0 -1
- package/js/ln-confirm/_ln-confirm.scss +0 -24
- package/js/ln-confirm/ln-confirm.js +0 -1
- package/js/ln-core/crypto.js +0 -83
- package/js/ln-core/helpers.js +0 -788
- package/js/ln-core/index.js +0 -7
- package/js/ln-core/persist.js +0 -97
- package/js/ln-couchdb-connector/ln-couchdb-connector.js +0 -1
- package/js/ln-data-coordinator/ln-data-coordinator.js +0 -1
- package/js/ln-data-coordinator/src/data-read-policy.js +0 -18
- package/js/ln-data-store/ln-data-store.js +0 -1
- package/js/ln-date/ln-date.js +0 -1
- package/js/ln-date/src/ln-date.js +0 -603
- package/js/ln-debug/README.md +0 -58
- package/js/ln-debug/ln-debug.js +0 -1
- package/js/ln-debug/src/ln-debug.js +0 -19
- package/js/ln-dropdown/ln-dropdown.js +0 -1
- package/js/ln-dropdown/ln-dropdown.scss +0 -15
- package/js/ln-editor/ln-editor.js +0 -1
- package/js/ln-editor/ln-editor.scss +0 -43
- package/js/ln-external-links/ln-external-links.js +0 -1
- package/js/ln-fill/ln-fill.js +0 -1
- package/js/ln-filter/README.md +0 -189
- package/js/ln-filter/ln-filter-dev.scss +0 -8
- package/js/ln-filter/ln-filter.js +0 -1
- package/js/ln-filter/src/ln-filter.js +0 -419
- package/js/ln-form/ln-form.js +0 -1
- package/js/ln-http/ln-http.js +0 -1
- package/js/ln-link/ln-link.js +0 -1
- package/js/ln-list/README.md +0 -129
- package/js/ln-list/ln-list.js +0 -1
- package/js/ln-list/ln-list.scss +0 -28
- package/js/ln-modal/ln-modal-dev.scss +0 -13
- package/js/ln-modal/ln-modal.js +0 -1
- package/js/ln-modal/ln-modal.scss +0 -35
- package/js/ln-modal-coordinator/README.md +0 -99
- package/js/ln-modal-coordinator/ln-modal-coordinator-dev.scss +0 -8
- package/js/ln-modal-coordinator/ln-modal-coordinator.js +0 -1
- package/js/ln-nav/ln-nav.js +0 -1
- package/js/ln-number/README.md +0 -149
- package/js/ln-number/ln-number.js +0 -1
- package/js/ln-number/src/ln-number.js +0 -443
- package/js/ln-options/ln-options.js +0 -1
- package/js/ln-popover/ln-popover.js +0 -1
- package/js/ln-progress/ln-progress.js +0 -1
- package/js/ln-progress/src/ln-progress.js +0 -98
- package/js/ln-router/ln-router.js +0 -1
- package/js/ln-search/README.md +0 -158
- package/js/ln-search/ln-search-dev.scss +0 -8
- package/js/ln-search/ln-search.js +0 -1
- package/js/ln-search/src/ln-search.js +0 -117
- package/js/ln-slug/ln-slug.js +0 -1
- package/js/ln-sort/ln-sort.js +0 -1
- package/js/ln-sort/src/ln-sort.js +0 -178
- package/js/ln-sortable/ln-sortable.js +0 -1
- package/js/ln-stat/ln-stat.js +0 -1
- package/js/ln-table/ln-table.js +0 -1
- package/js/ln-table/ln-table.scss +0 -11
- package/js/ln-table-coordinator/README.md +0 -73
- package/js/ln-table-coordinator/ln-table-coordinator.js +0 -1
- package/js/ln-table-coordinator/src/ln-table-coordinator.js +0 -160
- package/js/ln-tabs/ln-tabs-dev.scss +0 -18
- package/js/ln-tabs/ln-tabs.js +0 -1
- package/js/ln-tabs/src/ln-tabs.js +0 -188
- package/js/ln-time/ln-time.js +0 -1
- package/js/ln-toast/ln-toast.js +0 -1
- package/js/ln-toggle/ln-toggle.js +0 -1
- package/js/ln-tooltip/ln-tooltip.js +0 -1
- package/js/ln-tooltip/ln-tooltip.scss +0 -9
- package/js/ln-translations/ln-translations.js +0 -1
- package/js/ln-upload/README.md +0 -255
- package/js/ln-upload/ln-upload.js +0 -1
- package/js/ln-upload/ln-upload.scss +0 -20
- package/js/ln-upload/src/ln-upload.js +0 -423
- package/js/ln-validate/ln-validate.js +0 -1
- package/scss/components/_button.scss +0 -20
- package/scss/components/_confirm.scss +0 -5
- package/scss/components/_form.scss +0 -107
- package/scss/components/_status-badge.scss +0 -4
- package/scss/components/_toast.scss +0 -68
- package/scss/components/_upload.scss +0 -51
- package/scss/config/_theme.scss +0 -216
- package/scss/config/mixins/_btn.scss +0 -179
- package/scss/config/mixins/_confirm.scss +0 -31
- package/scss/config/mixins/_dropdown.scss +0 -141
- package/scss/config/mixins/_popover.scss +0 -64
- package/scss/ln-ashlar-dev.scss +0 -39
- /package/{js → components}/ln-core/positioning.js +0 -0
- /package/{js → components}/ln-core/reactive.js +0 -0
- /package/{js → components}/ln-filter/ln-filter.scss +0 -0
- /package/{js → components}/ln-icon/ln-icon.js +0 -0
- /package/{js → components}/ln-icon/src/ln-icon.js +0 -0
- /package/{js → components}/ln-search/ln-search.scss +0 -0
- /package/{js → components}/ln-toast/template.html +0 -0
- /package/{scss → theme}/components/_accordion.scss +0 -0
- /package/{scss → theme}/components/_ajax.scss +0 -0
- /package/{scss → theme}/components/_alert.scss +0 -0
- /package/{scss → theme}/components/_avatar.scss +0 -0
- /package/{scss → theme}/components/_breadcrumbs.scss +0 -0
- /package/{scss → theme}/components/_card.scss +0 -0
- /package/{scss → theme}/components/_chip.scss +0 -0
- /package/{scss → theme}/components/_circular-progress.scss +0 -0
- /package/{scss → theme}/components/_editor.scss +0 -0
- /package/{scss → theme}/components/_empty-state.scss +0 -0
- /package/{scss → theme}/components/_filter.scss +0 -0
- /package/{scss → theme}/components/_link.scss +0 -0
- /package/{scss → theme}/components/_loader.scss +0 -0
- /package/{scss → theme}/components/_modal.scss +0 -0
- /package/{scss → theme}/components/_nav.scss +0 -0
- /package/{scss → theme}/components/_page-header.scss +0 -0
- /package/{scss → theme}/components/_popover.scss +0 -0
- /package/{scss → theme}/components/_progress.scss +0 -0
- /package/{scss → theme}/components/_prose.scss +0 -0
- /package/{scss → theme}/components/_scrollbar.scss +0 -0
- /package/{scss → theme}/components/_sections.scss +0 -0
- /package/{scss → theme}/components/_sidebar.scss +0 -0
- /package/{scss → theme}/components/_stat-card.scss +0 -0
- /package/{scss → theme}/components/_stepper.scss +0 -0
- /package/{scss → theme}/components/_timeline.scss +0 -0
- /package/{scss → theme}/components/_tooltip.scss +0 -0
- /package/{scss → theme}/components/_translations.scss +0 -0
- /package/{scss → theme}/config/_icons.scss +0 -0
- /package/{scss → theme}/config/_mixins.scss +0 -0
- /package/{scss → theme}/config/mixins/_ajax.scss +0 -0
- /package/{scss → theme}/config/mixins/_avatar.scss +0 -0
- /package/{scss → theme}/config/mixins/_breadcrumbs.scss +0 -0
- /package/{scss → theme}/config/mixins/_breakpoints.scss +0 -0
- /package/{scss → theme}/config/mixins/_chip.scss +0 -0
- /package/{scss → theme}/config/mixins/_circular-progress.scss +0 -0
- /package/{scss → theme}/config/mixins/_display.scss +0 -0
- /package/{scss → theme}/config/mixins/_empty-state.scss +0 -0
- /package/{scss → theme}/config/mixins/_focus.scss +0 -0
- /package/{scss → theme}/config/mixins/_interaction.scss +0 -0
- /package/{scss → theme}/config/mixins/_kbd.scss +0 -0
- /package/{scss → theme}/config/mixins/_link.scss +0 -0
- /package/{scss → theme}/config/mixins/_page-header.scss +0 -0
- /package/{scss → theme}/config/mixins/_position.scss +0 -0
- /package/{scss → theme}/config/mixins/_progress.scss +0 -0
- /package/{scss → theme}/config/mixins/_prose.scss +0 -0
- /package/{scss → theme}/config/mixins/_shadows.scss +0 -0
- /package/{scss → theme}/config/mixins/_sizing.scss +0 -0
- /package/{scss → theme}/config/mixins/_spacing.scss +0 -0
- /package/{scss → theme}/config/mixins/_stat-card.scss +0 -0
- /package/{scss → theme}/config/mixins/_stepper.scss +0 -0
- /package/{scss → theme}/config/mixins/_timeline.scss +0 -0
- /package/{scss → theme}/config/mixins/_transitions.scss +0 -0
- /package/{scss → theme}/config/mixins/_translations.scss +0 -0
- /package/{scss → theme}/tabler-icons.txt +0 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
import { registerComponent, dispatch, getHeaders, parseHeaders, defineAttrs, attrSpec, attrStr } from '../../ln-core';
|
|
2
|
+
import { buildQueryParams, buildQueryUrl, joinUrl, unwrapEnvelope } from './connector-core';
|
|
3
|
+
|
|
4
|
+
(function () {
|
|
5
|
+
const DOM_SELECTOR = 'data-ln-api-connector';
|
|
6
|
+
const DOM_ATTRIBUTE = 'lnApiConnector';
|
|
7
|
+
const DOM_ALIAS = 'lnConnector';
|
|
8
|
+
if (window[DOM_ATTRIBUTE] !== undefined) return;
|
|
9
|
+
|
|
10
|
+
// ─── Attribute Contract (SSOT) ──────────────────────────
|
|
11
|
+
function _syncAttribute(el) {
|
|
12
|
+
const instance = el[DOM_ATTRIBUTE];
|
|
13
|
+
if (!instance) return;
|
|
14
|
+
instance.refreshConfig();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const ATTRIBUTES = {
|
|
18
|
+
'data-ln-api-connector': { type: 'marker', description: 'Mounts API connector bridging REST backend and ln-ashlar data coordinators' },
|
|
19
|
+
'data-ln-api-base-url': { prop: 'baseUrl', read: attrStr, type: 'string', fallback: '', effect: _syncAttribute, description: 'Base URL endpoint for API requests' },
|
|
20
|
+
'data-ln-api-path': { prop: 'path', read: attrStr, type: 'string', fallback: '', effect: _syncAttribute, description: 'Resource path appended to base URL' },
|
|
21
|
+
'data-ln-api-headers': { prop: 'rawHeaders', read: attrStr, type: 'json', fallback: null, effect: _syncAttribute, description: 'Custom HTTP headers in JSON format or semicolon-separated pairs' },
|
|
22
|
+
'data-ln-api-param-offset': { effect: _syncAttribute, type: 'string', fallback: 'offset', description: 'Query parameter name for pagination offset' },
|
|
23
|
+
'data-ln-api-param-limit': { effect: _syncAttribute, type: 'string', fallback: 'limit', description: 'Query parameter name for pagination page size' },
|
|
24
|
+
'data-ln-api-param-search': { effect: _syncAttribute, type: 'string', fallback: 'search', description: 'Query parameter name for text search filter' },
|
|
25
|
+
'data-ln-api-param-sort-field': { effect: _syncAttribute, type: 'string', fallback: 'sort_by', description: 'Query parameter name for sort field' },
|
|
26
|
+
'data-ln-api-param-sort-dir': { effect: _syncAttribute, type: 'string', fallback: 'sort_dir', description: 'Query parameter name for sort direction' },
|
|
27
|
+
'data-ln-api-connector-query-debounce': { effect: _syncAttribute, type: 'integer', fallback: 200, min: 0, description: 'Debounce delay in milliseconds before dispatching query requests' }
|
|
28
|
+
};
|
|
29
|
+
const ATTR_SPEC = attrSpec(ATTRIBUTES);
|
|
30
|
+
|
|
31
|
+
// ─── Response Resolver ──────────────────────────────────
|
|
32
|
+
|
|
33
|
+
function _resolve(res) {
|
|
34
|
+
if (res.ok) return res.status === 204 ? null : res.json();
|
|
35
|
+
return res.json().catch(() => null).then(body => {
|
|
36
|
+
const err = new Error('HTTP ' + res.status + ': ' + res.statusText);
|
|
37
|
+
err.status = res.status;
|
|
38
|
+
err.data = body;
|
|
39
|
+
throw err;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ─── Component Constructor ─────────────────────────────
|
|
44
|
+
|
|
45
|
+
function _component(dom) {
|
|
46
|
+
this.dom = dom;
|
|
47
|
+
defineAttrs(this, dom, ATTR_SPEC);
|
|
48
|
+
dom[DOM_ATTRIBUTE] = this;
|
|
49
|
+
dom[DOM_ALIAS] = this; // Set alias for compatibility
|
|
50
|
+
|
|
51
|
+
this._inflight = new Map();
|
|
52
|
+
this._queryTimers = new Map(); // per-key: { timer, pendingDetail, pendingParams, pendingTarget }
|
|
53
|
+
this.refreshConfig();
|
|
54
|
+
this._handlers = null;
|
|
55
|
+
_bindEvents(this);
|
|
56
|
+
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ─── Refresh Config from DOM Attributes ─────────────────
|
|
61
|
+
|
|
62
|
+
_component.prototype.refreshConfig = function () {
|
|
63
|
+
const dom = this.dom;
|
|
64
|
+
|
|
65
|
+
this.credentials = 'same-origin';
|
|
66
|
+
this.headers = parseHeaders(this.rawHeaders);
|
|
67
|
+
|
|
68
|
+
const paramKeys = {};
|
|
69
|
+
const offset = dom.getAttribute('data-ln-api-param-offset');
|
|
70
|
+
if (offset) paramKeys.offset = offset;
|
|
71
|
+
const limit = dom.getAttribute('data-ln-api-param-limit');
|
|
72
|
+
if (limit) paramKeys.limit = limit;
|
|
73
|
+
const search = dom.getAttribute('data-ln-api-param-search');
|
|
74
|
+
if (search) paramKeys.search = search;
|
|
75
|
+
const sortField = dom.getAttribute('data-ln-api-param-sort-field');
|
|
76
|
+
if (sortField) paramKeys.sortField = sortField;
|
|
77
|
+
const sortDir = dom.getAttribute('data-ln-api-param-sort-dir');
|
|
78
|
+
if (sortDir) paramKeys.sortDir = sortDir;
|
|
79
|
+
this.paramKeys = paramKeys;
|
|
80
|
+
|
|
81
|
+
const qd = dom.getAttribute('data-ln-api-connector-query-debounce');
|
|
82
|
+
this.queryDebounce = qd !== null ? +qd : 300;
|
|
83
|
+
|
|
84
|
+
dispatch(this.dom, 'ln-api-connector:config-changed', {
|
|
85
|
+
baseUrl: this.baseUrl,
|
|
86
|
+
path: this.path,
|
|
87
|
+
headers: this.headers,
|
|
88
|
+
paramKeys: this.paramKeys
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// ─── Request Headers (forces X-LN-Response) ─────────────
|
|
93
|
+
|
|
94
|
+
_component.prototype._reqHeaders = function (idempotencyKey) {
|
|
95
|
+
const headers = Object.assign({}, this.headers);
|
|
96
|
+
if (!headers['Accept'] && !headers['accept']) {
|
|
97
|
+
headers['Accept'] = 'application/json';
|
|
98
|
+
}
|
|
99
|
+
if (!headers['Content-Type'] && !headers['content-type']) {
|
|
100
|
+
headers['Content-Type'] = 'application/json';
|
|
101
|
+
}
|
|
102
|
+
if (idempotencyKey) {
|
|
103
|
+
headers['X-Idempotency-Key'] = idempotencyKey;
|
|
104
|
+
}
|
|
105
|
+
return headers;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// ─── Cancellation API ────────────────────────────────────
|
|
109
|
+
|
|
110
|
+
_component.prototype.cancel = function (key) {
|
|
111
|
+
if (!key) return false;
|
|
112
|
+
if (this._inflight.has(key)) {
|
|
113
|
+
this._inflight.get(key).abort();
|
|
114
|
+
this._inflight.delete(key);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// ─── JS API Methods (Promises) ──────────────────────────
|
|
121
|
+
|
|
122
|
+
_component.prototype.fetchDelta = function (since, targetEl) {
|
|
123
|
+
const self = this;
|
|
124
|
+
let url = joinUrl(self.baseUrl, self.path);
|
|
125
|
+
|
|
126
|
+
if (since !== undefined && since !== null && since !== '') {
|
|
127
|
+
url += (url.indexOf('?') !== -1 ? '&' : '?') + 'since=' + encodeURIComponent(since);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const key = targetEl || 'sync';
|
|
131
|
+
if (self._inflight.has(key)) {
|
|
132
|
+
self._inflight.get(key).abort();
|
|
133
|
+
}
|
|
134
|
+
const controller = new AbortController();
|
|
135
|
+
self._inflight.set(key, controller);
|
|
136
|
+
|
|
137
|
+
return window.fetch(url, {
|
|
138
|
+
method: 'GET',
|
|
139
|
+
headers: self._reqHeaders(),
|
|
140
|
+
credentials: self.credentials,
|
|
141
|
+
signal: controller.signal
|
|
142
|
+
})
|
|
143
|
+
.then(_resolve)
|
|
144
|
+
.finally(function () {
|
|
145
|
+
if (self._inflight.get(key) === controller) {
|
|
146
|
+
self._inflight.delete(key);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
_component.prototype.query = function (queryParams, targetEl) {
|
|
152
|
+
const self = this;
|
|
153
|
+
const qs = buildQueryParams(queryParams, self.paramKeys);
|
|
154
|
+
const url = buildQueryUrl(self.baseUrl, self.path, qs);
|
|
155
|
+
|
|
156
|
+
const key = targetEl || 'query';
|
|
157
|
+
if (self._inflight.has(key)) {
|
|
158
|
+
self._inflight.get(key).abort();
|
|
159
|
+
}
|
|
160
|
+
const controller = new AbortController();
|
|
161
|
+
self._inflight.set(key, controller);
|
|
162
|
+
|
|
163
|
+
return window.fetch(url, {
|
|
164
|
+
method: 'GET',
|
|
165
|
+
headers: self._reqHeaders(),
|
|
166
|
+
credentials: self.credentials,
|
|
167
|
+
signal: controller.signal
|
|
168
|
+
})
|
|
169
|
+
.then(_resolve)
|
|
170
|
+
.finally(function () {
|
|
171
|
+
if (self._inflight.get(key) === controller) {
|
|
172
|
+
self._inflight.delete(key);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
_component.prototype.create = function (payload, url, idempotencyKey) {
|
|
178
|
+
const self = this;
|
|
179
|
+
return window.fetch(joinUrl(self.baseUrl, url || self.path), {
|
|
180
|
+
method: 'POST',
|
|
181
|
+
headers: self._reqHeaders(idempotencyKey),
|
|
182
|
+
credentials: self.credentials,
|
|
183
|
+
body: JSON.stringify(payload)
|
|
184
|
+
})
|
|
185
|
+
.then(_resolve);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
_component.prototype.update = function (id, payload, expectedVersion, url, idempotencyKey) {
|
|
189
|
+
const self = this;
|
|
190
|
+
if (expectedVersion !== undefined && expectedVersion !== null) {
|
|
191
|
+
payload = Object.assign({}, payload, { expected_version: expectedVersion });
|
|
192
|
+
}
|
|
193
|
+
// An explicit `url` is the COMPLETE resource URL — it already carries the
|
|
194
|
+
// id (e.g. the form's resolved action `/documents/42`). Do NOT re-append
|
|
195
|
+
// id, symmetric with create(). Only the path fallback needs id appended.
|
|
196
|
+
const target = url ? joinUrl(self.baseUrl, url) : joinUrl(self.baseUrl, self.path, id);
|
|
197
|
+
return window.fetch(target, {
|
|
198
|
+
method: 'PUT',
|
|
199
|
+
headers: self._reqHeaders(idempotencyKey),
|
|
200
|
+
credentials: self.credentials,
|
|
201
|
+
body: JSON.stringify(payload)
|
|
202
|
+
})
|
|
203
|
+
.then(_resolve);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
_component.prototype.delete = function (id, url, idempotencyKey) {
|
|
207
|
+
const self = this;
|
|
208
|
+
return window.fetch(joinUrl(self.baseUrl, url || self.path, id), {
|
|
209
|
+
method: 'DELETE',
|
|
210
|
+
headers: self._reqHeaders(idempotencyKey),
|
|
211
|
+
credentials: self.credentials
|
|
212
|
+
})
|
|
213
|
+
.then(_resolve);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
_component.prototype.bulkDelete = function (ids, url, idempotencyKey) {
|
|
217
|
+
const self = this;
|
|
218
|
+
return window.fetch(joinUrl(self.baseUrl, url || self.path, 'bulk-delete'), {
|
|
219
|
+
method: 'DELETE',
|
|
220
|
+
headers: self._reqHeaders(idempotencyKey),
|
|
221
|
+
credentials: self.credentials,
|
|
222
|
+
body: JSON.stringify({ ids: ids })
|
|
223
|
+
})
|
|
224
|
+
.then(_resolve);
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// ─── DOM Event Routing ────────────────────────────────────
|
|
228
|
+
|
|
229
|
+
function _bindEvents(self) {
|
|
230
|
+
self._handlers = {
|
|
231
|
+
sync: function (e) {
|
|
232
|
+
const detail = e.detail || {};
|
|
233
|
+
const targetEl = (detail.meta && detail.meta.targetEl) ? detail.meta.targetEl : null;
|
|
234
|
+
self.fetchDelta(detail.since, targetEl)
|
|
235
|
+
.then(function (data) {
|
|
236
|
+
dispatch(self.dom, 'ln-api-connector:fetched', { data: data, since: detail.since, meta: detail.meta || null });
|
|
237
|
+
})
|
|
238
|
+
.catch(function (err) {
|
|
239
|
+
if (err && err.name === 'AbortError') return;
|
|
240
|
+
dispatch(self.dom, 'ln-api-connector:error', {
|
|
241
|
+
action: 'sync',
|
|
242
|
+
error: err.message,
|
|
243
|
+
status: err.status || 0,
|
|
244
|
+
data: err.data || null,
|
|
245
|
+
since: detail.since,
|
|
246
|
+
meta: detail.meta || null
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
},
|
|
250
|
+
query: function (e) {
|
|
251
|
+
const detail = e.detail || {};
|
|
252
|
+
const queryParams = detail.query || detail;
|
|
253
|
+
const targetEl = (detail.meta && detail.meta.targetEl) ? detail.meta.targetEl : null;
|
|
254
|
+
const key = targetEl || 'query';
|
|
255
|
+
const delay = self.queryDebounce;
|
|
256
|
+
|
|
257
|
+
function _doQuery(d, qp, tel) {
|
|
258
|
+
self.query(qp, tel)
|
|
259
|
+
.then(function (res) {
|
|
260
|
+
const payload = res || {};
|
|
261
|
+
dispatch(self.dom, 'ln-api-connector:fetched', {
|
|
262
|
+
data: payload.data || (Array.isArray(payload) ? payload : []),
|
|
263
|
+
total: payload.total,
|
|
264
|
+
filtered: payload.filtered,
|
|
265
|
+
offset: qp.offset,
|
|
266
|
+
queryGen: qp.queryGen,
|
|
267
|
+
meta: d.meta || null
|
|
268
|
+
});
|
|
269
|
+
})
|
|
270
|
+
.catch(function (err) {
|
|
271
|
+
if (err && err.name === 'AbortError') return;
|
|
272
|
+
dispatch(self.dom, 'ln-api-connector:error', {
|
|
273
|
+
action: 'query',
|
|
274
|
+
error: err.message,
|
|
275
|
+
status: err.status || 0,
|
|
276
|
+
data: err.data || null,
|
|
277
|
+
meta: d.meta || null
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (delay === 0) {
|
|
283
|
+
_doQuery(detail, queryParams, targetEl);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (self._queryTimers.has(key)) {
|
|
288
|
+
clearTimeout(self._queryTimers.get(key));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const timer = setTimeout(function () {
|
|
292
|
+
self._queryTimers.delete(key);
|
|
293
|
+
_doQuery(detail, queryParams, targetEl);
|
|
294
|
+
}, delay);
|
|
295
|
+
|
|
296
|
+
self._queryTimers.set(key, timer);
|
|
297
|
+
},
|
|
298
|
+
cancel: function (e) {
|
|
299
|
+
const detail = e.detail || {};
|
|
300
|
+
const targetKey = (detail.meta && detail.meta.targetEl) ? detail.meta.targetEl : (detail.targetEl || detail.key);
|
|
301
|
+
if (targetKey) self.cancel(targetKey);
|
|
302
|
+
},
|
|
303
|
+
create: function (e) {
|
|
304
|
+
const detail = e.detail || {};
|
|
305
|
+
self.create(detail.data, detail.url, detail.idempotencyKey)
|
|
306
|
+
.then(function (body) {
|
|
307
|
+
const unwrapped = unwrapEnvelope(body);
|
|
308
|
+
dispatch(self.dom, 'ln-api-connector:created', {
|
|
309
|
+
record: unwrapped.record,
|
|
310
|
+
tempId: detail.tempId,
|
|
311
|
+
message: unwrapped.message,
|
|
312
|
+
meta: detail.meta || null
|
|
313
|
+
});
|
|
314
|
+
})
|
|
315
|
+
.catch(function (err) {
|
|
316
|
+
if (err && err.name === 'AbortError') return;
|
|
317
|
+
dispatch(self.dom, 'ln-api-connector:error', {
|
|
318
|
+
action: 'create',
|
|
319
|
+
error: err.message,
|
|
320
|
+
status: err.status || 0,
|
|
321
|
+
data: err.data || null,
|
|
322
|
+
tempId: detail.tempId,
|
|
323
|
+
meta: detail.meta || null
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
},
|
|
327
|
+
update: function (e) {
|
|
328
|
+
const detail = e.detail || {};
|
|
329
|
+
self.update(detail.id, detail.data, detail.expected_version, detail.url, detail.idempotencyKey)
|
|
330
|
+
.then(function (body) {
|
|
331
|
+
const unwrapped = unwrapEnvelope(body);
|
|
332
|
+
dispatch(self.dom, 'ln-api-connector:updated', {
|
|
333
|
+
record: unwrapped.record,
|
|
334
|
+
id: detail.id,
|
|
335
|
+
message: unwrapped.message,
|
|
336
|
+
meta: detail.meta || null
|
|
337
|
+
});
|
|
338
|
+
})
|
|
339
|
+
.catch(function (err) {
|
|
340
|
+
if (err && err.name === 'AbortError') return;
|
|
341
|
+
dispatch(self.dom, 'ln-api-connector:error', {
|
|
342
|
+
action: 'update',
|
|
343
|
+
error: err.message,
|
|
344
|
+
status: err.status || 0,
|
|
345
|
+
data: err.data || null,
|
|
346
|
+
id: detail.id,
|
|
347
|
+
conflictData: err.status === 409 ? err.data : null,
|
|
348
|
+
meta: detail.meta || null
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
},
|
|
352
|
+
delete: function (e) {
|
|
353
|
+
const detail = e.detail || {};
|
|
354
|
+
self.delete(detail.id, detail.url, detail.idempotencyKey)
|
|
355
|
+
.then(function (body) {
|
|
356
|
+
const message = (body && body.message) ? body.message : null;
|
|
357
|
+
dispatch(self.dom, 'ln-api-connector:deleted', {
|
|
358
|
+
response: body,
|
|
359
|
+
id: detail.id,
|
|
360
|
+
message: message,
|
|
361
|
+
meta: detail.meta || null
|
|
362
|
+
});
|
|
363
|
+
})
|
|
364
|
+
.catch(function (err) {
|
|
365
|
+
if (err && err.name === 'AbortError') return;
|
|
366
|
+
dispatch(self.dom, 'ln-api-connector:error', {
|
|
367
|
+
action: 'delete',
|
|
368
|
+
error: err.message,
|
|
369
|
+
status: err.status || 0,
|
|
370
|
+
data: err.data || null,
|
|
371
|
+
id: detail.id,
|
|
372
|
+
meta: detail.meta || null
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
},
|
|
376
|
+
bulkDelete: function (e) {
|
|
377
|
+
const detail = e.detail || {};
|
|
378
|
+
self.bulkDelete(detail.ids, detail.url, detail.idempotencyKey)
|
|
379
|
+
.then(function (body) {
|
|
380
|
+
const message = (body && body.message) ? body.message : null;
|
|
381
|
+
dispatch(self.dom, 'ln-api-connector:bulk-deleted', {
|
|
382
|
+
response: body,
|
|
383
|
+
ids: detail.ids,
|
|
384
|
+
message: message,
|
|
385
|
+
meta: detail.meta || null
|
|
386
|
+
});
|
|
387
|
+
})
|
|
388
|
+
.catch(function (err) {
|
|
389
|
+
if (err && err.name === 'AbortError') return;
|
|
390
|
+
dispatch(self.dom, 'ln-api-connector:error', {
|
|
391
|
+
action: 'bulk-delete',
|
|
392
|
+
error: err.message,
|
|
393
|
+
status: err.status || 0,
|
|
394
|
+
data: err.data || null,
|
|
395
|
+
ids: detail.ids,
|
|
396
|
+
meta: detail.meta || null
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
self.dom.addEventListener('ln-api-connector:request-sync', self._handlers.sync);
|
|
403
|
+
self.dom.addEventListener('ln-api-connector:request-query', self._handlers.query);
|
|
404
|
+
self.dom.addEventListener('ln-api-connector:request-cancel', self._handlers.cancel);
|
|
405
|
+
self.dom.addEventListener('ln-api-connector:request-create', self._handlers.create);
|
|
406
|
+
self.dom.addEventListener('ln-api-connector:request-update', self._handlers.update);
|
|
407
|
+
self.dom.addEventListener('ln-api-connector:request-delete', self._handlers.delete);
|
|
408
|
+
self.dom.addEventListener('ln-api-connector:request-bulk-delete', self._handlers.bulkDelete);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
_component.prototype.destroy = function () {
|
|
412
|
+
if (!this.dom[DOM_ATTRIBUTE]) return;
|
|
413
|
+
|
|
414
|
+
const self = this;
|
|
415
|
+
if (self._inflight) {
|
|
416
|
+
self._inflight.forEach(function (controller) {
|
|
417
|
+
controller.abort();
|
|
418
|
+
});
|
|
419
|
+
self._inflight.clear();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (this._queryTimers) {
|
|
423
|
+
this._queryTimers.forEach(function (timer) {
|
|
424
|
+
if (timer) clearTimeout(timer);
|
|
425
|
+
});
|
|
426
|
+
this._queryTimers.clear();
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (this._handlers) {
|
|
430
|
+
self.dom.removeEventListener('ln-api-connector:request-sync', self._handlers.sync);
|
|
431
|
+
self.dom.removeEventListener('ln-api-connector:request-query', self._handlers.query);
|
|
432
|
+
self.dom.removeEventListener('ln-api-connector:request-cancel', self._handlers.cancel);
|
|
433
|
+
self.dom.removeEventListener('ln-api-connector:request-create', self._handlers.create);
|
|
434
|
+
self.dom.removeEventListener('ln-api-connector:request-update', self._handlers.update);
|
|
435
|
+
self.dom.removeEventListener('ln-api-connector:request-delete', self._handlers.delete);
|
|
436
|
+
self.dom.removeEventListener('ln-api-connector:request-bulk-delete', self._handlers.bulkDelete);
|
|
437
|
+
self._handlers = null;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
delete this.dom[DOM_ATTRIBUTE];
|
|
441
|
+
delete this.dom[DOM_ALIAS];
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
registerComponent(DOM_SELECTOR, DOM_ATTRIBUTE, _component, 'ln-api-connector', {
|
|
445
|
+
attributes: ATTRIBUTES
|
|
446
|
+
});
|
|
447
|
+
})();
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# `data-ln-api-queue`
|
|
2
2
|
|
|
3
|
+
> Applied to an outbox element (`<li data-ln-api-queue>`) nested inside `data-ln-data-coordinator`. It listens for `ln-api-queue:request-enqueue` from the coordinator, persists mutations to an internal `IndexedDB` outbox (`ln_api_queue`) with monotonic per-scope sequence counters, and emits `ln-api-queue:send` CustomEvents for FIFO dispatch. It never initiates network requests directly, updating retry attempts with exponential backoff until acknowledged via `ack`/`nack`.
|
|
4
|
+
|
|
3
5
|
A zero-dependency, Local-First **offline write outbox** component that implements the persistent-queue tier of `ln-ashlar`'s 3-tier data layer.
|
|
4
6
|
|
|
5
7
|
This component persists pending mutations to its own `IndexedDB` database and replays them, FIFO per chain, once the coordinator can execute transport for them. It is **connector-blind and id-blind** — it never calls the network itself, never knows about REST paths, and never interprets `entryId`/`targetId`/`chainKey` beyond bookkeeping. The parent `ln-data-coordinator` executes the actual transport call on the queue's `ln-api-queue:send` command and reports the outcome back via `ack` / `nack`.
|
|
@@ -11,9 +13,9 @@ This component persists pending mutations to its own `IndexedDB` database and re
|
|
|
11
13
|
Place the queue inside your parent coordinator element alongside your store and connector — it is an **optional** third child:
|
|
12
14
|
|
|
13
15
|
```html
|
|
14
|
-
<ul data-ln-data-coordinator
|
|
16
|
+
<ul id="documents-module" data-ln-data-coordinator hidden>
|
|
15
17
|
<!-- Storage Layer Cache (Blind to networking) -->
|
|
16
|
-
<li data-ln-data-store
|
|
18
|
+
<li id="documents" data-ln-data-store
|
|
17
19
|
data-ln-data-store-indexes="status,updated_at">
|
|
18
20
|
</li>
|
|
19
21
|
|
|
@@ -24,7 +26,7 @@ Place the queue inside your parent coordinator element alongside your store and
|
|
|
24
26
|
</li>
|
|
25
27
|
|
|
26
28
|
<!-- Offline Outbox (optional Child 3) -->
|
|
27
|
-
<li data-ln-api-queue></li>
|
|
29
|
+
<li id="documents-queue" data-ln-api-queue></li>
|
|
28
30
|
</ul>
|
|
29
31
|
```
|
|
30
32
|
|
|
@@ -36,8 +38,9 @@ When this child is absent, the coordinator's write handlers call the connector d
|
|
|
36
38
|
|
|
37
39
|
| Attribute | Category | Description |
|
|
38
40
|
|-----------|----------|-------------|
|
|
39
|
-
| `
|
|
40
|
-
| `data-ln-api-queue
|
|
41
|
+
| `id="name"` | Identity | Unique identifier of the queue (the scope name). Defaults to the coordinator's `id` if nested, else `'default'`. |
|
|
42
|
+
| `data-ln-api-queue` | Selector | Marker attribute to declare the component. |
|
|
43
|
+
| `data-ln-api-queue-online` | Connectivity Override | Consumer override attribute (e.g. `"false"` to simulate offline state during testing/manual debugging). Checked via `_isOnline()`. |
|
|
41
44
|
|
|
42
45
|
---
|
|
43
46
|
|
|
@@ -48,7 +51,7 @@ The queue owns its **own** IndexedDB database, `ln_api_queue` — entirely separ
|
|
|
48
51
|
| Object store | Key path | Indexes | Purpose |
|
|
49
52
|
|---|---|---|---|
|
|
50
53
|
| `outbox` | `entryId` | `by_scope_chain` (`[scope, chainKey]`), `by_scope_seq` (`[scope, seq]`) | One row per pending mutation. `seq` is a monotonically increasing per-scope counter used to preserve global FIFO ordering within a scope; `by_scope_chain` is used to find the head entry per chain. |
|
|
51
|
-
| `_queue_meta` | `key` | — | Holds `seq:<scope>` counters and `paused:<scope>` auth
|
|
54
|
+
| `_queue_meta` | `key` | — | Holds `seq:<scope>` counters and `paused:<scope>` state (`'auth'`, `'manual'`, or `false`). |
|
|
52
55
|
|
|
53
56
|
Each `outbox` entry carries: `entryId`, `scope`, `chainKey`, `seq`, `op`, `targetId`, `payload`, `expectedVersion`, `meta`, `attempts`, `status` (`pending` / `inflight` / `failed`), `leaseOwner`, `leaseUntil`, and timestamps. The queue never inspects `payload` — it passes it through untouched to whatever the coordinator sends on `ln-api-queue:send`.
|
|
54
57
|
|
|
@@ -86,6 +89,7 @@ const queue = queueEl.lnApiQueue;
|
|
|
86
89
|
| `ln-api-queue:request-remap` | `{ oldKey, newId }` | For pending entries whose chain is `oldKey`: any entry with `targetId === oldKey` gets `targetId = newId`; the chain itself is re-keyed from `oldKey` to `newId`; if `meta.action` contains `oldKey` as a substring, it is string-replaced with `newId` too (keeps a persisted per-record URL in sync after a create resolves). |
|
|
87
90
|
| `ln-api-queue:resolve-create` | `{ entryId, oldKey, newId }` | Atomically deletes the acknowledged create and remaps every queued sibling from the temp key to the authoritative id in one transaction, then advances the chain. |
|
|
88
91
|
| `ln-api-queue:request-resume` | `{}` | Clears the pause on this scope and resumes draining. |
|
|
92
|
+
| `ln-api-queue:request-pause` | `{}` | Manually pauses draining for this scope. |
|
|
89
93
|
| `ln-api-queue:request-drain` | `{}` | Manually triggers a drain attempt (e.g. to retry `failed` entries). |
|
|
90
94
|
| `ln-api-queue:request-clear` | `{}` | Deletes all entries for this scope (e.g. on logout). |
|
|
91
95
|
|
|
@@ -97,12 +101,11 @@ const queue = queueEl.lnApiQueue;
|
|
|
97
101
|
| `ln-api-queue:enqueued` | `{ entryId, chainKey, count }` | An entry was persisted. |
|
|
98
102
|
| `ln-api-queue:pending-count` | `{ count, scope }` | Live outbox depth for the scope — the primary UI-facing signal (badge, banner). |
|
|
99
103
|
| `ln-api-queue:auth-required` | `{ entryId, chainKey }` | The scope paused after a `401`/`419` nack. The consumer drives re-authentication, then dispatches `request-resume`. |
|
|
100
|
-
| `ln-api-queue:paused` | `{ reason }` | Draining paused for this scope. |
|
|
104
|
+
| `ln-api-queue:paused` | `{ reason: "auth" \| "manual", restored?: Boolean }` | Draining paused for this scope. `restored: true` when re-emitted upon component boot from persisted state. |
|
|
101
105
|
| `ln-api-queue:resumed` | `{}` | Draining resumed for this scope. |
|
|
102
106
|
| `ln-api-queue:failed` | `{ entryId, chainKey, attempts }` | Retries exhausted (see backoff below); the entry is retained (not deleted) for a manual `request-drain`. |
|
|
103
107
|
| `ln-api-queue:drained` | `{ scope }` | The outbox for this scope is empty. |
|
|
104
108
|
| `ln-api-queue:error` | `{ operation, entryId?, error }` | IndexedDB or queue orchestration failed without silently discarding the entry. |
|
|
105
|
-
| `ln-api-queue:destroyed` | `{ scope }` | The instance was torn down. |
|
|
106
109
|
|
|
107
110
|
---
|
|
108
111
|
|
|
@@ -174,7 +177,7 @@ The queue never imports or references a connector, never constructs a URL, and n
|
|
|
174
177
|
|
|
175
178
|
```javascript
|
|
176
179
|
(function () {
|
|
177
|
-
const parent = document.
|
|
180
|
+
const parent = document.getElementById('documents-module');
|
|
178
181
|
const queueEl = parent.querySelector('[data-ln-api-queue]');
|
|
179
182
|
const connectorEl = parent.querySelector('[data-ln-api-connector]');
|
|
180
183
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){"use strict";function R(){return typeof window>"u"?!1:window.lnDebug===!0||window.lnCore&&window.lnCore._debugSink?!0:typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug")||document.body.querySelector("[data-ln-debug]")!==null:!1}function k(e){if(typeof window>"u")return!1;if(window.lnDebug===!0)return!0;if(window.lnCore&&window.lnCore._debugIsContained)return e?window.lnCore._debugIsContained(e):window.lnCore._debugSink!==null;if(e&&e.closest){const t=e.closest("[data-ln-debug]");return!(!t||typeof document<"u"&&t===document.documentElement)}return typeof document<"u"&&document.body?document.body.hasAttribute("data-ln-debug"):!1}if(typeof window<"u"&&(window.lnCore=window.lnCore||{},!window.lnCore._warnBound)){window.lnCore._warnBound=!0;const e=console.warn;console.warn=function(...t){if(typeof t[0]=="string"&&(t[0].startsWith("[ln-")||t[0].startsWith("[lnCore"))){let o=null;for(let u=1;u<t.length;u++)if(t[u]&&t[u].nodeType===1){o=t[u];break}if(!k(o))return}e.apply(console,t)}}function w(e,t,r){const o=r||{};window.lnCore._debugSink&&window.lnCore._debugSink("event",t,e,o),e.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:o}))}function A(e,t){if(!document.body){document.addEventListener("DOMContentLoaded",function(){A(e,t)}),console.warn("["+t+'] Script loaded before <body> — add "defer" to your <script> tag');return}e()}const P={};function z(e,t){P[e]=t}function X(e){return P[e]||{ingress:t=>t,egress:t=>t}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerDataMapper=z,window.lnCore.getDataMapper=X);function G(){typeof window>"u"||(window.lnCore=window.lnCore||{},!window.lnCore._localeObserverBound&&(window.lnCore._localeObserverBound=!0,A(function(){new MutationObserver(function(){w(document,"ln-core:locale-change",{})}).observe(document.documentElement,{attributes:!0,attributeFilter:["lang"],subtree:!0})},"ln-core")))}const Q={};function J(e,t){if(!e||typeof t!="object")return;const r=e.toLowerCase().split("-")[0];Q[r]=t}function Y(e){if(!e)return null;const t=e.toLowerCase().split("-")[0];return Q[t]||null}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.registerLocaleFallback=J,window.lnCore.getLocaleFallback=Y,window.lnCore.ensureLocaleObserver=G);const E={};function Z(e,t){E[e]||(E[e]=document.querySelector('[data-ln-template="'+e+'"]'));const r=E[e];return r?r.content.cloneNode(!0):(console.warn("["+(t||"ln-core")+'] Template "'+e+'" not found'),null)}function B(e,t){if(!e||!t)return e;const r=e.querySelectorAll("[data-ln-field]");for(let i=0;i<r.length;i++){const l=r[i],c=l.getAttribute("data-ln-field");t[c]!=null&&(l.textContent=t[c])}const o=e.querySelectorAll("[data-ln-attr]");for(let i=0;i<o.length;i++){const l=o[i],c=l.getAttribute("data-ln-attr").split(",");for(let d=0;d<c.length;d++){const n=c[d].trim().split(":");if(n.length!==2)continue;const s=n[0].trim(),f=n[1].trim();t[f]!=null&&l.setAttribute(s,t[f])}}const u=e.querySelectorAll("[data-ln-show]");for(let i=0;i<u.length;i++){const l=u[i],c=l.getAttribute("data-ln-show");c in t&&l.classList.toggle("hidden",!t[c])}const a=e.querySelectorAll("[data-ln-class]");for(let i=0;i<a.length;i++){const l=a[i],c=l.getAttribute("data-ln-class").split(",");for(let d=0;d<c.length;d++){const n=c[d].trim().split(":");if(n.length!==2)continue;const s=n[0].trim(),f=n[1].trim();f in t&&l.classList.toggle(s,!!t[f])}}return e}function ee(e,t){e.matches&&e.matches("[data-ln-form], [data-ln-fillable]")&&(window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",e,t??null),e.dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0})));const r=e.querySelectorAll("[data-ln-form], [data-ln-fillable]");for(let o=0;o<r.length;o++)window.lnCore._debugSink&&window.lnCore._debugSink("event","ln-fill",r[o],t??null),r[o].dispatchEvent(new CustomEvent("ln-fill",{detail:t??null,bubbles:!0}));return e}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._fillBound||(window.lnCore._fillBound=!0,document.addEventListener("ln-fill",function(e){if(!(!e.target.matches||!e.target.matches("[data-ln-fillable]")))if(e.detail)B(e.target,e.detail);else{const t=e.target.querySelectorAll("[data-ln-field]");for(let r=0;r<t.length;r++)t[r].textContent=""}})));function M(e,t){if(!e||!t)return e;const r=document.createTreeWalker(e,NodeFilter.SHOW_TEXT);for(;r.nextNode();){const a=r.currentNode;a.textContent.indexOf("{{")!==-1&&(a.textContent=a.textContent.replace(/\{\{\s*(\w+)\s*\}\}/g,function(i,l){return t[l]!==void 0?t[l]:""}))}const o=function(a,i){return t[i]!==void 0?t[i]:""},u=Array.from(e.querySelectorAll("*"));e.nodeType===1&&u.push(e);for(let a=0;a<u.length;a++){const i=u[a],l=i.attributes;for(let c=0;c<l.length;c++){const d=l[c];d.value.indexOf("{{")!==-1&&i.setAttribute(d.name,d.value.replace(/\{\{\s*(\w+)\s*\}\}/g,o))}}return e}function te(e,t,r,o,u,a){const i={};for(let c=0;c<e.children.length;c++){const d=e.children[c],n=d.getAttribute("data-ln-render-key");n&&(i[n]=d)}const l=document.createDocumentFragment();for(let c=0;c<t.length;c++){const d=t[c],n=String(o(d));let s=i[n];if(s)u(s,d,c);else{const f=Z(r,a);if(!f||(M(f,d),s=f.firstElementChild,!s))continue;s.setAttribute("data-ln-render-key",n),u(s,d,c)}l.appendChild(s)}e.textContent="",e.appendChild(l)}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.fillTemplate=M,window.lnCore.fill=B,window.lnCore.lnFill=ee,window.lnCore.renderList=te);function $(e,t,r,o,u){if(!e||t===null)return!0;const a=o||"ln-component",i=e.type;if(i==="trigger"||i==="marker"||i==="string"||i==="list"||!i||t===""&&e.fallback!==void 0)return!0;const l=c=>{u?console.warn(c,u):console.warn(c)};if(i==="boolean"){const c=t.trim().toLowerCase();return c!==""&&c!=="true"&&c!=="false"&&c!=="1"&&c!=="0"?(l(`[${a}] Invalid value "${t}" for boolean attribute "${r}". Allowed: "true", "false", or presence-only.`),!1):!0}if(i==="enum"){const c=e.values||[];return c.includes(t)?!0:(l(`[${a}] Invalid value "${t}" for attribute "${r}". Allowed: ${c.join(", ")}. Fallback: "${e.fallback}".`),!1)}if(i==="integer"){if(!/^-?\d+$/.test(t))return l(`[${a}] Invalid integer "${t}" for attribute "${r}". Fallback: ${e.fallback}.`),!1;const c=parseInt(t,10);return e.min!==void 0&&c<e.min?(l(`[${a}] Value ${c} for attribute "${r}" is less than min (${e.min}).`),!1):e.max!==void 0&&c>e.max?(l(`[${a}] Value ${c} for attribute "${r}" is greater than max (${e.max}).`),!1):!0}if(i==="float")return isNaN(Number(t))?(l(`[${a}] Invalid float "${t}" for attribute "${r}". Fallback: ${e.fallback}.`),!1):!0;if(i==="json")try{return JSON.parse(t),!0}catch(c){return l(`[${a}] Invalid JSON for attribute "${r}": ${c.message}. Fallback: ${e.fallback}.`),!1}return!0}function ne(e){const t={};for(const r in e){const o=e[r];o&&o.effect&&(t[r]=o.effect)}return Object.keys(t).length?t:null}function re(e){if(e.onAttrChange&&!e.declared)return null;const t=new Set;if(e.effects)for(const r in e.effects)t.add(r);if(e.onAttrChange&&e.declared)for(const r of e.declared)t.add(r);return t}function S(e,t,r,o){if(e.nodeType!==1)return;const a=t.indexOf("[")!==-1||t.indexOf(".")!==-1||t.indexOf("#")!==-1?t:"["+t+"]",i=Array.from(e.querySelectorAll(a));e.matches&&e.matches(a)&&i.push(e);for(const l of i)if(!l[r]){window.lnCore._persistSink&&l.hasAttribute("data-ln-persist")&&window.lnCore._persistSink(l,t);try{l[r]=new o(l)}catch(c){console.error("["+r+"] init failed",l,c)}}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[]);function oe(){return typeof window<"u"&&window.lnCore&&window.lnCore._bootHolds||0}function ie(e){typeof window<"u"?(window.lnCore=window.lnCore||{},window.lnCore._bootHolds=window.lnCore._bootHolds||0,window.lnCore._bootQueue=window.lnCore._bootQueue||[],window.lnCore._bootHolds>0?window.lnCore._bootQueue.push(e):setTimeout(e,0)):e()}function N(){window.lnCore=window.lnCore||{};const e=window.lnCore._attrRegistry=window.lnCore._attrRegistry||{byAttr:new Map,reactive:[],persist:[]};return e.byReactive=e.byReactive||new Map,e.reactiveWildcard=e.reactiveWildcard||[],e}function se(e){const t=N(),r=e.observed||[];for(let o=0;o<r.length;o++){const u=r[o];t.byAttr.has(u)||t.byAttr.set(u,[]),t.byAttr.get(u).push(e)}if(t.byDeclaredAttr=t.byDeclaredAttr||new Map,e.attributes)for(const o in e.attributes){t.byDeclaredAttr.has(o)||t.byDeclaredAttr.set(o,[]);const u=t.byDeclaredAttr.get(o);u.some(a=>a.componentTag===e.componentTag)||u.push({spec:e.attributes[o],componentTag:e.componentTag})}if(e.onAttrChange||e.effects){t.reactive.push(e);const o=re(e);if(o===null)t.reactiveWildcard.push(e);else for(const u of o)t.byReactive.has(u)||t.byReactive.set(u,[]),t.byReactive.get(u).push(e)}e.persist&&t.persist.push(e)}function F(e,t,r,o){for(let u=0;u<e.length;u++){const a=e[u];if(!t[a.attribute])continue;const i=a.effects&&a.effects[r];i?i(t,r,o):a.onAttrChange&&(!a.declared||a.declared.has(r))&&a.onAttrChange(t,r,o)}}function ae(e){const t=e.target,r=e.attributeName;if(e.oldValue===t.getAttribute(r))return;const o=N(),u=o.byAttr.get(r);if(R()&&o.byDeclaredAttr&&o.byDeclaredAttr.has(r)&&k(t)){const a=o.byDeclaredAttr.get(r),i=t.getAttribute(r);for(let l=0;l<a.length;l++)$(a[l].spec,i,r,a[l].componentTag,t)}if(window.lnCore._debugSink&&(r.indexOf("data-ln-")===0||u)&&window.lnCore._debugSink("attr",r,t,{oldValue:e.oldValue,newValue:t.getAttribute(r)}),r.indexOf("data-ln-")===0){const a=o.byReactive.get(r);a&&F(a,t,r,e.oldValue),o.reactiveWildcard.length&&F(o.reactiveWildcard,t,r,e.oldValue)}if(u)for(let a=0;a<u.length;a++){const i=u[a];if(i.handler){i.handler(t,r,e.oldValue);continue}i.onAttributeChange&&t[i.attribute]?i.onAttributeChange(t,r):(S(t,i.selector,i.attribute,i.ComponentFn),i.onInit&&i.onInit(t))}}function ue(){window.lnCore=window.lnCore||{},!window.lnCore._attrObserverBound&&(window.lnCore._attrObserverBound=!0,A(function(){new MutationObserver(function(t){for(let r=0;r<t.length;r++)try{ae(t[r])}catch(o){console.error("[ln-core] mutation handler failed",t[r].target,o)}}).observe(document.body,{attributes:!0,subtree:!0,attributeOldValue:!0})},"ln-core"))}function K(){return window.lnCore=window.lnCore||{},window.lnCore._lifecycleRegistry=window.lnCore._lifecycleRegistry||[]}function le(e){const t=K();if(t.length){if(e.target)for(let r=0;r<t.length;r++){const o=t[r];if(o.onSubtreeChange){const u=o.query,a=e.target.nodeType===1?e.target.matches(u)?e.target:e.target.closest(u):e.target.parentElement?e.target.parentElement.closest(u):null;a&&o.onSubtreeChange(a,e)}}for(let r=0;r<e.addedNodes.length;r++){const o=e.addedNodes[r];if(o.nodeType===1)for(let u=0;u<t.length;u++){const a=t[u];S(o,a.selector,a.attribute,a.ComponentFn),a.onInit&&a.onInit(o)}}for(let r=0;r<e.removedNodes.length;r++){const o=e.removedNodes[r];if(o.nodeType===1)for(let u=0;u<t.length;u++){const a=t[u],i=a.query,l=Array.from(o.querySelectorAll(i));o.matches&&o.matches(i)&&l.push(o);for(let c=0;c<l.length;c++){const d=l[c];if(!document.contains(d)){const n=d[a.attribute];if(n&&typeof n.destroy=="function")try{n.destroy()}catch(s){console.error("["+a.attribute+"] destroy failed",d,s)}delete d[a.attribute]}}}}}}function ce(){window.lnCore=window.lnCore||{},!window.lnCore._lifecycleObserverBound&&(window.lnCore._lifecycleObserverBound=!0,A(function(){new MutationObserver(function(t){for(let r=0;r<t.length;r++){const o=t[r];if(o.type==="childList")try{le(o)}catch(u){console.error("[ln-core] lifecycle handler failed",o.target,u)}}}).observe(document.body,{childList:!0,subtree:!0})},"ln-core"))}function de(e,t,r,o,u={}){const a=u.extraAttributes||[],i=u.onAttributeChange||null,l=u.onSubtreeChange||null,c=u.onInit||null,d=u.onAttrChange||null,n=u.effects||null,s=u.attributes||null,f=s?ne(s):n,p=s?new Set(Object.keys(s)):null,m=u.persist||null;function h(D){const _=D||document.body;if(S(_,e,t,r),s&&R())for(const x in s){const Ee=s[x],L=Array.from(_.querySelectorAll("["+x+"]"));_.matches&&_.matches("["+x+"]")&&L.push(_);for(let O=0;O<L.length;O++){const T=L[O];k(T)&&$(Ee,T.getAttribute(x),x,o,T)}}c&&c(_)}const C=[];if(e.indexOf("[")!==-1){const D=/\[([\w-]+)/g;let _;for(;(_=D.exec(e))!==null;)C.push(_[1])}else C.push(e);se({selector:e,attribute:t,componentTag:o,attributes:s,ComponentFn:r,onInit:c,observed:C.concat(a),onAttributeChange:i,onAttrChange:d,effects:f,declared:p,persist:m}),ue();const ke=e.indexOf("[")!==-1||e.indexOf(".")!==-1||e.indexOf("#")!==-1?e:"["+e+"]";K().push({selector:e,attribute:t,ComponentFn:r,onInit:c,onSubtreeChange:l,query:ke}),ce(),window[t]=h;function H(){oe()>0?ie(function(){h(document.body)}):h(document.body)}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",H):H(),h}function U(e){return(e||"").replace(/^#/,"")}function I(e){const t=e===void 0?location.hash:e,r={},o=U(t);if(!o)return r;const u=o.split("&");for(let a=0;a<u.length;a++){const i=u[a];if(!i)continue;const l=i.indexOf(":"),c=l>-1?i.slice(0,l):i,d=l>-1?i.slice(l+1):"";if(c)try{r[c]=decodeURIComponent(d)}catch{r[c]=d}}return r}function fe(e){if(!e)return null;const t=I();return e in t?t[e]:null}function pe(e,t){if(!e)return;const r=I();t==null?delete r[e]:r[e]=String(t);const u=Object.keys(r).map(function(a){const i=r[a];return i===""?a:a+":"+encodeURIComponent(i)}).join("&");U(location.hash)!==u&&(location.hash=u)}function he(e){return e.button===1||e.ctrlKey||e.metaKey||e.shiftKey?!1:(e.preventDefault(),!0)}function we(e,t){if(!e||!e.hasAttribute("data-ln-hash"))return null;const r=e.getAttribute("data-ln-hash");if(r&&r.trim()!=="")return r.trim();const o=e.getAttribute("data-ln-sort")||e.getAttribute("data-ln-search-for")||e.getAttribute("data-ln-search")||e.getAttribute("data-ln-filter")||e.id;return o?t?o+"-"+t:o:t||null}function me(e,t){return!t||t==="none"||e===null||e===void 0?null:String(e)+"."+t}function be(e){return!e||typeof e!="string"?null:e.endsWith(".asc")?{fieldOrColumn:e.slice(0,-4),direction:"asc"}:e.endsWith(".desc")?{fieldOrColumn:e.slice(0,-5),direction:"desc"}:null}function ye(e,t){return!e||!Array.isArray(t)||t.length===0?null:e+":"+t.map(encodeURIComponent).join(",")}function ge(e){if(!e||typeof e!="string")return null;const t=e.indexOf(":");if(t===-1)return null;const r=e.slice(0,t),o=e.slice(t+1),u=o?o.split(",").map(function(a){try{return decodeURIComponent(a)}catch{return a}}).filter(Boolean):[];return{key:r,values:u}}typeof window<"u"&&(window.lnCore=window.lnCore||{},window.lnCore.hashParse=I,window.lnCore.hashGet=fe,window.lnCore.hashSet=pe,window.lnCore.hashLinkClick=he,window.lnCore.resolveHashNamespace=we,window.lnCore.hashSortEncode=me,window.lnCore.hashSortDecode=be,window.lnCore.hashFilterEncode=ye,window.lnCore.hashFilterDecode=ge);const _e="ln_api_queue",Ce=2,b="outbox",y="_queue_meta";function g(e,t){return e.error||new Error(t)}function q(e,t){return e.bound([t,-1/0],[t,1/0])}function V(e){return"seq:"+e}function v(e){return"paused:"+e}function j(e){e.leaseOwner=null,e.leaseUntil=0}function qe(e,t,r){return typeof e!="string"||e.indexOf(t)===-1?e:e.split(t).join(r)}function xe(e,t,r,o){const u=new Map,a=[],i=[];for(const l of e||[])u.has(l.chainKey)||u.set(l.chainKey,[]),u.get(l.chainKey).push(l);return u.forEach((l,c)=>{l.sort((n,s)=>n.seq-s.seq);const d=l[0];if(!(!d||d.status==="failed")){if(d.status==="inflight"&&(d.leaseUntil||0)>o){i.push({chainKey:c,at:d.leaseUntil});return}if((d.nextAttemptAt||0)>o){i.push({chainKey:c,at:d.nextAttemptAt});return}d.status="inflight",d.leaseOwner=t,d.leaseUntil=o+r,d.updatedAt=o,a.push(d)}}),{entries:a,wakeups:i}}function Ae(e,t,r,o,u){const a=[],i=[];for(const l of e||[]){if(l.entryId===t){i.push(l.entryId);continue}l.chainKey===r&&(l.chainKey=o,l.targetId===r&&(l.targetId=o),l.meta&&l.meta.id===r&&(l.meta.id=o),l.meta&&typeof l.meta.action=="string"&&(l.meta.action=qe(l.meta.action,r,o)),l.updatedAt=u,a.push(l))}return{changed:a,deleted:i}}class ve{constructor(t){t=t||{},this.indexedDB=t.indexedDB||globalThis.indexedDB,this.keyRange=t.IDBKeyRange||globalThis.IDBKeyRange,this.dbName=t.dbName||_e,this.now=t.now||(()=>Date.now()),this.uuid=t.uuid||(()=>crypto.randomUUID()),this._db=null,this._ready=null}open(){return this._ready?this._ready:!this.indexedDB||!this.keyRange?Promise.resolve(null):(this._ready=new Promise((t,r)=>{const o=this.indexedDB.open(this.dbName,Ce);o.onupgradeneeded=u=>{const a=u.target.result;let i;a.objectStoreNames.contains(b)?i=u.target.transaction.objectStore(b):i=a.createObjectStore(b,{keyPath:"entryId"}),i.indexNames.contains("by_scope_chain")||i.createIndex("by_scope_chain",["scope","chainKey"],{unique:!1}),i.indexNames.contains("by_scope_seq")||i.createIndex("by_scope_seq",["scope","seq"],{unique:!1}),a.objectStoreNames.contains(y)||a.createObjectStore(y,{keyPath:"key"})},o.onerror=()=>r(g(o,"Queue database open failed")),o.onsuccess=u=>{this._db=u.target.result,this._db.onversionchange=()=>this.close(),t(this._db)}}),this._ready)}close(){this._db&&this._db.close(),this._db=null,this._ready=null}deleteDatabase(){return this.close(),this.indexedDB?new Promise((t,r)=>{const o=this.indexedDB.deleteDatabase(this.dbName);o.onsuccess=()=>t(),o.onerror=()=>r(g(o,"Queue database delete failed")),o.onblocked=()=>r(new Error("Queue database delete blocked"))}):Promise.resolve()}allForScope(t){return this.open().then(r=>r?new Promise((o,u)=>{const i=r.transaction(b,"readonly").objectStore(b).index("by_scope_seq").getAll(q(this.keyRange,t));i.onsuccess=()=>o(i.result||[]),i.onerror=()=>u(g(i,"Queue scope read failed"))}):[])}enqueue(t,r){return r=r||{},this.open().then(o=>o?new Promise((u,a)=>{const i=o.transaction([y,b],"readwrite"),l=i.objectStore(y),c=i.objectStore(b),d=V(t);let n=null;const s=p=>{const m=p+1;n={entryId:this.uuid(),scope:t,chainKey:r.chainKey,seq:m,op:r.op,targetId:r.targetId!==void 0?r.targetId:null,payload:r.payload,expectedVersion:r.expectedVersion!==void 0?r.expectedVersion:null,meta:r.meta||{},attempts:0,nextAttemptAt:0,status:"pending",leaseOwner:null,leaseUntil:0,createdAt:this.now(),updatedAt:this.now()},l.put({key:d,value:m}),c.put(n)},f=l.get(d);f.onerror=()=>a(g(f,"Queue sequence read failed")),f.onsuccess=()=>{const p=f.result;if(p&&typeof p.value=="number"){s(p.value);return}const m=c.index("by_scope_seq").getAll(q(this.keyRange,t));m.onerror=()=>a(g(m,"Queue sequence migration failed")),m.onsuccess=()=>{const h=(m.result||[]).reduce((C,W)=>Math.max(C,W.seq||0),0);s(h)}},i.oncomplete=()=>u(n),i.onerror=()=>a(i.error||new Error("Queue enqueue transaction failed")),i.onabort=()=>a(i.error||new Error("Queue enqueue transaction aborted"))}):null)}claimReady(t,r,o){return this.open().then(u=>u?new Promise((a,i)=>{const l=u.transaction(b,"readwrite"),c=l.objectStore(b),d=c.index("by_scope_seq").getAll(q(this.keyRange,t)),n=this.now();let s={entries:[],wakeups:[]};d.onerror=()=>i(g(d,"Queue claim read failed")),d.onsuccess=()=>{s=xe(d.result||[],r,o,n);for(const f of s.entries)c.put(f)},l.oncomplete=()=>a(s),l.onerror=()=>i(l.error||new Error("Queue claim transaction failed")),l.onabort=()=>i(l.error||new Error("Queue claim transaction aborted"))}):{entries:[],wakeups:[]})}ack(t,r){return this._updateEntry(t,r,(o,u)=>(u.delete(o.entryId),{status:"acked",entry:o}))}nack(t,r,o,u){u=u||{};const a=u.maxAttempts||8,i=u.backoff||[2e3,5e3,15e3,6e4,3e5];return this.open().then(l=>l?new Promise((c,d)=>{const n=l.transaction([b,y],"readwrite"),s=n.objectStore(b),f=n.objectStore(y),p=s.get(r);let m=null;p.onerror=()=>d(g(p,"Queue nack read failed")),p.onsuccess=()=>{const h=p.result;if(!(!h||h.scope!==t)){if(o==="drop"){s.delete(h.entryId),m={status:"dropped",entry:h};return}if(j(h),h.updatedAt=this.now(),o==="auth"){h.status="pending",s.put(h),f.put({key:v(t),value:"auth"}),m={status:"auth",entry:h};return}if(o==="retry"){if(h.attempts=(h.attempts||0)+1,h.attempts>=a){h.status="failed",h.nextAttemptAt=0,s.put(h),m={status:"failed",entry:h};return}const C=i[Math.min(h.attempts-1,i.length-1)];h.status="pending",h.nextAttemptAt=this.now()+C,s.put(h),m={status:"retry",entry:h,delay:C}}}},n.oncomplete=()=>c(m),n.onerror=()=>d(n.error||new Error("Queue nack transaction failed")),n.onabort=()=>d(n.error||new Error("Queue nack transaction aborted"))}):null)}remap(t,r,o){return this._remapTransaction(t,null,r,o)}resolveCreate(t,r,o,u){return this._remapTransaction(t,r,o,u)}_remapTransaction(t,r,o,u){return this.open().then(a=>a?new Promise((i,l)=>{const c=a.transaction(b,"readwrite"),d=c.objectStore(b),n=d.index("by_scope_seq").getAll(q(this.keyRange,t));let s={changed:[],deleted:[]};n.onerror=()=>l(g(n,"Queue remap read failed")),n.onsuccess=()=>{s=Ae(n.result||[],r,o,u,this.now());for(const f of s.deleted)d.delete(f);for(const f of s.changed)d.put(f)},c.oncomplete=()=>i(s.changed),c.onerror=()=>l(c.error||new Error("Queue remap transaction failed")),c.onabort=()=>l(c.error||new Error("Queue remap transaction aborted"))}):[])}resetFailed(t){return this.open().then(r=>r?new Promise((o,u)=>{const a=r.transaction(b,"readwrite"),i=a.objectStore(b),l=i.index("by_scope_seq").getAll(q(this.keyRange,t));let c=0;l.onerror=()=>u(g(l,"Queue failed-entry read failed")),l.onsuccess=()=>{for(const d of l.result||[])d.status==="failed"&&(d.status="pending",d.attempts=0,d.nextAttemptAt=0,d.updatedAt=this.now(),j(d),i.put(d),c++)},a.oncomplete=()=>o(c),a.onerror=()=>u(a.error||new Error("Queue failed-entry reset failed")),a.onabort=()=>u(a.error||new Error("Queue failed-entry reset aborted"))}):0)}getPaused(t){return this.open().then(r=>r?new Promise((o,u)=>{const i=r.transaction(y,"readonly").objectStore(y).get(v(t));i.onsuccess=()=>{const l=i.result?i.result.value:!1;o(l||!1)},i.onerror=()=>u(g(i,"Queue pause-state read failed"))}):!1)}setPaused(t,r){return this.open().then(o=>{if(o)return new Promise((u,a)=>{const i=o.transaction(y,"readwrite"),l=typeof r=="string"?r:r?"manual":!1;i.objectStore(y).put({key:v(t),value:l}),i.oncomplete=()=>u(),i.onerror=()=>a(i.error||new Error("Queue pause-state write failed")),i.onabort=()=>a(i.error||new Error("Queue pause-state write aborted"))})})}clear(t){return this.open().then(r=>{if(r)return new Promise((o,u)=>{const a=r.transaction([b,y],"readwrite"),l=a.objectStore(b).index("by_scope_seq").openCursor(q(this.keyRange,t));l.onsuccess=c=>{const d=c.target.result;d&&(d.delete(),d.continue())},l.onerror=()=>u(g(l,"Queue clear failed")),a.objectStore(y).delete(V(t)),a.objectStore(y).delete(v(t)),a.oncomplete=()=>o(),a.onerror=()=>u(a.error||new Error("Queue clear transaction failed")),a.onabort=()=>u(a.error||new Error("Queue clear transaction aborted"))})})}_updateEntry(t,r,o){return this.open().then(u=>u?new Promise((a,i)=>{const l=u.transaction(b,"readwrite"),c=l.objectStore(b),d=c.get(r);let n=null;d.onerror=()=>i(g(d,"Queue entry read failed")),d.onsuccess=()=>{const s=d.result;!s||s.scope!==t||(n=o(s,c))},l.oncomplete=()=>a(n),l.onerror=()=>i(l.error||new Error("Queue entry transaction failed")),l.onabort=()=>i(l.error||new Error("Queue entry transaction aborted"))}):null)}}(function(){const e="data-ln-api-queue",t="lnApiQueue",r=[2e3,5e3,15e3,6e4,3e5],o=8,u=6e4;if(window[t]!==void 0)return;function a(n){const s=n[t];s&&s._drain()}const i={"data-ln-api-queue":{type:"marker",description:"Mounts offline API synchronization queue backed by IndexedDB"},"data-ln-api-queue-online":{effect:a,type:"enum",values:["true","false"],fallback:"auto",description:"Network connectivity override (true/false, or auto-detect from navigator.onLine)"}};function l(){try{return crypto.randomUUID()}catch{return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,s=>{const f=Math.random()*16|0;return(s==="x"?f:f&3|8).toString(16)})}}const c=new ve({indexedDB:window.indexedDB,IDBKeyRange:window.IDBKeyRange,uuid:l});function d(n){this.dom=n,n[t]=this;const s=n.closest("[data-ln-data-coordinator]");this.scope=n.id||(s?s.id:null)||"default",this._paused=!1,this._timers=new Map,this._workerId=l(),this._drainPromise=null,this._onlineHandler=()=>this._drain(),this._bindEvents(),window.addEventListener("online",this._onlineHandler);const f=this;return c.open().then(p=>p?c.getPaused(f.scope):(console.warn("[ln-api-queue] IndexedDB not available — queue disabled"),!1)).then(p=>{if(f._paused=!!p,f._paused){const m=typeof p=="string"?p:"auth";w(f.dom,"ln-api-queue:paused",{reason:m,restored:!0})}return f._emitPendingCount()}).then(()=>f._drain()).catch(p=>{console.error("[ln-api-queue] Initialization failed:",p),w(f.dom,"ln-api-queue:error",{operation:"initialize",error:p})}),this}d.prototype._isOnline=function(){const n=this.dom.getAttribute("data-ln-api-queue-online");return n==="true"?!0:n==="false"?!1:navigator.onLine},d.prototype._emitPendingCount=function(){const n=this;return c.allForScope(n.scope).then(s=>(w(n.dom,"ln-api-queue:pending-count",{count:s.length,scope:n.scope}),s.length===0&&w(n.dom,"ln-api-queue:drained",{scope:n.scope}),s))},d.prototype._clearTimer=function(n){const s=this._timers.get(n);s&&(clearTimeout(s),this._timers.delete(n))},d.prototype._scheduleTimer=function(n,s){const f=Math.max(0,s),p=this._timers.get(n);p&&clearTimeout(p);const m=this,h=setTimeout(()=>{m._timers.delete(n),m._drain()},f);this._timers.set(n,h)},d.prototype._drain=function(){const n=this;return n._paused||!n._isOnline()?Promise.resolve():(n._drainPromise||(n._drainPromise=c.claimReady(n.scope,n._workerId,u).then(s=>{for(const f of s.wakeups)n._scheduleTimer(f.chainKey,f.at-Date.now());for(const f of s.entries)n._clearTimer(f.chainKey),w(n.dom,"ln-api-queue:send",{entryId:f.entryId,chainKey:f.chainKey,op:f.op,targetId:f.targetId,payload:f.payload,expectedVersion:f.expectedVersion,idempotencyKey:f.entryId,meta:f.meta})}).catch(s=>{console.error("[ln-api-queue] Drain failed:",s),w(n.dom,"ln-api-queue:error",{operation:"drain",error:s})}).finally(()=>{n._drainPromise=null})),n._drainPromise)},d.prototype._onEnqueue=function(n){const s=this;return c.enqueue(s.scope,n.detail||{}).then(f=>{if(f)return s._emitPendingCount().then(p=>(w(s.dom,"ln-api-queue:enqueued",{entryId:f.entryId,chainKey:f.chainKey,count:p.length}),s._drain()))}).catch(f=>{w(s.dom,"ln-api-queue:error",{operation:"enqueue",error:f})})},d.prototype._onAck=function(n){const s=this,f=n.detail||{};return c.ack(s.scope,f.entryId).then(()=>s._emitPendingCount()).then(()=>s._drain()).catch(p=>{w(s.dom,"ln-api-queue:error",{operation:"ack",entryId:f.entryId,error:p})})},d.prototype._onNack=function(n){const s=this,f=n.detail||{};return c.nack(s.scope,f.entryId,f.reason,{maxAttempts:o,backoff:r}).then(p=>{if(p)return p.status==="failed"?w(s.dom,"ln-api-queue:failed",{entryId:p.entry.entryId,chainKey:p.entry.chainKey,attempts:p.entry.attempts}):p.status==="retry"?s._scheduleTimer(p.entry.chainKey,p.delay):p.status==="auth"&&(s._paused=!0,w(s.dom,"ln-api-queue:paused",{reason:"auth"}),w(s.dom,"ln-api-queue:auth-required",{entryId:p.entry.entryId,chainKey:p.entry.chainKey})),s._emitPendingCount().then(()=>{if(p.status==="dropped")return s._drain()})}).catch(p=>{w(s.dom,"ln-api-queue:error",{operation:"nack",entryId:f.entryId,error:p})})},d.prototype._onRemap=function(n){const s=this,f=n.detail||{};return c.remap(s.scope,f.oldKey,f.newId).catch(p=>{w(s.dom,"ln-api-queue:error",{operation:"remap",error:p})})},d.prototype._onResolveCreate=function(n){const s=this,f=n.detail||{};return c.resolveCreate(s.scope,f.entryId,f.oldKey,f.newId).then(()=>s._emitPendingCount()).then(()=>s._drain()).catch(p=>{w(s.dom,"ln-api-queue:error",{operation:"resolve-create",entryId:f.entryId,error:p})})},d.prototype._onResume=function(){const n=this;return c.setPaused(n.scope,!1).then(()=>(n._paused=!1,w(n.dom,"ln-api-queue:resumed",{}),n._drain())).catch(s=>{w(n.dom,"ln-api-queue:error",{operation:"resume",error:s})})},d.prototype._onPause=function(){const n=this;return c.setPaused(n.scope,"manual").then(()=>{n._paused=!0,w(n.dom,"ln-api-queue:paused",{reason:"manual"})}).catch(s=>{w(n.dom,"ln-api-queue:error",{operation:"pause",error:s})})},d.prototype._onDrain=function(){const n=this;return c.resetFailed(n.scope).then(()=>{const s=n._drainPromise;return s?s.then(()=>n._drain()):n._drain()}).catch(s=>{w(n.dom,"ln-api-queue:error",{operation:"manual-drain",error:s})})},d.prototype._onClear=function(){const n=this;return n._timers.forEach(s=>clearTimeout(s)),n._timers.clear(),c.clear(n.scope).then(()=>{n._paused=!1,w(n.dom,"ln-api-queue:pending-count",{count:0,scope:n.scope}),w(n.dom,"ln-api-queue:drained",{scope:n.scope})}).catch(s=>{w(n.dom,"ln-api-queue:error",{operation:"clear",error:s})})},d.prototype._bindEvents=function(){const n=this;n._handlers={enqueue:s=>n._onEnqueue(s),ack:s=>n._onAck(s),nack:s=>n._onNack(s),remap:s=>n._onRemap(s),resolveCreate:s=>n._onResolveCreate(s),resume:()=>n._onResume(),pause:()=>n._onPause(),drain:()=>n._onDrain(),clear:()=>n._onClear()},n.dom.addEventListener("ln-api-queue:request-enqueue",n._handlers.enqueue),n.dom.addEventListener("ln-api-queue:ack",n._handlers.ack),n.dom.addEventListener("ln-api-queue:nack",n._handlers.nack),n.dom.addEventListener("ln-api-queue:request-remap",n._handlers.remap),n.dom.addEventListener("ln-api-queue:resolve-create",n._handlers.resolveCreate),n.dom.addEventListener("ln-api-queue:request-resume",n._handlers.resume),n.dom.addEventListener("ln-api-queue:request-pause",n._handlers.pause),n.dom.addEventListener("ln-api-queue:request-drain",n._handlers.drain),n.dom.addEventListener("ln-api-queue:request-clear",n._handlers.clear)},d.prototype.destroy=function(){if(!this.dom[t])return;const n=this;n.dom.removeEventListener("ln-api-queue:request-enqueue",n._handlers.enqueue),n.dom.removeEventListener("ln-api-queue:ack",n._handlers.ack),n.dom.removeEventListener("ln-api-queue:nack",n._handlers.nack),n.dom.removeEventListener("ln-api-queue:request-remap",n._handlers.remap),n.dom.removeEventListener("ln-api-queue:resolve-create",n._handlers.resolveCreate),n.dom.removeEventListener("ln-api-queue:request-resume",n._handlers.resume),n.dom.removeEventListener("ln-api-queue:request-pause",n._handlers.pause),n.dom.removeEventListener("ln-api-queue:request-drain",n._handlers.drain),n.dom.removeEventListener("ln-api-queue:request-clear",n._handlers.clear),window.removeEventListener("online",n._onlineHandler),n._timers.forEach(s=>clearTimeout(s)),n._timers.clear(),delete n.dom[t]},de(e,t,d,"ln-api-queue",{attributes:i})})()})();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "This file is partly generated. The $comment, component, generator, and each attribute's direction, sources, type, values, fallback, and description keys are owned by the generator and synchronized from JS source code. All other keys are preserved and safe to hand-author. Regenerate with `npm run sync:ln-schemas`.",
|
|
3
|
+
"component": "ln-api-queue",
|
|
4
|
+
"generator": "scripts/sync-ln-schemas.mjs",
|
|
5
|
+
"attributes": {
|
|
6
|
+
"data-ln-api-queue": {
|
|
7
|
+
"direction": null,
|
|
8
|
+
"sources": [
|
|
9
|
+
"src/ln-api-queue.js"
|
|
10
|
+
],
|
|
11
|
+
"type": "marker",
|
|
12
|
+
"description": "Mounts offline API synchronization queue backed by IndexedDB"
|
|
13
|
+
},
|
|
14
|
+
"data-ln-api-queue-online": {
|
|
15
|
+
"direction": "author",
|
|
16
|
+
"sources": [
|
|
17
|
+
"src/ln-api-queue.js"
|
|
18
|
+
],
|
|
19
|
+
"type": "enum",
|
|
20
|
+
"values": [
|
|
21
|
+
"true",
|
|
22
|
+
"false"
|
|
23
|
+
],
|
|
24
|
+
"fallback": "auto",
|
|
25
|
+
"description": "Network connectivity override (true/false, or auto-detect from navigator.onLine)"
|
|
26
|
+
},
|
|
27
|
+
"data-ln-data-coordinator": {
|
|
28
|
+
"direction": "author",
|
|
29
|
+
"sources": [
|
|
30
|
+
"src/ln-api-queue.js"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|