@storecraft/database-sql-base 1.0.0 → 1.0.2

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.
Files changed (39) hide show
  1. package/README.md +30 -12
  2. package/index.js +172 -1
  3. package/{tsconfig.json → jsconfig.json} +1 -5
  4. package/migrate.js +25 -19
  5. package/migrations.mysql/00000_init_tables.js +6 -5
  6. package/migrations.postgres/00000_init_tables.js +15 -14
  7. package/migrations.shared/00001_seed_email_templates copy.js +262 -0
  8. package/migrations.shared/00001_seed_email_templates.js +5 -238
  9. package/migrations.sqlite/00000_init_tables.js +12 -12
  10. package/package.json +2 -4
  11. package/src/con.auth_users.js +5 -2
  12. package/src/con.collections.js +2 -2
  13. package/src/con.customers.js +2 -2
  14. package/src/con.discounts.js +3 -3
  15. package/src/con.discounts.utils.js +11 -11
  16. package/src/con.helpers.json.js +3 -3
  17. package/src/con.images.js +5 -5
  18. package/src/con.notifications.js +2 -2
  19. package/src/con.orders.js +19 -4
  20. package/src/con.posts.js +2 -2
  21. package/src/con.products.js +5 -5
  22. package/src/con.search.js +7 -7
  23. package/src/con.shared.experiment.js +723 -0
  24. package/src/con.shared.js +55 -21
  25. package/src/con.shipping.js +2 -2
  26. package/src/con.storefronts.js +2 -2
  27. package/src/con.tags.js +2 -2
  28. package/src/con.templates.js +22 -7
  29. package/src/utils.query.js +6 -6
  30. package/tests/runner.mssql-local.test.js +10 -6
  31. package/tests/runner.mysql-local.test.js +16 -63
  32. package/tests/runner.postgres-local.test.js +17 -62
  33. package/tests/runner.sqlite-local.test.js +15 -64
  34. package/tests/sandbox.test.js +15 -13
  35. package/types.public.d.ts +12 -4
  36. package/types.sql.tables.d.ts +4 -2
  37. package/driver.js +0 -190
  38. package/tests/query.cursor.test.js +0 -389
  39. package/tests/query.vql.test.js +0 -71
@@ -1,5 +1,6 @@
1
1
  import { Kysely } from 'kysely'
2
2
  import { upsert } from '../src/con.templates.js'
3
+ import { templates } from '@storecraft/core/assets/seed-templates.js';
3
4
 
4
5
  /**
5
6
  * @typedef {import('../types.sql.tables.js').Database} Database
@@ -11,8 +12,10 @@ import { upsert } from '../src/con.templates.js'
11
12
  */
