@jskit-ai/google-rewarded-core 0.1.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.
Files changed (42) hide show
  1. package/README.md +98 -0
  2. package/docs/protecting-server-actions.md +190 -0
  3. package/package.descriptor.mjs +186 -0
  4. package/package.json +10 -0
  5. package/src/server/GoogleRewardedCoreProvider.js +51 -0
  6. package/src/server/actions.js +102 -0
  7. package/src/server/inputSchemas.js +394 -0
  8. package/src/server/providerConfigs/GoogleRewardedProviderConfigsProvider.js +98 -0
  9. package/src/server/providerConfigs/actions.js +157 -0
  10. package/src/server/providerConfigs/registerRoutes.js +176 -0
  11. package/src/server/providerConfigs/repository.js +107 -0
  12. package/src/server/providerConfigs/service.js +61 -0
  13. package/src/server/registerRoutes.js +169 -0
  14. package/src/server/rules/GoogleRewardedRulesProvider.js +98 -0
  15. package/src/server/rules/actions.js +157 -0
  16. package/src/server/rules/registerRoutes.js +176 -0
  17. package/src/server/rules/repository.js +107 -0
  18. package/src/server/rules/service.js +61 -0
  19. package/src/server/service.js +552 -0
  20. package/src/server/support/requireGoogleRewardedUnlock.js +142 -0
  21. package/src/server/unlockReceipts/GoogleRewardedUnlockReceiptsProvider.js +98 -0
  22. package/src/server/unlockReceipts/actions.js +157 -0
  23. package/src/server/unlockReceipts/registerRoutes.js +176 -0
  24. package/src/server/unlockReceipts/repository.js +107 -0
  25. package/src/server/unlockReceipts/service.js +61 -0
  26. package/src/server/watchSessions/GoogleRewardedWatchSessionsProvider.js +98 -0
  27. package/src/server/watchSessions/actions.js +157 -0
  28. package/src/server/watchSessions/registerRoutes.js +176 -0
  29. package/src/server/watchSessions/repository.js +107 -0
  30. package/src/server/watchSessions/service.js +61 -0
  31. package/src/shared/googleRewardedProviderConfigResource.js +94 -0
  32. package/src/shared/googleRewardedRuleResource.js +136 -0
  33. package/src/shared/googleRewardedUnlockReceiptResource.js +113 -0
  34. package/src/shared/googleRewardedWatchSessionResource.js +139 -0
  35. package/src/shared/index.js +12 -0
  36. package/templates/migrations/google_rewarded_provider_configs_initial.cjs +27 -0
  37. package/templates/migrations/google_rewarded_rules_initial.cjs +31 -0
  38. package/templates/migrations/google_rewarded_unlock_receipts_initial.cjs +35 -0
  39. package/templates/migrations/google_rewarded_watch_sessions_initial.cjs +36 -0
  40. package/test/requireGoogleRewardedUnlock.test.js +274 -0
  41. package/test/routes.test.js +248 -0
  42. package/test/service.test.js +315 -0
@@ -0,0 +1,136 @@
1
+ import { defineCrudResource } from "@jskit-ai/resource-crud-core/shared/crudResource";
2
+
3
+ const resource = defineCrudResource({
4
+ namespace: "google_rewarded_rules",
5
+ tableName: "google_rewarded_rules",
6
+ schema: {
7
+ workspaceId: {
8
+ type: "id",
9
+ required: true,
10
+ search: true,
11
+ hidden: true,
12
+ operations: {}
13
+ },
14
+ gateKey: {
15
+ type: "string",
16
+ maxLength: 120,
17
+ required: true,
18
+ search: true,
19
+ operations: {
20
+ output: { required: true },
21
+ create: { required: true },
22
+ patch: { required: false }
23
+ }
24
+ },
25
+ surface: {
26
+ type: "string",
27
+ maxLength: 64,
28
+ required: true,
29
+ search: true,
30
+ operations: {
31
+ output: { required: true },
32
+ create: { required: true },
33
+ patch: { required: false }
34
+ }
35
+ },
36
+ enabled: {
37
+ type: "boolean",
38
+ search: true,
39
+ operations: {
40
+ output: { required: true },
41
+ create: { required: false },
42
+ patch: { required: false }
43
+ }
44
+ },
45
+ unlockMinutes: {
46
+ type: "integer",
47
+ min: 0,
48
+ search: true,
49
+ operations: {
50
+ output: { required: true },
51
+ create: { required: false },
52
+ patch: { required: false }
53
+ }
54
+ },
55
+ cooldownMinutes: {
56
+ type: "integer",
57
+ min: 0,
58
+ search: true,
59
+ operations: {
60
+ output: { required: true },
61
+ create: { required: false },
62
+ patch: { required: false }
63
+ }
64
+ },
65
+ dailyLimit: {
66
+ type: "integer",
67
+ min: 0,
68
+ nullable: true,
69
+ search: true,
70
+ operations: {
71
+ output: { required: true },
72
+ create: { required: false },
73
+ patch: { required: false }
74
+ }
75
+ },
76
+ title: {
77
+ type: "string",
78
+ maxLength: 160,
79
+ search: true,
80
+ operations: {
81
+ output: { required: true },
82
+ create: { required: false },
83
+ patch: { required: false }
84
+ }
85
+ },
86
+ description: {
87
+ type: "string",
88
+ maxLength: 65535,
89
+ nullable: true,
90
+ search: true,
91
+ operations: {
92
+ output: { required: true },
93
+ create: { required: false },
94
+ patch: { required: false }
95
+ }
96
+ },
97
+ createdAt: {
98
+ type: "dateTime",
99
+ default: "now()",
100
+ storage: { writeSerializer: "datetime-utc" },
101
+ operations: {
102
+ output: { required: true }
103
+ }
104
+ },
105
+ updatedAt: {
106
+ type: "dateTime",
107
+ default: "now()",
108
+ storage: { writeSerializer: "datetime-utc" },
109
+ operations: {
110
+ output: { required: true }
111
+ }
112
+ },
113
+ },
114
+ searchSchema: {
115
+ id: { type: "id", actualField: "id" },
116
+ q: { type: "string", oneOf: ["gateKey","surface","title","description"], filterOperator: "like", splitBy: " ", matchAll: true },
117
+ },
118
+ defaultSort: ["-createdAt"],
119
+ autofilter: "workspace",
120
+ messages: {
121
+ validation: "Fix invalid values and try again.",
122
+ saveSuccess: "Record saved.",
123
+ saveError: "Unable to save record.",
124
+ deleteSuccess: "Record deleted.",
125
+ deleteError: "Unable to delete record."
126
+ },
127
+ contract: {
128
+ lookup: {
129
+ containerKey: "lookups",
130
+ defaultInclude: "*",
131
+ maxDepth: 3
132
+ }
133
+ }
134
+ });
135
+
136
+ export { resource };
@@ -0,0 +1,113 @@
1
+ import { defineCrudResource } from "@jskit-ai/resource-crud-core/shared/crudResource";
2
+
3
+ const resource = defineCrudResource({
4
+ namespace: "google_rewarded_unlock_receipts",
5
+ tableName: "google_rewarded_unlock_receipts",
6
+ schema: {
7
+ workspaceId: {
8
+ type: "id",
9
+ required: true,
10
+ search: true,
11
+ hidden: true,
12
+ operations: {}
13
+ },
14
+ userId: {
15
+ type: "id",
16
+ required: true,
17
+ search: true,
18
+ hidden: true,
19
+ operations: {}
20
+ },
21
+ gateKey: {
22
+ type: "string",
23
+ maxLength: 120,
24
+ required: true,
25
+ search: true,
26
+ operations: {
27
+ output: { required: true },
28
+ create: { required: true },
29
+ patch: { required: false }
30
+ }
31
+ },
32
+ providerConfigId: {
33
+ type: "id",
34
+ nullable: true,
35
+ search: true,
36
+ relation: { kind: "lookup", namespace: "google-rewarded-provider-configs", valueKey: "id" },
37
+ belongsTo: "googleRewardedProviderConfigs",
38
+ as: "providerConfig",
39
+ ui: { formControl: "autocomplete" },
40
+ operations: {
41
+ output: { required: true },
42
+ create: { required: false },
43
+ patch: { required: false }
44
+ }
45
+ },
46
+ watchSessionId: {
47
+ type: "id",
48
+ nullable: true,
49
+ search: true,
50
+ relation: { kind: "lookup", namespace: "google-rewarded-watch-sessions", valueKey: "id" },
51
+ belongsTo: "googleRewardedWatchSessions",
52
+ as: "watchSession",
53
+ ui: { formControl: "autocomplete" },
54
+ operations: {
55
+ output: { required: true },
56
+ create: { required: false },
57
+ patch: { required: false }
58
+ }
59
+ },
60
+ grantedAt: {
61
+ type: "dateTime",
62
+ default: "now()",
63
+ search: true,
64
+ storage: { writeSerializer: "datetime-utc" },
65
+ operations: {
66
+ output: { required: true },
67
+ create: { required: false },
68
+ patch: { required: false }
69
+ }
70
+ },
71
+ unlockedUntil: {
72
+ type: "dateTime",
73
+ required: true,
74
+ search: true,
75
+ storage: { writeSerializer: "datetime-utc" },
76
+ operations: {
77
+ output: { required: true },
78
+ create: { required: true },
79
+ patch: { required: false }
80
+ }
81
+ },
82
+ createdAt: {
83
+ type: "dateTime",
84
+ default: "now()",
85
+ storage: { writeSerializer: "datetime-utc" },
86
+ operations: {
87
+ output: { required: true }
88
+ }
89
+ },
90
+ },
91
+ searchSchema: {
92
+ id: { type: "id", actualField: "id" },
93
+ q: { type: "string", oneOf: ["gateKey"], filterOperator: "like", splitBy: " ", matchAll: true },
94
+ },
95
+ defaultSort: ["-createdAt"],
96
+ autofilter: "workspace_user",
97
+ messages: {
98
+ validation: "Fix invalid values and try again.",
99
+ saveSuccess: "Record saved.",
100
+ saveError: "Unable to save record.",
101
+ deleteSuccess: "Record deleted.",
102
+ deleteError: "Unable to delete record."
103
+ },
104
+ contract: {
105
+ lookup: {
106
+ containerKey: "lookups",
107
+ defaultInclude: "*",
108
+ maxDepth: 3
109
+ }
110
+ }
111
+ });
112
+
113
+ export { resource };
@@ -0,0 +1,139 @@
1
+ import { defineCrudResource } from "@jskit-ai/resource-crud-core/shared/crudResource";
2
+
3
+ const resource = defineCrudResource({
4
+ namespace: "google_rewarded_watch_sessions",
5
+ tableName: "google_rewarded_watch_sessions",
6
+ schema: {
7
+ workspaceId: {
8
+ type: "id",
9
+ required: true,
10
+ search: true,
11
+ hidden: true,
12
+ operations: {}
13
+ },
14
+ userId: {
15
+ type: "id",
16
+ required: true,
17
+ search: true,
18
+ hidden: true,
19
+ operations: {}
20
+ },
21
+ gateKey: {
22
+ type: "string",
23
+ maxLength: 120,
24
+ required: true,
25
+ search: true,
26
+ operations: {
27
+ output: { required: true },
28
+ create: { required: true },
29
+ patch: { required: false }
30
+ }
31
+ },
32
+ providerConfigId: {
33
+ type: "id",
34
+ nullable: true,
35
+ search: true,
36
+ relation: { kind: "lookup", namespace: "google-rewarded-provider-configs", valueKey: "id" },
37
+ belongsTo: "googleRewardedProviderConfigs",
38
+ as: "providerConfig",
39
+ ui: { formControl: "autocomplete" },
40
+ operations: {
41
+ output: { required: true },
42
+ create: { required: false },
43
+ patch: { required: false }
44
+ }
45
+ },
46
+ status: {
47
+ type: "string",
48
+ maxLength: 32,
49
+ search: true,
50
+ operations: {
51
+ output: { required: true },
52
+ create: { required: false },
53
+ patch: { required: false }
54
+ }
55
+ },
56
+ startedAt: {
57
+ type: "dateTime",
58
+ default: "now()",
59
+ search: true,
60
+ storage: { writeSerializer: "datetime-utc" },
61
+ operations: {
62
+ output: { required: true },
63
+ create: { required: false },
64
+ patch: { required: false }
65
+ }
66
+ },
67
+ rewardedAt: {
68
+ type: "dateTime",
69
+ nullable: true,
70
+ search: true,
71
+ storage: { writeSerializer: "datetime-utc" },
72
+ operations: {
73
+ output: { required: true },
74
+ create: { required: false },
75
+ patch: { required: false }
76
+ }
77
+ },
78
+ completedAt: {
79
+ type: "dateTime",
80
+ nullable: true,
81
+ search: true,
82
+ storage: { writeSerializer: "datetime-utc" },
83
+ operations: {
84
+ output: { required: true },
85
+ create: { required: false },
86
+ patch: { required: false }
87
+ }
88
+ },
89
+ closedAt: {
90
+ type: "dateTime",
91
+ nullable: true,
92
+ search: true,
93
+ storage: { writeSerializer: "datetime-utc" },
94
+ operations: {
95
+ output: { required: true },
96
+ create: { required: false },
97
+ patch: { required: false }
98
+ }
99
+ },
100
+ createdAt: {
101
+ type: "dateTime",
102
+ default: "now()",
103
+ storage: { writeSerializer: "datetime-utc" },
104
+ operations: {
105
+ output: { required: true }
106
+ }
107
+ },
108
+ updatedAt: {
109
+ type: "dateTime",
110
+ default: "now()",
111
+ storage: { writeSerializer: "datetime-utc" },
112
+ operations: {
113
+ output: { required: true }
114
+ }
115
+ },
116
+ },
117
+ searchSchema: {
118
+ id: { type: "id", actualField: "id" },
119
+ q: { type: "string", oneOf: ["gateKey","status"], filterOperator: "like", splitBy: " ", matchAll: true },
120
+ },
121
+ defaultSort: ["-createdAt"],
122
+ autofilter: "workspace_user",
123
+ messages: {
124
+ validation: "Fix invalid values and try again.",
125
+ saveSuccess: "Record saved.",
126
+ saveError: "Unable to save record.",
127
+ deleteSuccess: "Record deleted.",
128
+ deleteError: "Unable to delete record."
129
+ },
130
+ contract: {
131
+ lookup: {
132
+ containerKey: "lookups",
133
+ defaultInclude: "*",
134
+ maxDepth: 3
135
+ }
136
+ }
137
+ });
138
+
139
+ export { resource };
@@ -0,0 +1,12 @@
1
+ export {
2
+ resource as googleRewardedRuleResource
3
+ } from "./googleRewardedRuleResource.js";
4
+ export {
5
+ resource as googleRewardedProviderConfigResource
6
+ } from "./googleRewardedProviderConfigResource.js";
7
+ export {
8
+ resource as googleRewardedWatchSessionResource
9
+ } from "./googleRewardedWatchSessionResource.js";
10
+ export {
11
+ resource as googleRewardedUnlockReceiptResource
12
+ } from "./googleRewardedUnlockReceiptResource.js";
@@ -0,0 +1,27 @@
1
+ const TABLE_NAME = "google_rewarded_provider_configs";
2
+
3
+ exports.up = async function up(knex) {
4
+ const hasCrudTable = await knex.schema.hasTable(TABLE_NAME);
5
+ if (hasCrudTable) {
6
+ return;
7
+ }
8
+
9
+ await knex.schema.createTable(TABLE_NAME, (table) => {
10
+ table.bigIncrements("id").unsigned().primary();
11
+ table.bigInteger("workspace_id").unsigned().notNullable();
12
+ table.string("surface", 64).notNullable();
13
+ table.boolean("enabled").notNullable().defaultTo(true);
14
+ table.string("ad_unit_path", 255).notNullable();
15
+ table.string("script_mode", 64).notNullable().defaultTo("gpt_rewarded");
16
+ table.timestamp("created_at").notNullable().defaultTo(knex.fn.now());
17
+ table.timestamp("updated_at").notNullable().defaultTo(knex.raw("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"));
18
+ table.index(["workspace_id"], "idx_google_rewarded_provider_configs_workspace");
19
+ table.unique(["workspace_id","surface"], "uq_google_rewarded_provider_configs_workspace_surface");
20
+ table.foreign(["workspace_id"], "fk_google_rewarded_provider_configs_workspace").references(["id"]).inTable("workspaces").onUpdate("RESTRICT").onDelete("CASCADE");
21
+ });
22
+
23
+ };
24
+
25
+ exports.down = async function down(knex) {
26
+ await knex.schema.dropTableIfExists(TABLE_NAME);
27
+ };
@@ -0,0 +1,31 @@
1
+ const TABLE_NAME = "google_rewarded_rules";
2
+
3
+ exports.up = async function up(knex) {
4
+ const hasCrudTable = await knex.schema.hasTable(TABLE_NAME);
5
+ if (hasCrudTable) {
6
+ return;
7
+ }
8
+
9
+ await knex.schema.createTable(TABLE_NAME, (table) => {
10
+ table.bigIncrements("id").unsigned().primary();
11
+ table.bigInteger("workspace_id").unsigned().notNullable();
12
+ table.string("gate_key", 120).notNullable();
13
+ table.string("surface", 64).notNullable();
14
+ table.boolean("enabled").notNullable().defaultTo(true);
15
+ table.integer("unlock_minutes").unsigned().notNullable().defaultTo(30);
16
+ table.integer("cooldown_minutes").unsigned().notNullable().defaultTo(0);
17
+ table.integer("daily_limit").unsigned().nullable();
18
+ table.string("title", 160).notNullable().defaultTo("");
19
+ table.text("description").nullable();
20
+ table.timestamp("created_at").notNullable().defaultTo(knex.fn.now());
21
+ table.timestamp("updated_at").notNullable().defaultTo(knex.raw("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"));
22
+ table.index(["workspace_id"], "idx_google_rewarded_rules_workspace");
23
+ table.unique(["workspace_id","gate_key"], "uq_google_rewarded_rules_workspace_gate");
24
+ table.foreign(["workspace_id"], "fk_google_rewarded_rules_workspace").references(["id"]).inTable("workspaces").onUpdate("RESTRICT").onDelete("CASCADE");
25
+ });
26
+
27
+ };
28
+
29
+ exports.down = async function down(knex) {
30
+ await knex.schema.dropTableIfExists(TABLE_NAME);
31
+ };
@@ -0,0 +1,35 @@
1
+ const TABLE_NAME = "google_rewarded_unlock_receipts";
2
+
3
+ exports.up = async function up(knex) {
4
+ const hasCrudTable = await knex.schema.hasTable(TABLE_NAME);
5
+ if (hasCrudTable) {
6
+ return;
7
+ }
8
+
9
+ await knex.schema.createTable(TABLE_NAME, (table) => {
10
+ table.bigIncrements("id").unsigned().primary();
11
+ table.bigInteger("workspace_id").unsigned().notNullable();
12
+ table.bigInteger("user_id").unsigned().notNullable();
13
+ table.string("gate_key", 120).notNullable();
14
+ table.bigInteger("provider_config_id").unsigned().nullable();
15
+ table.bigInteger("watch_session_id").unsigned().nullable();
16
+ table.timestamp("granted_at").notNullable().defaultTo(knex.fn.now());
17
+ table.timestamp("unlocked_until").notNullable();
18
+ table.timestamp("created_at").notNullable().defaultTo(knex.fn.now());
19
+ table.index(["user_id"], "fk_google_rewarded_unlock_receipts_user");
20
+ table.index(["gate_key"], "idx_google_rewarded_unlock_receipts_gate");
21
+ table.index(["provider_config_id"], "idx_google_rewarded_unlock_receipts_provider_config");
22
+ table.index(["unlocked_until"], "idx_google_rewarded_unlock_receipts_unlocked_until");
23
+ table.index(["watch_session_id"], "idx_google_rewarded_unlock_receipts_watch_session");
24
+ table.index(["workspace_id","user_id"], "idx_google_rewarded_unlock_receipts_workspace_user");
25
+ table.foreign(["provider_config_id"], "fk_google_rewarded_unlock_receipts_provider_config").references(["id"]).inTable("google_rewarded_provider_configs").onUpdate("RESTRICT").onDelete("SET NULL");
26
+ table.foreign(["user_id"], "fk_google_rewarded_unlock_receipts_user").references(["id"]).inTable("users").onUpdate("RESTRICT").onDelete("CASCADE");
27
+ table.foreign(["watch_session_id"], "fk_google_rewarded_unlock_receipts_watch_session").references(["id"]).inTable("google_rewarded_watch_sessions").onUpdate("RESTRICT").onDelete("SET NULL");
28
+ table.foreign(["workspace_id"], "fk_google_rewarded_unlock_receipts_workspace").references(["id"]).inTable("workspaces").onUpdate("RESTRICT").onDelete("CASCADE");
29
+ });
30
+
31
+ };
32
+
33
+ exports.down = async function down(knex) {
34
+ await knex.schema.dropTableIfExists(TABLE_NAME);
35
+ };
@@ -0,0 +1,36 @@
1
+ const TABLE_NAME = "google_rewarded_watch_sessions";
2
+
3
+ exports.up = async function up(knex) {
4
+ const hasCrudTable = await knex.schema.hasTable(TABLE_NAME);
5
+ if (hasCrudTable) {
6
+ return;
7
+ }
8
+
9
+ await knex.schema.createTable(TABLE_NAME, (table) => {
10
+ table.bigIncrements("id").unsigned().primary();
11
+ table.bigInteger("workspace_id").unsigned().notNullable();
12
+ table.bigInteger("user_id").unsigned().notNullable();
13
+ table.string("gate_key", 120).notNullable();
14
+ table.bigInteger("provider_config_id").unsigned().nullable();
15
+ table.string("status", 32).notNullable().defaultTo("started");
16
+ table.timestamp("started_at").notNullable().defaultTo(knex.fn.now());
17
+ table.timestamp("rewarded_at").nullable();
18
+ table.timestamp("completed_at").nullable();
19
+ table.timestamp("closed_at").nullable();
20
+ table.timestamp("created_at").notNullable().defaultTo(knex.fn.now());
21
+ table.timestamp("updated_at").notNullable().defaultTo(knex.raw("CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"));
22
+ table.index(["user_id"], "fk_google_rewarded_watch_sessions_user");
23
+ table.index(["gate_key"], "idx_google_rewarded_watch_sessions_gate");
24
+ table.index(["provider_config_id"], "idx_google_rewarded_watch_sessions_provider_config");
25
+ table.index(["status"], "idx_google_rewarded_watch_sessions_status");
26
+ table.index(["workspace_id","user_id"], "idx_google_rewarded_watch_sessions_workspace_user");
27
+ table.foreign(["provider_config_id"], "fk_google_rewarded_watch_sessions_provider_config").references(["id"]).inTable("google_rewarded_provider_configs").onUpdate("RESTRICT").onDelete("SET NULL");
28
+ table.foreign(["user_id"], "fk_google_rewarded_watch_sessions_user").references(["id"]).inTable("users").onUpdate("RESTRICT").onDelete("CASCADE");
29
+ table.foreign(["workspace_id"], "fk_google_rewarded_watch_sessions_workspace").references(["id"]).inTable("workspaces").onUpdate("RESTRICT").onDelete("CASCADE");
30
+ });
31
+
32
+ };
33
+
34
+ exports.down = async function down(knex) {
35
+ await knex.schema.dropTableIfExists(TABLE_NAME);
36
+ };