12
13
  export async function up(db) {
13
14
 
14
- for (const template of templates) {
15
- const result = await upsert(db)(template);
15
+ for (const template of templates.slice(0)) {
16
+ const result = await upsert(db)(template, template.search);
17
+ if(!result)
18
+ throw new Error('Failed to write a template object')
16
19
  }
17
20
  }
18
21
 
@@ -22,239 +25,3 @@ export async function up(db) {
22
25
  */
23
26
  export async function down(db) {
24
27
  }
25
-
26
-
27
- const templates = [
28
- {
29
- "title": "Welcome Customer",
30
- "template_html": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns=\"http://www.w3.org/1999/xhtml\" style=\"color-scheme: light dark; supported-color-schemes: light dark;\">\n <head>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <meta name=\"x-apple-disable-message-reformatting\" />\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n <meta name=\"color-scheme\" content=\"light dark\" />\n <meta name=\"supported-color-schemes\" content=\"light dark\" />\n <title></title>\n <style type=\"text/css\" rel=\"stylesheet\" media=\"all\">\n /* Base ------------------------------ */\n \n @import url(\"https://fonts.googleapis.com/css?family=Nunito+Sans:400,700&amp;display=swap\");\n body {\n width: 100% !important;\n height: 100%;\n margin: 0;\n -webkit-text-size-adjust: none;\n }\n \n a {\n color: #3869D4;\n }\n \n a img {\n border: none;\n }\n \n td {\n word-break: break-word;\n }\n \n .preheader {\n display: none !important;\n visibility: hidden;\n mso-hide: all;\n font-size: 1px;\n line-height: 1px;\n max-height: 0;\n max-width: 0;\n opacity: 0;\n overflow: hidden;\n }\n /* Type ------------------------------ */\n \n body,\n td,\n th {\n font-family: \"Nunito Sans\", Helvetica, Arial, sans-serif;\n }\n \n h1 {\n margin-top: 0;\n color: #333333;\n font-size: 22px;\n font-weight: bold;\n text-align: left;\n }\n \n h2 {\n margin-top: 0;\n color: #333333;\n font-size: 16px;\n font-weight: bold;\n text-align: left;\n }\n \n h3 {\n margin-top: 0;\n color: #333333;\n font-size: 14px;\n font-weight: bold;\n text-align: left;\n }\n \n td,\n th {\n font-size: 16px;\n }\n \n p,\n ul,\n ol,\n blockquote {\n margin: .4em 0 1.1875em;\n font-size: 16px;\n line-height: 1.625;\n }\n \n p.sub {\n font-size: 13px;\n }\n /* Utilities ------------------------------ */\n \n .align-right {\n text-align: right;\n }\n \n .align-left {\n text-align: left;\n }\n \n .align-center {\n text-align: center;\n }\n \n .u-margin-bottom-none {\n margin-bottom: 0;\n }\n /* Buttons ------------------------------ */\n \n .button {\n background-color: #3869D4;\n border-top: 10px solid #3869D4;\n border-right: 18px solid #3869D4;\n border-bottom: 10px solid #3869D4;\n border-left: 18px solid #3869D4;\n display: inline-block;\n color: #FFF;\n text-decoration: none;\n border-radius: 3px;\n box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16);\n -webkit-text-size-adjust: none;\n box-sizing: border-box;\n }\n \n .button--green {\n background-color: #22BC66;\n border-top: 10px solid #22BC66;\n border-right: 18px solid #22BC66;\n border-bottom: 10px solid #22BC66;\n border-left: 18px solid #22BC66;\n }\n \n .button--red {\n background-color: #FF6136;\n border-top: 10px solid #FF6136;\n border-right: 18px solid #FF6136;\n border-bottom: 10px solid #FF6136;\n border-left: 18px solid #FF6136;\n }\n \n @media only screen and (max-width: 500px) {\n .button {\n width: 100% !important;\n text-align: center !important;\n }\n }\n /* Attribute list ------------------------------ */\n \n .attributes {\n margin: 0 0 21px;\n }\n \n .attributes_content {\n background-color: #F4F4F7;\n padding: 16px;\n }\n \n .attributes_item {\n padding: 0;\n }\n /* Related Items ------------------------------ */\n \n .related {\n width: 100%;\n margin: 0;\n padding: 25px 0 0 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n }\n \n .related_item {\n padding: 10px 0;\n color: #CBCCCF;\n font-size: 15px;\n line-height: 18px;\n }\n \n .related_item-title {\n display: block;\n margin: .5em 0 0;\n }\n \n .related_item-thumb {\n display: block;\n padding-bottom: 10px;\n }\n \n .related_heading {\n border-top: 1px solid #CBCCCF;\n text-align: center;\n padding: 25px 0 10px;\n }\n /* Discount Code ------------------------------ */\n \n .discount {\n width: 100%;\n margin: 0;\n padding: 24px;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n background-color: #F4F4F7;\n border: 2px dashed #CBCCCF;\n }\n \n .discount_heading {\n text-align: center;\n }\n \n .discount_body {\n text-align: center;\n font-size: 15px;\n }\n /* Social Icons ------------------------------ */\n \n .social {\n width: auto;\n }\n \n .social td {\n padding: 0;\n width: auto;\n }\n \n .social_icon {\n height: 20px;\n margin: 0 8px 10px 8px;\n padding: 0;\n }\n /* Data table ------------------------------ */\n \n .purchase {\n width: 100%;\n margin: 0;\n padding: 35px 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n }\n \n .purchase_content {\n width: 100%;\n margin: 0;\n padding: 25px 0 0 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n }\n \n .purchase_item {\n padding: 10px 0;\n color: #51545E;\n font-size: 15px;\n line-height: 18px;\n }\n \n .purchase_heading {\n padding-bottom: 8px;\n border-bottom: 1px solid #EAEAEC;\n }\n \n .purchase_heading p {\n margin: 0;\n color: #85878E;\n font-size: 12px;\n }\n \n .purchase_footer {\n padding-top: 15px;\n border-top: 1px solid #EAEAEC;\n }\n \n .purchase_total {\n margin: 0;\n text-align: right;\n font-weight: bold;\n color: #333333;\n }\n \n .purchase_total--label {\n padding: 0 15px 0 0;\n }\n \n body {\n background-color: #F4F4F7;\n color: #51545E;\n }\n \n p {\n color: #51545E;\n }\n \n p.sub {\n color: #6B6E76;\n }\n \n .email-wrapper {\n width: 100%;\n margin: 0;\n padding: 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n background-color: #F4F4F7;\n }\n \n .email-content {\n width: 100%;\n margin: 0;\n padding: 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n }\n /* Masthead ----------------------- */\n \n .email-masthead {\n padding: 25px 0;\n text-align: center;\n }\n \n .email-masthead_logo {\n width: 94px;\n }\n \n .email-masthead_name {\n font-size: 16px;\n font-weight: bold;\n color: #A8AAAF;\n text-decoration: none;\n text-shadow: 0 1px 0 white;\n }\n /* Body ------------------------------ */\n \n .email-body {\n width: 100%;\n margin: 0;\n padding: 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n background-color: #FFFFFF;\n }\n \n .email-body_inner {\n width: 570px;\n margin: 0 auto;\n padding: 0;\n -premailer-width: 570px;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n background-color: #FFFFFF;\n }\n \n .email-footer {\n width: 570px;\n margin: 0 auto;\n padding: 0;\n -premailer-width: 570px;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n text-align: center;\n }\n \n .email-footer p {\n color: #6B6E76;\n }\n \n .body-action {\n width: 100%;\n margin: 30px auto;\n padding: 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n text-align: center;\n }\n \n .body-sub {\n margin-top: 25px;\n padding-top: 25px;\n border-top: 1px solid #EAEAEC;\n }\n \n .content-cell {\n padding: 35px;\n }\n /*Media Queries ------------------------------ */\n \n @media only screen and (max-width: 600px) {\n .email-body_inner,\n .email-footer {\n width: 100% !important;\n }\n }\n \n @media (prefers-color-scheme: dark) {\n body,\n .email-body,\n .email-body_inner,\n .email-content,\n .email-wrapper,\n .email-masthead,\n .email-footer {\n background-color: #333333 !important;\n color: #FFF !important;\n }\n p,\n ul,\n ol,\n blockquote,\n h1,\n h2,\n h3,\n span,\n .purchase_item {\n color: #FFF !important;\n }\n .attributes_content,\n .discount {\n background-color: #222 !important;\n }\n .email-masthead_name {\n text-shadow: none !important;\n }\n }\n \n :root {\n color-scheme: light dark;\n supported-color-schemes: light dark;\n }\n </style>\n <!--[if mso]>\n <style type=\"text/css\">\n .f-fallback {\n font-family: Arial, sans-serif;\n }\n </style>\n <![endif]-->\n <style type=\"text/css\" rel=\"stylesheet\" media=\"all\">\n body {\n width: 100% !important;\n height: 100%;\n margin: 0;\n -webkit-text-size-adjust: none;\n }\n \n body {\n font-family: \"Nunito Sans\", Helvetica, Arial, sans-serif;\n }\n \n body {\n background-color: #F4F4F7;\n color: #51545E;\n }\n </style>\n </head>\n <body style=\"width: 100% !important; height: 100%; -webkit-text-size-adjust: none; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; background-color: #F4F4F7; color: #51545E; margin: 0;\" bgcolor=\"#F4F4F7\">\n <span class=\"preheader\" style=\"display: none !important; visibility: hidden; mso-hide: all; font-size: 1px; line-height: 1px; max-height: 0; max-width: 0; opacity: 0; overflow: hidden;\">Thanks for signing up with us. We’re thrilled to have you on board.</span>\n <table class=\"email-wrapper\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; background-color: #F4F4F7; margin: 0; padding: 0;\" bgcolor=\"#F4F4F7\">\n <tr>\n <td align=\"center\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px;\">\n <table class=\"email-content\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; margin: 0; padding: 0;\">\n <tr>\n <td class=\"email-masthead\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; text-align: center; padding: 25px 0;\" align=\"center\">\n <a href=\"{{info.general_store_website}}\" class=\"f-fallback email-masthead_name\" style=\"color: #A8AAAF; font-size: 16px; font-weight: bold; text-decoration: none; text-shadow: 0 1px 0 white;\">\n {{info.general_store_name}}\n </a>\n </td>\n </tr>\n <!-- Email Body -->\n <tr>\n <td class=\"email-body\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; background-color: #FFFFFF; margin: 0; padding: 0;\" bgcolor=\"#FFFFFF\">\n <table class=\"email-body_inner\" align=\"center\" width=\"570\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width: 570px; -premailer-width: 570px; -premailer-cellpadding: 0; -premailer-cellspacing: 0; background-color: #FFFFFF; margin: 0 auto; padding: 0;\" bgcolor=\"#FFFFFF\">\n <!-- Body content -->\n <tr>\n <td class=\"content-cell\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding: 35px;\">\n <div class=\"f-fallback\">\n <h1 style=\"margin-top: 0; color: #333333; font-size: 22px; font-weight: bold; text-align: left;\" align=\"left\">Welcome, {{customer.firstname}}!</h1>\n <p style=\"font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;\">Thanks for signing up with us. We’re thrilled to have you on board.</p>\n <!-- Action -->\n <table class=\"body-action\" align=\"center\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; text-align: center; margin: 30px auto; padding: 0;\">\n <tr>\n <td align=\"center\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px;\">\n <!-- Border based button\n https://litmus.com/blog/a-guide-to-bulletproof-buttons-in-email-design -->\n <table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" role=\"presentation\">\n <tr>\n <td align=\"center\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px;\">\n <a href=\"{{info.general_confirm_email_base_url}}/user={{customer.id}}\" class=\"f-fallback button\" target=\"_blank\" style=\"color: #FFF; background-color: #3869D4; display: inline-block; text-decoration: none; border-radius: 3px; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16); -webkit-text-size-adjust: none; box-sizing: border-box; border-color: #3869D4; border-style: solid; border-width: 10px 18px;\">Confirm your email</a>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n <p style=\"font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;\">For reference, here's your login information:</p>\n <table class=\"attributes\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"margin: 0 0 21px;\">\n <tr>\n <td class=\"attributes_content\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; background-color: #F4F4F7; padding: 16px;\" bgcolor=\"#F4F4F7\">\n <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\">\n <tr>\n <td class=\"attributes_item\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding: 0;\">\n <span class=\"f-fallback\">\n <strong>User ID:</strong> {{customer.id}}\n </span>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n <p style=\"font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;\">Need help, or have any questions ? Simply reply to this email, we'd love to help</p>\n <!-- Sub copy -->\n \n </div>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n <tr>\n <td style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px;\">\n <table class=\"email-footer\" align=\"center\" width=\"570\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width: 570px; -premailer-width: 570px; -premailer-cellpadding: 0; -premailer-cellspacing: 0; text-align: center; margin: 0 auto; padding: 0;\">\n <tr>\n <td class=\"content-cell\" align=\"center\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding: 35px;\">\n <p class=\"f-fallback sub align-center\" style=\"font-size: 13px; line-height: 1.625; text-align: center; color: #6B6E76; margin: .4em 0 1.1875em;\" align=\"center\">\n {{info.general_store_name}}\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n</html>",
31
- "template_text": "Thanks for signing up with us. \nWe’re thrilled to have you on board.\n\n******************\nWelcome, {{customer.firstname}}!\n******************\n\nThanks for signing up with us. We’re thrilled to \nhave you on board.\n\nConfirm your email here: \n{{ info.general_confirm_email_base_url }}/user={{customer.id}}\n\nFor reference, here's your login information:\n\nUser ID: {{customer.id}}\n\nNeed help, or have any questions ?\nSimply reply to this email, we'd love to help\n\n[{{info.general_store_name}}] ({{info.general_store_website}})\n",
32
- "reference_example_input": {
33
- "customer": {
34
- "email": "john@dow.com",
35
- "firstname": "John",
36
- "lastname": "Dow",
37
- "id": "cus_65f2ae6e8bf30e6cd0ca95fa"
38
- },
39
- "info": {
40
- "general_store_name": "Wush Wush Games",
41
- "general_store_website": "https://wush.games/",
42
- "general_store_description": "We sell retro video games",
43
- "general_confirm_email_base_url": "https://wush.games/confirm-email"
44
- }
45
- },
46
- "handle": "welcome-customer",
47
- "id": "template_664afed24eba71b9ee185be4",
48
- "created_at": "2024-05-20T07:42:10.436Z",
49
- "updated_at": "2024-05-20T09:39:46.492Z",
50
- "_relations": {
51
- "search": [
52
- "handle:welcome-customer",
53
- "welcome-customer",
54
- "id:template_664afed24eba71b9ee185be4",
55
- "template_664afed24eba71b9ee185be4",
56
- "664afed24eba71b9ee185be4",
57
- "welcome",
58
- "customer",
59
- "welcome customer"
60
- ]
61
- }
62
- },
63
- {
64
- "title": "Checkout Complete",
65
- "template_html": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns=\"http://www.w3.org/1999/xhtml\" style=\"color-scheme: light dark; supported-color-schemes: light dark;\">\n <head>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <meta name=\"x-apple-disable-message-reformatting\" />\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n <meta name=\"color-scheme\" content=\"light dark\" />\n <meta name=\"supported-color-schemes\" content=\"light dark\" />\n <title></title>\n <style type=\"text/css\" rel=\"stylesheet\" media=\"all\">\n /* Base ------------------------------ */\n \n @import url(\"https://fonts.googleapis.com/css?family=Nunito+Sans:400,700&amp;display=swap\");\n body {\n width: 100% !important;\n height: 100%;\n margin: 0;\n -webkit-text-size-adjust: none;\n }\n \n a {\n color: #3869D4;\n }\n \n a img {\n border: none;\n }\n \n td {\n word-break: break-word;\n }\n \n .preheader {\n display: none !important;\n visibility: hidden;\n mso-hide: all;\n font-size: 1px;\n line-height: 1px;\n max-height: 0;\n max-width: 0;\n opacity: 0;\n overflow: hidden;\n }\n /* Type ------------------------------ */\n \n body,\n td,\n th {\n font-family: \"Nunito Sans\", Helvetica, Arial, sans-serif;\n }\n \n h1 {\n margin-top: 0;\n color: #333333;\n font-size: 22px;\n font-weight: bold;\n text-align: left;\n }\n \n h2 {\n margin-top: 0;\n color: #333333;\n font-size: 16px;\n font-weight: bold;\n text-align: left;\n }\n \n h3 {\n margin-top: 0;\n color: #333333;\n font-size: 14px;\n font-weight: bold;\n text-align: left;\n }\n \n td,\n th {\n font-size: 16px;\n }\n \n p,\n ul,\n ol,\n blockquote {\n margin: .4em 0 1.1875em;\n font-size: 16px;\n line-height: 1.625;\n }\n \n p.sub {\n font-size: 13px;\n }\n /* Utilities ------------------------------ */\n \n .align-right {\n text-align: right;\n }\n \n .align-left {\n text-align: left;\n }\n \n .align-center {\n text-align: center;\n }\n \n .u-margin-bottom-none {\n margin-bottom: 0;\n }\n /* Buttons ------------------------------ */\n \n .button {\n background-color: #3869D4;\n border-top: 10px solid #3869D4;\n border-right: 18px solid #3869D4;\n border-bottom: 10px solid #3869D4;\n border-left: 18px solid #3869D4;\n display: inline-block;\n color: #FFF;\n text-decoration: none;\n border-radius: 3px;\n box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16);\n -webkit-text-size-adjust: none;\n box-sizing: border-box;\n }\n \n .button--green {\n background-color: #22BC66;\n border-top: 10px solid #22BC66;\n border-right: 18px solid #22BC66;\n border-bottom: 10px solid #22BC66;\n border-left: 18px solid #22BC66;\n }\n \n .button--red {\n background-color: #FF6136;\n border-top: 10px solid #FF6136;\n border-right: 18px solid #FF6136;\n border-bottom: 10px solid #FF6136;\n border-left: 18px solid #FF6136;\n }\n \n @media only screen and (max-width: 500px) {\n .button {\n width: 100% !important;\n text-align: center !important;\n }\n }\n /* Attribute list ------------------------------ */\n \n .attributes {\n margin: 0 0 21px;\n }\n \n .attributes_content {\n background-color: #F4F4F7;\n padding: 16px;\n }\n \n .attributes_item {\n padding: 0;\n }\n /* Related Items ------------------------------ */\n \n .related {\n width: 100%;\n margin: 0;\n padding: 25px 0 0 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n }\n \n .related_item {\n padding: 10px 0;\n color: #CBCCCF;\n font-size: 15px;\n line-height: 18px;\n }\n \n .related_item-title {\n display: block;\n margin: .5em 0 0;\n }\n \n .related_item-thumb {\n display: block;\n padding-bottom: 10px;\n }\n \n .related_heading {\n border-top: 1px solid #CBCCCF;\n text-align: center;\n padding: 25px 0 10px;\n }\n /* Discount Code ------------------------------ */\n \n .discount {\n width: 100%;\n margin: 0;\n padding: 24px;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n background-color: #F4F4F7;\n border: 2px dashed #CBCCCF;\n }\n \n .discount_heading {\n text-align: center;\n }\n \n .discount_body {\n text-align: center;\n font-size: 15px;\n }\n /* Social Icons ------------------------------ */\n \n .social {\n width: auto;\n }\n \n .social td {\n padding: 0;\n width: auto;\n }\n \n .social_icon {\n height: 20px;\n margin: 0 8px 10px 8px;\n padding: 0;\n }\n /* Data table ------------------------------ */\n \n .purchase {\n width: 100%;\n margin: 0;\n padding: 35px 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n }\n \n .purchase_content {\n width: 100%;\n margin: 0;\n padding: 25px 0 0 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n }\n \n .purchase_item {\n padding: 10px 0;\n color: #51545E;\n font-size: 15px;\n line-height: 18px;\n }\n \n .purchase_heading {\n padding-bottom: 8px;\n border-bottom: 1px solid #EAEAEC;\n }\n \n .purchase_heading p {\n margin: 0;\n color: #85878E;\n font-size: 12px;\n }\n \n .purchase_footer {\n padding-top: 15px;\n border-top: 1px solid #EAEAEC;\n }\n \n .purchase_total {\n margin: 0;\n text-align: right;\n font-weight: bold;\n color: #333333;\n }\n \n .purchase_total--label {\n padding: 0 15px 0 0;\n }\n \n body {\n background-color: #F4F4F7;\n color: #51545E;\n }\n \n p {\n color: #51545E;\n }\n \n p.sub {\n color: #6B6E76;\n }\n \n .email-wrapper {\n width: 100%;\n margin: 0;\n padding: 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n background-color: #F4F4F7;\n }\n \n .email-content {\n width: 100%;\n margin: 0;\n padding: 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n }\n /* Masthead ----------------------- */\n \n .email-masthead {\n padding: 25px 0;\n text-align: center;\n }\n \n .email-masthead_logo {\n width: 94px;\n }\n \n .email-masthead_name {\n font-size: 16px;\n font-weight: bold;\n color: #A8AAAF;\n text-decoration: none;\n text-shadow: 0 1px 0 white;\n }\n /* Body ------------------------------ */\n \n .email-body {\n width: 100%;\n margin: 0;\n padding: 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n background-color: #FFFFFF;\n }\n \n .email-body_inner {\n width: 570px;\n margin: 0 auto;\n padding: 0;\n -premailer-width: 570px;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n background-color: #FFFFFF;\n }\n \n .email-footer {\n width: 570px;\n margin: 0 auto;\n padding: 0;\n -premailer-width: 570px;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n text-align: center;\n }\n \n .email-footer p {\n color: #6B6E76;\n }\n \n .body-action {\n width: 100%;\n margin: 30px auto;\n padding: 0;\n -premailer-width: 100%;\n -premailer-cellpadding: 0;\n -premailer-cellspacing: 0;\n text-align: center;\n }\n \n .body-sub {\n margin-top: 25px;\n padding-top: 25px;\n border-top: 1px solid #EAEAEC;\n }\n \n .content-cell {\n padding: 35px;\n }\n /*Media Queries ------------------------------ */\n \n @media only screen and (max-width: 600px) {\n .email-body_inner,\n .email-footer {\n width: 100% !important;\n }\n }\n \n @media (prefers-color-scheme: dark) {\n body,\n .email-body,\n .email-body_inner,\n .email-content,\n .email-wrapper,\n .email-masthead,\n .email-footer {\n background-color: #333333 !important;\n color: #FFF !important;\n }\n p,\n ul,\n ol,\n blockquote,\n h1,\n h2,\n h3,\n span,\n .purchase_item {\n color: #FFF !important;\n }\n .attributes_content,\n .discount {\n background-color: #222 !important;\n }\n .email-masthead_name {\n text-shadow: none !important;\n }\n }\n \n :root {\n color-scheme: light dark;\n supported-color-schemes: light dark;\n }\n </style>\n <!--[if mso]>\n <style type=\"text/css\">\n .f-fallback {\n font-family: Arial, sans-serif;\n }\n </style>\n <![endif]-->\n <style type=\"text/css\" rel=\"stylesheet\" media=\"all\">\n body {\n width: 100% !important;\n height: 100%;\n margin: 0;\n -webkit-text-size-adjust: none;\n }\n \n body {\n font-family: \"Nunito Sans\", Helvetica, Arial, sans-serif;\n }\n \n body {\n background-color: #F4F4F7;\n color: #51545E;\n }\n </style>\n </head>\n <body style=\"width: 100% !important; height: 100%; -webkit-text-size-adjust: none; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; background-color: #F4F4F7; color: #51545E; margin: 0;\" bgcolor=\"#F4F4F7\">\n <table class=\"email-wrapper\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; background-color: #F4F4F7; margin: 0; padding: 0;\" bgcolor=\"#F4F4F7\">\n <tr>\n <td align=\"center\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px;\">\n <table class=\"email-content\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; margin: 0; padding: 0;\">\n <tr>\n <td class=\"email-masthead\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; text-align: center; padding: 25px 0;\" align=\"center\">\n <a href=\"{{info.general_store_website}}\" class=\"f-fallback email-masthead_name\" style=\"color: #A8AAAF; font-size: 16px; font-weight: bold; text-decoration: none; text-shadow: 0 1px 0 white;\">\n {{info.general_store_name}}\n </a>\n </td>\n </tr>\n <!-- Email Body -->\n <tr>\n <td class=\"email-body\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; background-color: #FFFFFF; margin: 0; padding: 0;\" bgcolor=\"#FFFFFF\">\n <table class=\"email-body_inner\" align=\"center\" width=\"570\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width: 570px; -premailer-width: 570px; -premailer-cellpadding: 0; -premailer-cellspacing: 0; background-color: #FFFFFF; margin: 0 auto; padding: 0;\" bgcolor=\"#FFFFFF\">\n <!-- Body content -->\n <tr>\n <td class=\"content-cell\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding: 35px;\">\n <div class=\"f-fallback\">\n <h1 style=\"margin-top: 0; color: #333333; font-size: 22px; font-weight: bold; text-align: left;\" align=\"left\">Hi {{order.contact.firstname}},</h1>\n <p style=\"font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;\">Thank you for your purchase. This email is the receipt for your purchase.</p>\n <table class=\"purchase\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; margin: 0; padding: 0px 0;\">\n <tr>\n <td style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px;\">\n <h3 style=\"margin-top: 0; color: #333333; font-size: 14px; font-weight: bold; text-align: left;\" align=\"left\">{{order.id}}</h3></td>\n \n </tr>\n <tr>\n <td colspan=\"2\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px;\">\n <table class=\"purchase_content\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; margin: 0; padding: 25px 0 0;\">\n <tr>\n <th class=\"purchase_heading\" align=\"left\" style=\"font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding-bottom: 8px; border-bottom-width: 1px; border-bottom-color: #EAEAEC; border-bottom-style: solid;\">\n <p class=\"f-fallback\" style=\"font-size: 12px; line-height: 1.625; color: #85878E; margin: 0;\">Description</p>\n </th>\n <th class=\"purchase_heading\" align=\"right\" style=\"font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding-bottom: 8px; border-bottom-width: 1px; border-bottom-color: #EAEAEC; border-bottom-style: solid;\">\n <p class=\"f-fallback\" style=\"font-size: 12px; line-height: 1.625; color: #85878E; margin: 0;\">Amount</p>\n </th>\n </tr>\n {{#each order.line_items}}\n <tr>\n <td width=\"80%\" class=\"purchase_item\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 15px; color: #51545E; line-height: 18px; padding: 10px 0;\"><span class=\"f-fallback\">{{data.title}}</span></td>\n <td class=\"align-right\" width=\"20%\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; text-align: right;\" align=\"right\"><span class=\"f-fallback\">{{qty}}</span></td>\n </tr>\n {{/each}}\n <tr>\n <td width=\"80%\" class=\"purchase_footer\" valign=\"middle\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding-top: 15px; border-top-width: 1px; border-top-color: #EAEAEC; border-top-style: solid;\">\n <p class=\"f-fallback purchase_total purchase_total--label\" style=\"font-size: 16px; line-height: 1.625; text-align: right; font-weight: bold; color: #333333; margin: 0; padding: 0 15px 0 0;\" align=\"right\">Shipping</p>\n </td>\n <td width=\"20%\" class=\"purchase_footer\" valign=\"middle\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding-top: 15px; border-top-width: 1px; border-top-color: #EAEAEC; border-top-style: solid;\">\n <p class=\"f-fallback purchase_total\" style=\"font-size: 16px; line-height: 1.625; text-align: right; font-weight: bold; color: #333333; margin: 0;\" align=\"right\">{{order.shipping_method.price}}</p>\n </td>\n </tr>\n <tr>\n <td width=\"80%\" class=\"purchase_footer\" valign=\"middle\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding-top: 15px; border-top-width: 1px; border-top-color: #EAEAEC; border-top-style: solid;\">\n <p class=\"f-fallback purchase_total purchase_total--label\" style=\"font-size: 16px; line-height: 1.625; text-align: right; font-weight: bold; color: #333333; margin: 0; padding: 0 15px 0 0;\" align=\"right\">Subtotal Discounts</p>\n </td>\n <td width=\"20%\" class=\"purchase_footer\" valign=\"middle\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding-top: 15px; border-top-width: 1px; border-top-color: #EAEAEC; border-top-style: solid;\">\n <p class=\"f-fallback purchase_total\" style=\"font-size: 16px; line-height: 1.625; text-align: right; font-weight: bold; color: #333333; margin: 0;\" align=\"right\">-{{order.pricing.subtotal_discount}}</p>\n </td>\n </tr>\n <tr>\n <td width=\"80%\" class=\"purchase_footer\" valign=\"middle\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding-top: 15px; border-top-width: 1px; border-top-color: #EAEAEC; border-top-style: solid;\">\n <p class=\"f-fallback purchase_total purchase_total--label\" style=\"font-size: 16px; line-height: 1.625; text-align: right; font-weight: bold; color: #333333; margin: 0; padding: 0 15px 0 0;\" align=\"right\">Total</p>\n </td>\n <td width=\"20%\" class=\"purchase_footer\" valign=\"middle\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding-top: 15px; border-top-width: 1px; border-top-color: #EAEAEC; border-top-style: solid;\">\n <p class=\"f-fallback purchase_total\" style=\"font-size: 16px; line-height: 1.625; text-align: right; font-weight: bold; color: #333333; margin: 0;\" align=\"right\">{{order.pricing.total}}</p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n <p style=\"font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;\">If you have any questions about this receipt, simply reply to this email or reach out to our <a href=\"{{info.general_store_support_email}}\" style=\"color: #3869D4;\">support team</a> for help.</p>\n <p style=\"font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;\">Cheers,\n <br />The {{info.general_store_name}} team</p>\n <!-- Action -->\n <table class=\"body-action\" align=\"center\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; text-align: center; margin: 30px auto; padding: 0;\">\n <tr>\n <td align=\"center\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px;\">\n <!-- Border based button\n https://litmus.com/blog/a-guide-to-bulletproof-buttons-in-email-design -->\n <table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" role=\"presentation\">\n <tr>\n <td align=\"center\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px;\">\n <a href=\"{{action_url}}\" class=\"f-fallback button button--blue\" target=\"_blank\" style=\"color: #FFF; background-color: #3869D4; display: inline-block; text-decoration: none; border-radius: 3px; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16); -webkit-text-size-adjust: none; box-sizing: border-box; border-color: #3869D4; border-style: solid; border-width: 10px 18px;\">Download as PDF</a>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n <!-- Sub copy -->\n \n </div>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n <tr>\n <td style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px;\">\n <table class=\"email-footer\" align=\"center\" width=\"570\" cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" style=\"width: 570px; -premailer-width: 570px; -premailer-cellpadding: 0; -premailer-cellspacing: 0; text-align: center; margin: 0 auto; padding: 0;\">\n <tr>\n <td class=\"content-cell\" align=\"center\" style=\"word-break: break-word; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; font-size: 16px; padding: 35px;\">\n <p class=\"f-fallback sub align-center\" style=\"font-size: 13px; line-height: 1.625; text-align: center; color: #6B6E76; margin: .4em 0 1.1875em;\" align=\"center\">\n {{info.general_store_name}} \n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n</html>",
66
- "template_text": "[{{info.general_store_name}}] ({{info.general_store_website}})\n\n************\nHi {{order.contact.firstname}},\n************\n\nThank you for your purchase !!!\n\n\nOrder ID is {{order.id}}\n--------------\n\n{{date}}\n--------\n\nDescription\n\nItems\n{{#each order.line_items}}\n- {{data.title}} x {{qty}}\n{{/each}}\n\nShipping \n{{order.shipping_method.title}}, {{order.shipping_method.price}}\n\nDiscounts\n{{#each order.pricing.evo}}\n- {{discount.title}} - {{total_discount}}\n{{/each}}\n\nTotal\n{{order.pricing.total}}\n\nIf you have any questions about this receipt, simply reply to this \nemail or reach out to our support team ( {{ info.general_store_support_email }} ) for help.\n\nCheers,\nThe {{info.general_store_name}} team\n\n\n{{info.general_store_name}}\n{{info.general_store_website}}",
67
- "reference_example_input": {
68
- "order": {
69
- "contact": {
70
- "email": "john@doe.com",
71
- "firstname": "John",
72
- "phone_number": "000-000-000",
73
- "customer_id": "cus_65f2ae6e8bf30e6cd0ca95fa"
74
- },
75
- "address": {},
76
- "status": {
77
- "checkout": {
78
- "id": 0,
79
- "name2": "created",
80
- "name": "Created"
81
- },
82
- "payment": {
83
- "id": 1,
84
- "name": "Authorized",
85
- "name2": "authorized"
86
- },
87
- "fulfillment": {
88
- "id": 0,
89
- "name2": "draft",
90
- "name": "Draft"
91
- }
92
- },
93
- "pricing": {
94
- "evo": [
95
- {
96
- "quantity_discounted": 0,
97
- "quantity_undiscounted": 11,
98
- "subtotal": 1100,
99
- "total": 1150
100
- },
101
- {
102
- "quantity_discounted": 2,
103
- "total_discount": 100,
104
- "quantity_undiscounted": 9,
105
- "discount": {
106
- "active": true,
107
- "handle": "discount-bundle-50-off-robot-arms-and-legs-not-recursive",
108
- "title": "50% OFF Bundle: robot arms and legs (not recursive)",
109
- "priority": 0,
110
- "application": {
111
- "id": 0,
112
- "name": "Automatic",
113
- "name2": "automatic"
114
- },
115
- "info": {
116
- "details": {
117
- "meta": {
118
- "id": 4,
119
- "type": "bundle",
120
- "name": "Bundle Discount"
121
- },
122
- "extra": {
123
- "fixed": 0,
124
- "percent": 50,
125
- "recursive": false
126
- }
127
- },
128
- "filters": [
129
- {
130
- "meta": {
131
- "id": 4,
132
- "type": "product",
133
- "op": "p-in-tags",
134
- "name": "Product has Tag"
135
- },
136
- "value": [
137
- "robot_arm"
138
- ]
139
- },
140
- {
141
- "meta": {
142
- "id": 4,
143
- "type": "product",
144
- "op": "p-in-tags",
145
- "name": "Product has Tag"
146
- },
147
- "value": [
148
- "robot_leg"
149
- ]
150
- }
151
- ]
152
- }
153
- },
154
- "discount_code": "discount-bundle-50-off-robot-arms-and-legs-not-recursive",
155
- "subtotal": 1000,
156
- "total": 1050
157
- }
158
- ],
159
- "shipping_method": {
160
- "title": "",
161
- "handle": "",
162
- "price": 50
163
- },
164
- "subtotal_discount": 100,
165
- "subtotal_undiscounted": 1100,
166
- "subtotal": 1000,
167
- "total": 1050,
168
- "quantity_total": 11,
169
- "quantity_discounted": 2,
170
- "errors": []
171
- },
172
- "line_items": [
173
- {
174
- "id": "robot-leg-white",
175
- "qty": 3,
176
- "data": {
177
- "tags": [
178
- "robot_leg"
179
- ],
180
- "qty": 100,
181
- "active": true,
182
- "title": "Robot Leg White",
183
- "price": 100
184
- }
185
- },
186
- {
187
- "id": "battery",
188
- "qty": 5,
189
- "data": {
190
- "tags": [
191
- "would-not-be-discounted"
192
- ],
193
- "qty": 100,
194
- "active": true,
195
- "title": "Battery",
196
- "price": 100
197
- }
198
- },
199
- {
200
- "id": "robot-arm-red",
201
- "qty": 2,
202
- "data": {
203
- "tags": [
204
- "robot_arm"
205
- ],
206
- "qty": 100,
207
- "active": true,
208
- "title": "Robot Arm Red",
209
- "price": 100
210
- }
211
- },
212
- {
213
- "id": "robot-arm-green",
214
- "qty": 1,
215
- "data": {
216
- "tags": [
217
- "robot_arm"
218
- ],
219
- "qty": 100,
220
- "active": true,
221
- "title": "Robot Arm Green",
222
- "price": 100
223
- }
224
- }
225
- ],
226
- "shipping_method": {
227
- "handle": "ship-fast",
228
- "title": "ship fast",
229
- "price": 50
230
- },
231
- "id": "order_65d774c6445e4581b9e34c11",
232
- "created_at": "2024-02-22T16:22:30.095Z",
233
- "updated_at": "2024-02-22T16:22:30.095Z"
234
- },
235
- "info": {
236
- "general_store_name": "Wush Wush Games",
237
- "general_store_website": "https://wush.games/",
238
- "general_store_description": "We sell retro video games",
239
- "general_confirm_email_base_url": "https://wush.games/confirm-email",
240
- "general_store_support_email": "support@wush.games"
241
- }
242
- },
243
- "handle": "checkout-complete",
244
- "id": "template_664b15174eba71b9ee185be5",
245
- "created_at": "2024-05-20T09:17:11.255Z",
246
- "updated_at": "2024-05-20T10:43:40.766Z",
247
- "_relations": {
248
- "search": [
249
- "handle:checkout-complete",
250
- "checkout-complete",
251
- "id:template_664b15174eba71b9ee185be5",
252
- "template_664b15174eba71b9ee185be5",
253
- "664b15174eba71b9ee185be5",
254
- "checkout",
255
- "complete",
256
- "checkout complete"
257
- ]
258
- }
259
- }
260
- ]
@@ -28,7 +28,7 @@ const add_base_columns = tb => {
28
28
  */
29
29
  const create_entity_to_value_table = (db, table_name) => {
30
30
  return db.schema
31
- .createTable(table_name)
31
+ .createTable(table_name).ifNotExists()
32
32
  .addColumn('id', 'integer',
33
33
  (col) => col.autoIncrement().primaryKey()
34
34
  )
@@ -45,7 +45,7 @@ const create_entity_to_value_table = (db, table_name) => {
45
45
  * @param {keyof Database} table_name
46
46
  */
47
47
  const create_safe_table = (db, table_name) => {
48
- return db.schema.createTable(table_name);
48
+ return db.schema.createTable(table_name).ifNotExists();
49
49
  }
50
50
 
51
51
  /**
@@ -53,7 +53,7 @@ const create_safe_table = (db, table_name) => {
53
53
  * @param {keyof Database} table_name
54
54
  */
55
55
  const drop_safe_table = (db, table_name) => {
56
- return db.schema.dropTable(table_name).execute();
56
+ return db.schema.dropTable(table_name).ifExists().execute();
57
57
  }
58
58
 
59
59
  /**
@@ -64,22 +64,22 @@ const drop_safe_table = (db, table_name) => {
64
64
  */
65
65
  const create_base_indexes = async (db, table_name, include_id=true, include_handle=true) => {
66
66
  if(include_id) {
67
- await db.schema.createIndex(`index_${table_name}_id_updated_at_asc`)
67
+ await db.schema.createIndex(`index_${table_name}_id_updated_at_asc`).ifNotExists()
68
68
  .on(table_name)
69
69
  .columns(['id', 'updated_at asc'])
70
70
  .execute();
71
- await db.schema.createIndex(`index_${table_name}_id_updated_at_desc`)
71
+ await db.schema.createIndex(`index_${table_name}_id_updated_at_desc`).ifNotExists()
72
72
  .on(table_name)
73
73
  .columns(['id', 'updated_at desc'])
74
74
  .execute();
75
75
  }
76
76
 
77
77
  if(include_handle) {
78
- await db.schema.createIndex(`index_${table_name}_handle_updated_at_asc`)
78
+ await db.schema.createIndex(`index_${table_name}_handle_updated_at_asc`).ifNotExists()
79
79
  .on(table_name)
80
80
  .columns(['handle', 'updated_at asc'])
81
81
  .execute();
82
- await db.schema.createIndex(`index_${table_name}_handle_updated_at_desc`)
82
+ await db.schema.createIndex(`index_${table_name}_handle_updated_at_desc`).ifNotExists()
83
83
  .on(table_name)
84
84
  .columns(['handle', 'updated_at desc'])
85
85
  .execute();
@@ -95,23 +95,23 @@ const create_base_indexes = async (db, table_name, include_id=true, include_hand
95
95
  * 'products_to_variants' | 'products_to_related_products' | 'storefronts_to_other'>} table_name
96
96
  */
97
97
  const create_entity_table_indexes = async (db, table_name) => {
98
- await db.schema.createIndex(`index_${table_name}_entity_id`)
98
+ await db.schema.createIndex(`index_${table_name}_entity_id`).ifNotExists()
99
99
  .on(table_name)
100
100
  .column('entity_id')
101
101
  .execute();
102
- await db.schema.createIndex(`index_${table_name}_entity_handle`)
102
+ await db.schema.createIndex(`index_${table_name}_entity_handle`).ifNotExists()
103
103
  .on(table_name)
104
104
  .column('entity_handle')
105
105
  .execute();
106
- await db.schema.createIndex(`index_${table_name}_value`)
106
+ await db.schema.createIndex(`index_${table_name}_value`).ifNotExists()
107
107
  .on(table_name)
108
108
  .column('value')
109
109
  .execute();
110
- await db.schema.createIndex(`index_${table_name}_reporter`)
110
+ await db.schema.createIndex(`index_${table_name}_reporter`).ifNotExists()
111
111
  .on(table_name)
112
112
  .column('reporter')
113
113
  .execute();
114
- await db.schema.createIndex(`index_${table_name}_context`)
114
+ await db.schema.createIndex(`index_${table_name}_context`).ifNotExists()
115
115
  .on(table_name)
116
116
  .column('context')
117
117
  .execute();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storecraft/database-sql-base",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Official SQL Database driver for storecraft",
5
5
  "license": "MIT",
6
6
  "author": "Tomer Shalev (https://github.com/store-craft)",
@@ -8,7 +8,7 @@
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "https://github.com/store-craft/storecraft.git",
11
- "directory": "packages/database-sql-base"
11
+ "directory": "packages/databases/database-sql-base"
12
12
  },
13
13
  "keywords": [
14
14
  "commerce",
@@ -31,8 +31,6 @@
31
31
  "kysely": "^0.27.2"
32
32
  },
33
33
  "devDependencies": {
34
- "@storecraft/platform-node": "^1.0.0",
35
- "@storecraft/test-runner": "^1.0.0",
36
34
  "@types/better-sqlite3": "^7.6.9",
37
35
  "@types/node": "^20.11.0",
38
36
  "@types/pg": "^8.11.2",
@@ -1,4 +1,4 @@
1
- import { SQL } from '../driver.js'
1
+ import { SQL } from '../index.js'
2
2
  import { sanitize_array } from './utils.funcs.js'
3
3
  import { count_regular, delete_me, insert_search_of, insert_tags_of, regular_upsert_me,
4
4
  where_id_or_handle_table,
@@ -7,7 +7,7 @@ import { count_regular, delete_me, insert_search_of, insert_tags_of, regular_ups
7
7
  import { query_to_eb, query_to_sort } from './utils.query.js';
8
8
 
9
9
  /**
10
- * @typedef {import('@storecraft/core/v-database').db_auth_users} db_col
10
+ * @typedef {import('@storecraft/core/database').db_auth_users} db_col
11
11
  */
12
12
 
13
13
  export const table_name = 'auth_users';
@@ -17,6 +17,7 @@ export const table_name = 'auth_users';
17
17
  * @returns {db_col["upsert"]}
18
18
  */
19
19
  const upsert = (driver) => {
20
+
20
21
  return async (item, search_terms=[]) => {
21
22
  const c = driver.client;
22
23
  try {
@@ -35,6 +36,8 @@ const upsert = (driver) => {
35
36
  updated_at: item.updated_at,
36
37
  id: item.id,
37
38
  roles: JSON.stringify(item.roles),
39
+ firstname: item.firstname,
40
+ lastname: item.lastname
38
41
  });
39
42
  }
40
43
  );
@@ -1,4 +1,4 @@
1
- import { SQL } from '../driver.js'
1
+ import { SQL } from '../index.js'
2
2
  import { report_document_media } from './con.images.js'
3
3
  import { delete_entity_values_by_value_or_reporter, delete_me,
4
4
  delete_media_of, delete_search_of, delete_tags_of,
@@ -12,7 +12,7 @@ import { query_to_eb, query_to_sort } from './utils.query.js'
12
12
 
13
13
 
14
14
  /**
15
- * @typedef {import('@storecraft/core/v-database').db_collections} db_col
15
+ * @typedef {import('@storecraft/core/database').db_collections} db_col
16
16
  */
17
17
  export const table_name = 'collections'
18
18
 
@@ -1,4 +1,4 @@
1
- import { SQL } from '../driver.js'
1
+ import { SQL } from '../index.js'
2
2
  import { report_document_media } from './con.images.js'
3
3
  import { count_regular, delete_me, delete_media_of, delete_search_of,
4
4
  delete_tags_of, insert_media_of, insert_search_of,
@@ -8,7 +8,7 @@ import { sanitize_array } from './utils.funcs.js'
8
8
  import { query_to_eb, query_to_sort } from './utils.query.js'
9
9
 
10
10
  /**
11
- * @typedef {import('@storecraft/core/v-database').db_customers} db_col
11
+ * @typedef {import('@storecraft/core/database').db_customers} db_col
12
12
  */
13
13
  export const table_name = 'customers'
14
14
 
@@ -1,5 +1,5 @@
1
- import { enums } from '@storecraft/core/v-api'
2
- import { SQL } from '../driver.js'
1
+ import { enums } from '@storecraft/core/api'
2
+ import { SQL } from '../index.js'
3
3
  import { discount_to_conjunctions } from './con.discounts.utils.js'
4
4
  import { delete_entity_values_by_value_or_reporter,
5
5
  delete_me, delete_media_of, delete_search_of,
@@ -12,7 +12,7 @@ import { query_to_eb, query_to_sort } from './utils.query.js'
12
12
  import { report_document_media } from './con.images.js'
13
13
 
14
14
  /**
15
- * @typedef {import('@storecraft/core/v-database').db_discounts} db_col
15
+ * @typedef {import('@storecraft/core/database').db_discounts} db_col
16
16
  */
17
17
  export const table_name = 'discounts'
18
18
 
@@ -1,11 +1,11 @@
1
- import { enums } from "@storecraft/core/v-api";
1
+ import { enums } from "@storecraft/core/api";
2
2
 
3
- /** @param {import("@storecraft/core/v-api").DiscountType} d */
3
+ /** @param {import("@storecraft/core/api").DiscountType} d */
4
4
  const is_order_discount = d => {
5
5
  return (d.info.details.meta.id===enums.DiscountMetaEnum.order.id);
6
6
  }
7
7
 
8
- /** @param {import("@storecraft/core/v-api").DiscountType} d */
8
+ /** @param {import("@storecraft/core/api").DiscountType} d */
9
9
  const is_automatic_discount = d => {
10
10
  return (d.application.id===enums.DiscountApplicationEnum.Auto.id);
11
11
  }
@@ -43,7 +43,7 @@ const eb_in = (eb, table, op, value) => {
43
43
  * create a mongodb conjunctions clauses from discount, intended
44
44
  * for filtering.
45
45
  * @param {import("kysely").ExpressionBuilder<Database, 'products'>} eb
46
- * @param {import("@storecraft/core/v-api").DiscountType} d
46
+ * @param {import("@storecraft/core/api").DiscountType} d
47
47
  */
48
48
  export const discount_to_conjunctions = (eb, d) => {
49
49
  // discount has to be product discount + automatic + active + has filters
@@ -66,7 +66,7 @@ export const discount_to_conjunctions = (eb, d) => {
66
66
  break;
67
67
  case enums.FilterMetaEnum.p_in_products.op:
68
68
  {
69
- /** @type {import("@storecraft/core/v-api").FilterValue_p_in_products} */
69
+ /** @type {import("@storecraft/core/api").FilterValue_p_in_products} */
70
70
  const cast = Array.isArray(filter?.value) ? filter.value : [];
71
71
 
72
72
  conjunctions.push(
@@ -79,7 +79,7 @@ export const discount_to_conjunctions = (eb, d) => {
79
79
  break;
80
80
  case enums.FilterMetaEnum.p_not_in_products.op:
81
81
  {
82
- /** @type {import("@storecraft/core/v-api").FilterValue_p_not_in_products} */
82
+ /** @type {import("@storecraft/core/api").FilterValue_p_not_in_products} */
83
83
  const cast = Array.isArray(filter?.value) ? filter.value : [];
84
84
 
85
85
  conjunctions.push(
@@ -92,7 +92,7 @@ export const discount_to_conjunctions = (eb, d) => {
92
92
  break;
93
93
  case enums.FilterMetaEnum.p_in_tags.op:
94
94
  {
95
- /** @type {import("@storecraft/core/v-api").FilterValue_p_in_tags} */
95
+ /** @type {import("@storecraft/core/api").FilterValue_p_in_tags} */
96
96
  const cast = Array.isArray(filter?.value) ? filter.value : [];
97
97
 
98
98
  conjunctions.push(
@@ -105,7 +105,7 @@ export const discount_to_conjunctions = (eb, d) => {
105
105
  break;
106
106
  case enums.FilterMetaEnum.p_not_in_tags.op:
107
107
  {
108
- /** @type {import("@storecraft/core/v-api").FilterValue_p_not_in_tags} */
108
+ /** @type {import("@storecraft/core/api").FilterValue_p_not_in_tags} */
109
109
  const cast = Array.isArray(filter?.value) ? filter.value : [];
110
110
 
111
111
  conjunctions.push(
@@ -120,7 +120,7 @@ export const discount_to_conjunctions = (eb, d) => {
120
120
  break;
121
121
  case enums.FilterMetaEnum.p_in_collections.op:
122
122
  {
123
- /** @type {import("@storecraft/core/v-api").FilterValue_p_in_collections} */
123
+ /** @type {import("@storecraft/core/api").FilterValue_p_in_collections} */
124
124
  const cast = Array.isArray(filter?.value) ? filter.value : [];
125
125
 
126
126
  // PROBLEM: we only have ids, but use handles in the filters
@@ -134,7 +134,7 @@ export const discount_to_conjunctions = (eb, d) => {
134
134
  break;
135
135
  case enums.FilterMetaEnum.p_not_in_collections.op:
136
136
  {
137
- /** @type {import("@storecraft/core/v-api").FilterValue_p_not_in_collections} */
137
+ /** @type {import("@storecraft/core/api").FilterValue_p_not_in_collections} */
138
138
  const cast = Array.isArray(filter?.value) ? filter.value : [];
139
139
 
140
140
  conjunctions.push(
@@ -149,7 +149,7 @@ export const discount_to_conjunctions = (eb, d) => {
149
149
  break;
150
150
  case enums.FilterMetaEnum.p_in_price_range.op:
151
151
  {
152
- /** @type {import("@storecraft/core/v-api").FilterValue_p_in_price_range} */
152
+ /** @type {import("@storecraft/core/api").FilterValue_p_in_price_range} */
153
153
  const cast = {
154
154
  from: 0,
155
155
  to: Number.POSITIVE_INFINITY,